refactor(Core/Scripts): convert Blackrock Mountain scripts to register macros (#25178)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew
2026-03-22 13:38:10 -03:00
committed by GitHub
parent f63a93276e
commit 2c4b7c3cd4
55 changed files with 6659 additions and 7938 deletions

View File

@@ -18,6 +18,7 @@
#include "blackrock_depths.h" #include "blackrock_depths.h"
#include "AreaTriggerScript.h" #include "AreaTriggerScript.h"
#include "CreatureScript.h" #include "CreatureScript.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h" #include "GameObjectScript.h"
#include "GameTime.h" #include "GameTime.h"
#include "Player.h" #include "Player.h"
@@ -34,93 +35,76 @@ enum IronhandData
constexpr Milliseconds IRONHAND_FLAMES_TIMER = 16s; constexpr Milliseconds IRONHAND_FLAMES_TIMER = 16s;
constexpr Milliseconds IRONHAND_FLAMES_TIMER_RAND = 3s; constexpr Milliseconds IRONHAND_FLAMES_TIMER_RAND = 3s;
class go_shadowforge_brazier : public GameObjectScript struct go_shadowforge_brazier : public GameObjectAI
{ {
public: go_shadowforge_brazier(GameObject* go) : GameObjectAI(go) {}
go_shadowforge_brazier() : GameObjectScript("go_shadowforge_brazier") {}
bool OnGossipHello(Player* /*player*/, GameObject* go) override bool GossipHello(Player* /*player*/, bool /*reportUse*/) override
{ {
if (InstanceScript* instance = go->GetInstanceScript()) if (InstanceScript* instance = me->GetInstanceScript())
{ {
GameObject* northBrazier = ObjectAccessor::GetGameObject(*go, instance->GetGuidData(DATA_SF_BRAZIER_N)); GameObject* northBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_N));
GameObject* southBrazier = ObjectAccessor::GetGameObject(*go, instance->GetGuidData(DATA_SF_BRAZIER_S)); GameObject* southBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_S));
if (!northBrazier || !southBrazier) if (!northBrazier || !southBrazier)
{
return false; return false;
}
// should only happen on first brazier // should only happen on first brazier
if (instance->GetData(TYPE_LYCEUM) == NOT_STARTED) if (instance->GetData(TYPE_LYCEUM) == NOT_STARTED)
{
instance->SetData(TYPE_LYCEUM, IN_PROGRESS); instance->SetData(TYPE_LYCEUM, IN_PROGRESS);
}
// Check if the opposite brazier is lit - if it is, open the gates. // 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)) if ((me->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (me->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE))
{ {
instance->SetData(TYPE_LYCEUM, DONE); instance->SetData(TYPE_LYCEUM, DONE);
} }
return false; return false;
} }
return false; return false;
}; }
}; };
class ironhand_guardian : public CreatureScript struct brd_ironhand_guardian : public CreatureAI
{ {
public: brd_ironhand_guardian(Creature* creature) : CreatureAI(creature) {}
ironhand_guardian() : CreatureScript("brd_ironhand_guardian") {}
CreatureAI* GetAI(Creature* creature) const override void SetData(uint32 id, uint32 value) override
{ {
return GetBlackrockDepthsAI<ironhand_guardianAI>(creature); if (id == 0)
if (value == 0 || value == 1)
{
_flamesEnabled = (bool) (value);
events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS);
}
} }
struct ironhand_guardianAI : public CreatureAI void UpdateAI(uint32 diff) override
{ {
ironhand_guardianAI(Creature* creature) : CreatureAI(creature) {} events.Update(diff);
bool flames_enabled = false;
void SetData(uint32 id, uint32 value) override if (_flamesEnabled)
{ {
if (id == 0) if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
if (value == 0 || value == 1) switch (eventId)
{ {
flames_enabled = (bool) (value); case SPELL_GOUT_OF_FLAMES:
events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS); DoCast(SPELL_GOUT_OF_FLAMES);
events.RescheduleEvent(SPELL_GOUT_OF_FLAMES, IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND);
break;
default:
break;
} }
} }
} }
}
void UpdateAI(uint32 diff) override private:
{ bool _flamesEnabled = false;
events.Update(diff); EventMap events;
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, IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND);
break;
default:
break;
}
}
}
}
EventMap events;
};
}; };
struct WaveCreature struct WaveCreature
@@ -159,13 +143,10 @@ public:
{ {
time_t now = GameTime::GetGameTime().count(); time_t now = GameTime::GetGameTime().count();
if (instance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || instance->GetData(TYPE_RING_OF_LAW) == DONE) if (instance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || instance->GetData(TYPE_RING_OF_LAW) == DONE)
{
return false; return false;
}
if (now - instance->GetData(DATA_TIME_RING_FAIL) < 2 * 60) // in case of wipe, so people can rez. if (now - instance->GetData(DATA_TIME_RING_FAIL) < 2 * 60) // in case of wipe, so people can rez.
{
return false; return false;
}
instance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS); instance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS);
return true; return true;
@@ -185,249 +166,232 @@ enum GrimstoneTexts
SAY_TEXT6 = 5 SAY_TEXT6 = 5
}; };
class npc_grimstone : public CreatureScript struct npc_grimstone : public npc_escortAI
{ {
public: npc_grimstone(Creature* creature) : npc_escortAI(creature), summons(me)
npc_grimstone() : CreatureScript("npc_grimstone") { }
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetBlackrockDepthsAI<npc_grimstoneAI>(creature); instance = creature->GetInstanceScript();
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();
} }
struct npc_grimstoneAI : public npc_escortAI InstanceScript* instance;
SummonList summons;
uint8 eventPhase;
uint32 eventTimer;
uint32 resetTimer;
uint8 MobSpawnId;
uint8 BossSpawnId;
bool theldrenEvent;
void Reset() override
{ {
npc_grimstoneAI(Creature* creature) : npc_escortAI(creature), summons(me) me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (Unit* target = SelectTargetFromPlayerList(100.0f))
summon->AI()->AttackStart(target);
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
// All Summons killed, next phase
if (summons.empty())
{ {
instance = creature->GetInstanceScript();
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; resetTimer = 0;
theldrenEvent = false; eventTimer = 5000;
summons.DespawnAll();
} }
}
InstanceScript* instance; void WaypointReached(uint32 waypointId) override
SummonList summons; {
switch (waypointId)
uint8 eventPhase;
uint32 eventTimer;
uint32 resetTimer;
uint8 MobSpawnId;
uint8 BossSpawnId;
bool theldrenEvent;
void Reset() override
{ {
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); case 0:
} Talk(SAY_TEXT1);
SetEscortPaused(true);
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (Unit* target = SelectTargetFromPlayerList(100.0f))
summon->AI()->AttackStart(target);
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
// All Summons killed, next phase
if (summons.empty())
{
resetTimer = 0;
eventTimer = 5000; eventTimer = 5000;
} break;
case 1:
Talk(SAY_TEXT2);
SetEscortPaused(true);
eventTimer = 5000;
break;
case 2:
SetEscortPaused(true);
break;
case 3:
Talk(SAY_TEXT3);
break;
case 4:
Talk(SAY_TEXT4);
SetEscortPaused(true);
eventTimer = 5000;
break;
case 5:
if (instance)
{
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me);
instance->SetData(TYPE_RING_OF_LAW, DONE);
}
break;
} }
}
void WaypointReached(uint32 waypointId) override void HandleGameObject(uint32 id, bool open)
{
instance->HandleGameObject(instance->GetGuidData(id), open);
}
void SummonBoss()
{
if (me->FindNearestGameObject(GO_BANNER_OF_PROVOCATION, 100.0f))
{ {
switch (waypointId) theldrenEvent = true;
me->SummonCreature(NPC_THELDREN, 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
uint8 rand = urand(0, 4);
for (uint8 i = rand; i < rand + 4; ++i)
me->SummonCreature(theldrenTeam[i], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
}
else
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 (auto const& sum : summons)
{ {
case 0: if (Creature* creature = ObjectAccessor::GetCreature(*me, sum))
Talk(SAY_TEXT1); {
SetEscortPaused(true); if (creature->IsAlive() && creature->GetVictim())
eventTimer = 5000;
break;
case 1:
Talk(SAY_TEXT2);
SetEscortPaused(true);
eventTimer = 5000;
break;
case 2:
SetEscortPaused(true);
break;
case 3:
Talk(SAY_TEXT3);
break;
case 4:
Talk(SAY_TEXT4);
SetEscortPaused(true);
eventTimer = 5000;
break;
case 5:
if (instance)
{ {
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me); resetTimer = 30000;
instance->SetData(TYPE_RING_OF_LAW, DONE); break; // only need to find one.
} }
break; }
} }
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
{
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);
} }
void HandleGameObject(uint32 id, bool open) if (eventTimer)
{ {
instance->HandleGameObject(instance->GetGuidData(id), open); if (eventTimer <= diff)
}
void SummonBoss()
{
if (me->FindNearestGameObject(GO_BANNER_OF_PROVOCATION, 100.0f))
{ {
theldrenEvent = true; switch (eventPhase)
me->SummonCreature(NPC_THELDREN, 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); {
uint8 rand = urand(0, 4); case 0:
for (uint8 i = rand; i < rand + 4; ++i) Talk(SAY_TEXT5);
me->SummonCreature(theldrenTeam[i], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); HandleGameObject(DATA_ARENA4, false);
me->SetWalk(true);
Start(false);
eventTimer = 0;
break;
case 1:
SetEscortPaused(false);
eventTimer = 0;
break;
case 2:
eventTimer = 2000;
break;
case 3:
HandleGameObject(DATA_ARENA1, true);
eventTimer = 3000;
break;
case 4:
SetEscortPaused(false);
me->SetVisible(false);
SpawnWave(MobSpawnId); // wave 1
eventTimer = 15000;
break;
case 5:
SpawnWave(MobSpawnId); // wave 2
eventTimer = 0; // will be set from SummonedCreatureDies
break;
case 6:
me->SetVisible(true);
HandleGameObject(DATA_ARENA1, false);
Talk(SAY_TEXT6);
SetEscortPaused(false);
eventTimer = 0;
break;
case 7:
HandleGameObject(DATA_ARENA2, true);
eventTimer = 5000;
break;
case 8:
me->SetVisible(false);
SummonBoss();
eventTimer = 0;
break;
case 9:
if (theldrenEvent)
{
// All objects are removed from world once tempsummons despawn, so have a player spawn it instead.
Player* player = me->SelectNearestPlayer(100.0f);
if (GameObject* go = player->SummonGameObject(GO_ARENA_SPOILS, 596.48f, -187.91f, -54.14f, 4.9f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
go->SetOwnerGUID(ObjectGuid::Empty);
Map::PlayerList const& pl = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
itr->GetSource()->KilledMonsterCredit(16166);
}
HandleGameObject(DATA_ARENA2, false);
HandleGameObject(DATA_ARENA3, true);
HandleGameObject(DATA_ARENA4, true);
SetEscortPaused(false);
break;
}
++eventPhase;
} }
else else
me->SummonCreature(RingBoss[BossSpawnId], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); eventTimer -= diff;
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 (auto const& 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
{
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)
{
switch (eventPhase)
{
case 0:
Talk(SAY_TEXT5);
HandleGameObject(DATA_ARENA4, false);
me->SetWalk(true);
Start(false);
eventTimer = 0;
break;
case 1:
SetEscortPaused(false);
eventTimer = 0;
break;
case 2:
eventTimer = 2000;
break;
case 3:
HandleGameObject(DATA_ARENA1, true);
eventTimer = 3000;
break;
case 4:
SetEscortPaused(false);
me->SetVisible(false);
SpawnWave(MobSpawnId); // wave 1
eventTimer = 15000;
break;
case 5:
SpawnWave(MobSpawnId); // wave 2
eventTimer = 0; // will be set from SummonedCreatureDies
break;
case 6:
me->SetVisible(true);
HandleGameObject(DATA_ARENA1, false);
Talk(SAY_TEXT6);
SetEscortPaused(false);
eventTimer = 0;
break;
case 7:
HandleGameObject(DATA_ARENA2, true);
eventTimer = 5000;
break;
case 8:
me->SetVisible(false);
SummonBoss();
eventTimer = 0;
break;
case 9:
if (theldrenEvent)
{
// All objects are removed from world once tempsummons despawn, so have a player spawn it instead.
Player* player = me->SelectNearestPlayer(100.0f);
if (GameObject* go = player->SummonGameObject(GO_ARENA_SPOILS, 596.48f, -187.91f, -54.14f, 4.9f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
{
go->SetOwnerGUID(ObjectGuid::Empty);
}
Map::PlayerList const& pl = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
itr->GetSource()->KilledMonsterCredit(16166);
}
HandleGameObject(DATA_ARENA2, false);
HandleGameObject(DATA_ARENA3, true);
HandleGameObject(DATA_ARENA4, true);
SetEscortPaused(false);
break;
}
++eventPhase;
}
else
eventTimer -= diff;
}
}
};
}; };
// npc_phalanx // npc_phalanx
@@ -438,67 +402,53 @@ enum PhalanxSpells
SPELL_MIGHTYBLOW = 14099 SPELL_MIGHTYBLOW = 14099
}; };
class npc_phalanx : public CreatureScript struct npc_phalanx : public ScriptedAI
{ {
public: npc_phalanx(Creature* creature) : ScriptedAI(creature) { }
npc_phalanx() : CreatureScript("npc_phalanx") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockDepthsAI<npc_phalanxAI>(creature); _thunderClapTimer = 12000;
_fireballVolleyTimer = 0;
_mightyBlowTimer = 15000;
} }
struct npc_phalanxAI : public ScriptedAI void UpdateAI(uint32 diff) override
{ {
npc_phalanxAI(Creature* creature) : ScriptedAI(creature) { } if (!UpdateVictim())
return;
uint32 ThunderClap_Timer; if (_thunderClapTimer <= diff)
uint32 FireballVolley_Timer;
uint32 MightyBlow_Timer;
void Reset() override
{ {
ThunderClap_Timer = 12000; DoCastVictim(SPELL_THUNDERCLAP);
FireballVolley_Timer = 0; _thunderClapTimer = 10000;
MightyBlow_Timer = 15000; }
else _thunderClapTimer -= diff;
if (HealthBelowPct(51))
{
if (_fireballVolleyTimer <= diff)
{
DoCastVictim(SPELL_FIREBALLVOLLEY);
_fireballVolleyTimer = 15000;
}
else _fireballVolleyTimer -= diff;
} }
void UpdateAI(uint32 diff) override if (_mightyBlowTimer <= diff)
{ {
//Return since we have no target DoCastVictim(SPELL_MIGHTYBLOW);
if (!UpdateVictim()) _mightyBlowTimer = 10000;
return;
//ThunderClap_Timer
if (ThunderClap_Timer <= diff)
{
DoCastVictim(SPELL_THUNDERCLAP);
ThunderClap_Timer = 10000;
}
else ThunderClap_Timer -= diff;
//FireballVolley_Timer
if (HealthBelowPct(51))
{
if (FireballVolley_Timer <= diff)
{
DoCastVictim(SPELL_FIREBALLVOLLEY);
FireballVolley_Timer = 15000;
}
else FireballVolley_Timer -= diff;
}
//MightyBlow_Timer
if (MightyBlow_Timer <= diff)
{
DoCastVictim(SPELL_MIGHTYBLOW);
MightyBlow_Timer = 10000;
}
else MightyBlow_Timer -= diff;
DoMeleeAttackIfReady();
} }
}; else _mightyBlowTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 _thunderClapTimer;
uint32 _fireballVolleyTimer;
uint32 _mightyBlowTimer;
}; };
// npc_lokhtos_darkbargainer // npc_lokhtos_darkbargainer
@@ -518,12 +468,11 @@ enum LokhtosSpells
SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059 SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059
}; };
class npc_lokhtos_darkbargainer : public CreatureScript struct npc_lokhtos_darkbargainer : public ScriptedAI
{ {
public: npc_lokhtos_darkbargainer(Creature* creature) : ScriptedAI(creature) { }
npc_lokhtos_darkbargainer() : CreatureScript("npc_lokhtos_darkbargainer") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1) if (action == GOSSIP_ACTION_INFO_DEF + 1)
@@ -532,32 +481,26 @@ public:
player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false); player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false);
} }
if (action == GOSSIP_ACTION_TRADE) if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(creature->GetGUID()); player->GetSession()->SendListInventory(me->GetGUID());
return true;
} }
bool OnGossipHello(Player* player, Creature* creature) override void sGossipHello(Player* player) override
{ {
if (creature->IsQuestGiver()) if (me->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID()); player->PrepareQuestMenu(me->GetGUID());
if (creature->IsVendor() && player->GetReputationRank(59) >= REP_FRIENDLY) if (me->IsVendor() && player->GetReputationRank(59) >= REP_FRIENDLY)
AddGossipItemFor(player, 4781, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); AddGossipItemFor(player, 4781, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 && if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 &&
!player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) && !player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) &&
player->HasItemCount(ITEM_SULFURON_INGOT)) player->HasItemCount(ITEM_SULFURON_INGOT))
{
AddGossipItemFor(player, 4781, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); AddGossipItemFor(player, 4781, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetReputationRank(59) < REP_FRIENDLY) if (player->GetReputationRank(59) < REP_FRIENDLY)
SendGossipMenuFor(player, 3673, creature->GetGUID()); SendGossipMenuFor(player, 3673, me->GetGUID());
else else
SendGossipMenuFor(player, 3677, creature->GetGUID()); SendGossipMenuFor(player, 3677, me->GetGUID());
return true;
} }
}; };
@@ -577,19 +520,29 @@ enum RocknotQuests
QUEST_ALE = 4295 QUEST_ALE = 4295
}; };
class npc_rocknot : public CreatureScript struct npc_rocknot : public npc_escortAI
{ {
public: npc_rocknot(Creature* creature) : npc_escortAI(creature)
npc_rocknot() : CreatureScript("npc_rocknot") { } {
instance = creature->GetInstanceScript();
bool OnQuestReward(Player* /*player*/, Creature* creature, Quest const* quest, uint32 /*item*/) override }
void Reset() override
{
if (HasEscortState(STATE_ESCORT_ESCORTING))
return;
_breakKegTimer = 0;
_breakDoorTimer = 0;
}
void sQuestReward(Player* /*player*/, Quest const* quest, uint32 /*opt*/) override
{ {
InstanceScript* instance = creature->GetInstanceScript();
if (!instance) if (!instance)
return true; return;
if (instance->GetData(TYPE_BAR) == DONE || instance->GetData(TYPE_BAR) == SPECIAL) if (instance->GetData(TYPE_BAR) == DONE || instance->GetData(TYPE_BAR) == SPECIAL)
return true; return;
if (quest->GetQuestId() == QUEST_ALE) if (quest->GetQuestId() == QUEST_ALE)
{ {
@@ -601,120 +554,92 @@ public:
//keep track of amount in instance script, returns SPECIAL if amount ok and event in progress //keep track of amount in instance script, returns SPECIAL if amount ok and event in progress
if (instance->GetData(TYPE_BAR) == SPECIAL) if (instance->GetData(TYPE_BAR) == SPECIAL)
{ {
creature->AI()->Talk(SAY_GOT_BEER); Talk(SAY_GOT_BEER);
creature->CastSpell(creature, SPELL_DRUNKEN_RAGE, false); me->CastSpell(me, SPELL_DRUNKEN_RAGE, false);
me->SetWalk(true);
if (npc_escortAI* escortAI = CAST_AI(npc_rocknot::npc_rocknotAI, creature->AI())) Start(false);
{
creature->SetWalk(true);
escortAI->Start(false);
}
} }
} }
return true;
} }
CreatureAI* GetAI(Creature* creature) const override void DoGo(uint32 id, uint32 state)
{ {
return GetBlackrockDepthsAI<npc_rocknotAI>(creature); if (GameObject* go = instance->instance->GetGameObject(instance->GetGuidData(id)))
go->SetGoState((GOState)state);
} }
struct npc_rocknotAI : public npc_escortAI void WaypointReached(uint32 waypointId) override
{ {
npc_rocknotAI(Creature* creature) : npc_escortAI(creature) switch (waypointId)
{ {
instance = creature->GetInstanceScript(); case 1:
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK);
break;
case 2:
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
break;
case 3:
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
break;
case 4:
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK);
break;
case 5:
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK);
_breakKegTimer = 2000;
break;
} }
}
InstanceScript* instance; void UpdateAI(uint32 diff) override
{
uint32 BreakKeg_Timer; if (_breakKegTimer)
uint32 BreakDoor_Timer;
void Reset() override
{ {
if (HasEscortState(STATE_ESCORT_ESCORTING)) if (_breakKegTimer <= diff)
return;
BreakKeg_Timer = 0;
BreakDoor_Timer = 0;
}
void DoGo(uint32 id, uint32 state)
{
if (GameObject* go = instance->instance->GetGameObject(instance->GetGuidData(id)))
go->SetGoState((GOState)state);
}
void WaypointReached(uint32 waypointId) override
{
switch (waypointId)
{ {
case 1: DoGo(DATA_GO_BAR_KEG, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); _breakKegTimer = 0;
break; _breakDoorTimer = 1000;
case 2:
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
break;
case 3:
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
break;
case 4:
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK);
break;
case 5:
me->HandleEmoteCommand(EMOTE_ONESHOT_KICK);
BreakKeg_Timer = 2000;
break;
} }
else _breakKegTimer -= diff;
} }
void UpdateAI(uint32 diff) override if (_breakDoorTimer)
{ {
if (BreakKeg_Timer) if (_breakDoorTimer <= diff)
{ {
if (BreakKeg_Timer <= diff) DoGo(DATA_GO_BAR_DOOR, 2);
{ DoGo(DATA_GO_BAR_KEG_TRAP, 0); //doesn't work very well, leaving code here for future
DoGo(DATA_GO_BAR_KEG, 0); //spell by trap has effect61, this indicate the bar go hostile
BreakKeg_Timer = 0;
BreakDoor_Timer = 1000; if (Unit* tmp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PHALANX)))
} tmp->SetFaction(FACTION_MONSTER);
else BreakKeg_Timer -= diff;
//for later, this event(s) has alot more to it.
//optionally, DONE can trigger bar to go hostile.
instance->SetData(TYPE_BAR, DONE);
_breakDoorTimer = 0;
} }
else _breakDoorTimer -= diff;
if (BreakDoor_Timer)
{
if (BreakDoor_Timer <= diff)
{
DoGo(DATA_GO_BAR_DOOR, 2);
DoGo(DATA_GO_BAR_KEG_TRAP, 0); //doesn't work very well, leaving code here for future
//spell by trap has effect61, this indicate the bar go hostile
if (Unit* tmp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PHALANX)))
tmp->SetFaction(FACTION_MONSTER);
//for later, this event(s) has alot more to it.
//optionally, DONE can trigger bar to go hostile.
instance->SetData(TYPE_BAR, DONE);
BreakDoor_Timer = 0;
}
else BreakDoor_Timer -= diff;
}
npc_escortAI::UpdateAI(diff);
} }
};
npc_escortAI::UpdateAI(diff);
}
private:
InstanceScript* instance;
uint32 _breakKegTimer;
uint32 _breakDoorTimer;
}; };
void AddSC_blackrock_depths() void AddSC_blackrock_depths()
{ {
new go_shadowforge_brazier(); RegisterBlackrockDepthsGameObjectAI(go_shadowforge_brazier);
new at_ring_of_law(); new at_ring_of_law();
new npc_grimstone(); RegisterBlackrockDepthsCreatureAI(npc_grimstone);
new npc_phalanx(); RegisterBlackrockDepthsCreatureAI(npc_phalanx);
new npc_lokhtos_darkbargainer(); RegisterBlackrockDepthsCreatureAI(npc_lokhtos_darkbargainer);
new npc_rocknot(); RegisterBlackrockDepthsCreatureAI(npc_rocknot);
new ironhand_guardian(); RegisterBlackrockDepthsCreatureAI(brd_ironhand_guardian);
} }

View File

@@ -151,4 +151,7 @@ inline AI* GetBlackrockDepthsAI(T* obj)
return GetInstanceAI<AI>(obj, BRDScriptName); return GetInstanceAI<AI>(obj, BRDScriptName);
} }
#define RegisterBlackrockDepthsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackrockDepthsAI)
#define RegisterBlackrockDepthsGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackrockDepthsAI)
#endif #endif

View File

@@ -50,219 +50,184 @@ const Position SummonPositions[7] =
std::vector<int> gobjectDwarfRunesEntry { 170578, 170579, 170580, 170581, 170582, 170583, 170584 }; std::vector<int> gobjectDwarfRunesEntry { 170578, 170579, 170580, 170581, 170582, 170583, 170584 };
class boss_ambassador_flamelash : public CreatureScript struct boss_ambassador_flamelash : public BossAI
{ {
public: boss_ambassador_flamelash(Creature* creature) : BossAI(creature, BOSS_AMBASSADOR_FLAMELASH) { }
boss_ambassador_flamelash() : CreatureScript("boss_ambassador_flamelash") { }
CreatureAI* GetAI(Creature* creature) const override void DoAction(int32 param) override
{ {
return GetBlackrockDepthsAI<boss_ambassador_flamelashAI>(creature); switch (param)
{
case EVENT_SUMMON_SPIRITS:
events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s);
break;
}
} }
struct boss_ambassador_flamelashAI : public BossAI void Reset() override
{ {
boss_ambassador_flamelashAI(Creature* creature) : BossAI(creature, BOSS_AMBASSADOR_FLAMELASH), summons(me) { } _Reset();
TurnRunes(false);
_foundValidPosition = false;
_validPosition.clear();
}
EventMap _events; void TurnRunes(bool mode)
{
// Active makes the runes burn, ready turns them off
GOState state = mode ? GO_STATE_ACTIVE : GO_STATE_READY;
// This will help reseting the boss for (int RuneEntry : gobjectDwarfRunesEntry)
SummonList summons; if (GameObject* dwarfRune = me->FindNearestGameObject(RuneEntry, 200.0f))
dwarfRune->SetGoState(state);
}
// This will allow to find a valid position to spawn them void JustEngagedWith(Unit* /*who*/) override
std::vector<int> validPosition; {
bool foundValidPosition = false; events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 2s);
void JustSummoned(Creature* cr) override { summons.Summon(cr); } // Spawn 7 Embers initially
for (int i = 0; i < 4; ++i)
events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 4s);
void DoAction(int32 param) override // Activate the runes (Start burning)
TurnRunes(true);
Talk(AGGRO_TEXT);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
TurnRunes(false);
}
int getValidRandomPosition()
{
/* Generate a random position which
* have not been used in 4 summonings.
* Since we are calling the event whenever the Spirit
* dies and not all at the time, we need to save at
* least 4 positions until reseting the vector
*/
// Searching a new position so reset this bool check
_foundValidPosition = false;
int randomPosition;
while (!_foundValidPosition)
{ {
switch (param) /* When we have summoned 4 creatures, reset the vector
* so we can summon new spirits in other positions.*/
if (_validPosition.size() == 4)
_validPosition.clear();
// The random ranges from the position 0 to the position 6
randomPosition = urand(0, 6);
// When we have an empty vector we can use any random position generated.
if (_validPosition.empty())
_foundValidPosition = true;
/* This check is done to avoid running the vector
* when it is empty. Because if it is empty, then any
* position can be used to summon Spirits.
*/
if (!_foundValidPosition)
{ {
case EVENT_SUMMON_SPIRITS: // Check every position inside the vector
_events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); for (int pos : _validPosition)
break;
}
}
void Reset() override
{
_events.Reset();
summons.DespawnAll();
TurnRunes(false);
foundValidPosition = false;
validPosition.clear();
}
void TurnRunes(bool mode)
{
// Active makes the runes burn, ready turns them off
GOState state = mode ? GO_STATE_ACTIVE : GO_STATE_READY;
for (int RuneEntry : gobjectDwarfRunesEntry)
if (GameObject* dwarfRune = me->FindNearestGameObject(RuneEntry, 200.0f))
dwarfRune->SetGoState(state);
}
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 2s);
// Spawn 7 Embers initially
for (int i = 0; i < 4; ++i)
_events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 4s);
// Activate the runes (Start burning)
TurnRunes(true);
Talk(AGGRO_TEXT);
}
void JustDied(Unit* /*killer*/) override
{
TurnRunes(false);
_events.Reset();
summons.DespawnAll();
}
int getValidRandomPosition()
{
/* Generate a random position which
* have not been used in 4 summonings.
* Since we are calling the event whenever the Spirit
* dies and not all at the time, we need to save at
* least 4 positions until reseting the vector
*/
// Searching a new position so reset this bool check
foundValidPosition = false;
int randomPosition;
while (!foundValidPosition)
{
/* When we have summoned 4 creatures, reset the vector
* so we can summon new spirits in other positions.*/
if (validPosition.size() == 4)
validPosition.clear();
// The random ranges from the position 0 to the position 6
randomPosition = urand(0, 6);
// When we have an empty vector we can use any random position generated.
if (validPosition.empty())
foundValidPosition = true;
/* This check is done to avoid running the vector
* when it is empty. Because if it is empty, then any
* position can be used to summon Spirits.
*/
if (!foundValidPosition)
{ {
// Check every position inside the vector // If the random is different, we found a temporary true,
for (int pos : validPosition) // until we find one that is equal, which means it has been used.
if (pos != randomPosition)
_foundValidPosition = true;
else
{ {
// If the random is different, we found a temporary true, _foundValidPosition = false;
// until we find one that is equal, which means it has been used. break;
if (pos != randomPosition)
foundValidPosition = true;
else
{
foundValidPosition = false;
break;
}
} }
} }
} }
// We found a valid position. Save it and return it to summon.
validPosition.emplace_back(randomPosition);
return randomPosition;
} }
void SummonSpirits() // We found a valid position. Save it and return it to summon.
_validPosition.emplace_back(randomPosition);
return randomPosition;
}
void SummonSpirits()
{
// Make the Spirits chase Ambassador Flamelash
me->SummonCreature(NPC_FIRE_SPIRIT, SummonPositions[getValidRandomPosition()], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60 * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{ {
// Make the Spirits chase Ambassador Flamelash case EVENT_SPELL_FIREBLAST:
me->SummonCreature(NPC_FIRE_SPIRIT, SummonPositions[getValidRandomPosition()], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60 * IN_MILLISECONDS); DoCastVictim(SPELL_FIREBLAST);
_events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s);
break;
case EVENT_SUMMON_SPIRITS:
SummonSpirits();
break;
} }
void UpdateAI(uint32 diff) override DoMeleeAttackIfReady();
{ }
//Return since we have no target
if (!UpdateVictim())
return;
_events.Update(diff); private:
// This will allow to find a valid position to spawn them
switch (_events.ExecuteEvent()) std::vector<int> _validPosition;
{ bool _foundValidPosition = false;
case EVENT_SPELL_FIREBLAST:
DoCastVictim(SPELL_FIREBLAST);
_events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s);
break;
case EVENT_SUMMON_SPIRITS:
SummonSpirits();
break;
}
DoMeleeAttackIfReady();
}
};
}; };
class npc_burning_spirit : public CreatureScript struct npc_burning_spirit : public ScriptedAI
{ {
public: npc_burning_spirit(Creature* creature) : ScriptedAI(creature) {}
npc_burning_spirit() : CreatureScript("npc_burning_spirit") { }
struct npc_burning_spiritAI : public ScriptedAI void IsSummonedBy(WorldObject* summoner) override
{ {
npc_burning_spiritAI(Creature* creature) : ScriptedAI(creature) {} if (!summoner->IsCreature())
return;
void IsSummonedBy(WorldObject* summoner) override _flamelasherGUID = summoner->GetGUID();
{ me->GetMotionMaster()->MoveFollow(summoner->ToCreature(), 0.f, 0.f);
if (!summoner->IsCreature())
{
return;
}
_flamelasherGUID = summoner->GetGUID();
me->GetMotionMaster()->MoveFollow(summoner->ToCreature(), 0.f, 0.f);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID))
{
me->GetMotionMaster()->MoveFollow(flamelasher, 5.f, 0.f);
}
}
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type != FOLLOW_MOTION_TYPE)
return;
if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID))
{
flamelasher->CastSpell(flamelasher, SPELL_BURNING_SPIRIT);
Unit::Kill(flamelasher, me);
}
}
private:
EventMap _events;
ObjectGuid _flamelasherGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<npc_burning_spiritAI>(creature);
} }
void EnterEvadeMode(EvadeReason /*why*/) override
{
if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID))
me->GetMotionMaster()->MoveFollow(flamelasher, 5.f, 0.f);
}
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type != FOLLOW_MOTION_TYPE)
return;
if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID))
{
flamelasher->CastSpell(flamelasher, SPELL_BURNING_SPIRIT);
Unit::Kill(flamelasher, me);
}
}
private:
ObjectGuid _flamelasherGUID;
}; };
void AddSC_boss_ambassador_flamelash() void AddSC_boss_ambassador_flamelash()
{ {
new boss_ambassador_flamelash(); RegisterBlackrockDepthsCreatureAI(boss_ambassador_flamelash);
new npc_burning_spirit(); RegisterBlackrockDepthsCreatureAI(npc_burning_spirit);
} }

View File

@@ -34,84 +34,67 @@ constexpr Milliseconds TIMER_CURSE_WEAKNESS = 12s;
constexpr Milliseconds TIMER_DEMON_ARMOR = 3s; //virtually only cast once constexpr Milliseconds TIMER_DEMON_ARMOR = 3s; //virtually only cast once
constexpr Milliseconds TIMER_ENVELOPING_WEB = 16s; constexpr Milliseconds TIMER_ENVELOPING_WEB = 16s;
class boss_anubshiah : public CreatureScript struct boss_anubshiah : public BossAI
{ {
public: boss_anubshiah(Creature* creature) : BossAI(creature, DATA_ANUBSHIAH) { }
boss_anubshiah() : CreatureScript("boss_anubshiah") { }
CreatureAI* GetAI(Creature* creature) const override void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_anubshiahAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 5);
events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES / 5);
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS / 5);
events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR / 5);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB / 5);
} }
struct boss_anubshiahAI : public BossAI void UpdateAI(uint32 diff) override
{ {
boss_anubshiahAI(Creature* creature) : BossAI(creature, DATA_ANUBSHIAH) { } //Return since we have no target
if (!UpdateVictim())
return;
void JustEngagedWith(Unit* /*who*/) override events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustEngagedWith(); switch (eventId)
events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 5); {
events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES / 5); case SPELL_SHADOWBOLT:
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS / 5); DoCastVictim(SPELL_SHADOWBOLT);
events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR / 5); events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT - 2s, TIMER_SHADOWBOLT + 2s);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB / 5); break;
case SPELL_CURSE_TONGUES:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_CURSE_TONGUES);
events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES - 2s, TIMER_CURSE_TONGUES + 2s);
break;
case SPELL_CURSE_WEAKNESS:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_CURSE_WEAKNESS);
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS - 2s, TIMER_CURSE_WEAKNESS + 2s);
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(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_ENVELOPING_WEB);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB - 2s, TIMER_ENVELOPING_WEB + 2s);
break;
default:
break;
}
} }
DoMeleeAttackIfReady();
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:
DoCastVictim(SPELL_SHADOWBOLT);
events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT - 2s, TIMER_SHADOWBOLT + 2s);
break;
case SPELL_CURSE_TONGUES:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
DoCast(target, SPELL_CURSE_TONGUES);
}
events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES - 2s, TIMER_CURSE_TONGUES + 2s);
break;
case SPELL_CURSE_WEAKNESS:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
DoCast(target, SPELL_CURSE_WEAKNESS);
}
events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS - 2s, TIMER_CURSE_WEAKNESS + 2s);
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(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_ENVELOPING_WEB);
events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB - 2s, TIMER_ENVELOPING_WEB + 2s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_anubshiah() void AddSC_boss_anubshiah()
{ {
new boss_anubshiah(); RegisterBlackrockDepthsCreatureAI(boss_anubshiah);
} }

View File

@@ -34,106 +34,87 @@ enum Spells
#define DATA_PERCENT_DEAD_SENATORS 0 #define DATA_PERCENT_DEAD_SENATORS 0
class boss_emperor_dagran_thaurissan : public CreatureScript struct boss_emperor_dagran_thaurissan : public BossAI
{ {
public: uint32 hasYelled = 0;
boss_emperor_dagran_thaurissan() : CreatureScript("boss_emperor_dagran_thaurissan") { } uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database
CreatureAI* GetAI(Creature* creature) const override boss_emperor_dagran_thaurissan(Creature* creature) : BossAI(creature, DATA_EMPEROR){}
void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_draganthaurissanAI>(creature); if (hasYelled != 5)
Talk(YELL_SENATORS_ALIVE);
else
Talk(YELL_SENATORS_DEAD);
me->CallForHelp(VISIBLE_RANGE);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s);
events.ScheduleEvent(SPELL_AVATAROFFLAME, 10s, 12s);
} }
struct boss_draganthaurissanAI : public BossAI void KilledUnit(Unit* /*victim*/) override
{ {
uint32 hasYelled = 0; Talk(SAY_SLAY);
uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database }
boss_draganthaurissanAI(Creature* creature) : BossAI(creature, DATA_EMPEROR){} void SetData(uint32 type, uint32 data) override
{
void JustEngagedWith(Unit* /*who*/) override if (type == DATA_PERCENT_DEAD_SENATORS)
{ {
if (hasYelled != 5) if (data >= 20 * (hasYelled + 1)) // map the 5 yells to %. Yell after 20,40,60,80,100%
{ {
Talk(YELL_SENATORS_ALIVE); if (hasYelled < 5)
} if (me->IsAlive())
else Talk(SenatorYells[hasYelled]);
{ hasYelled++;
Talk(YELL_SENATORS_DEAD);
}
me->CallForHelp(VISIBLE_RANGE);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s);
events.ScheduleEvent(SPELL_AVATAROFFLAME, 10s, 12s);
}
void KilledUnit(Unit* /*victim*/) override
{
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)
{
if (me->IsAlive())
{
Talk(SenatorYells[hasYelled]);
}
}
hasYelled++;
}
} }
} }
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{
if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOIRA)))
{ {
if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOIRA))) Moira->AI()->EnterEvadeMode();
Moira->AI()->Talk(0);
Moira->SetFaction(FACTION_FRIENDLY);
}
}
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)
{ {
Moira->AI()->EnterEvadeMode(); case SPELL_HANDOFTHAURISSAN:
Moira->AI()->Talk(0); DoCast(SelectTarget(SelectTargetMethod::Random), SPELL_HANDOFTHAURISSAN);
Moira->SetFaction(FACTION_FRIENDLY); //DoCastVictim(SPELL_HANDOFTHAURISSAN);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s);
break;
case SPELL_AVATAROFFLAME:
DoCastSelf(SPELL_AVATAROFFLAME);
events.ScheduleEvent(SPELL_AVATAROFFLAME, 23s, 27s);
break;
default:
break;
} }
} }
DoMeleeAttackIfReady();
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_HANDOFTHAURISSAN:
DoCast(SelectTarget(SelectTargetMethod::Random), SPELL_HANDOFTHAURISSAN);
//DoCastVictim(SPELL_HANDOFTHAURISSAN);
events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s);
break;
case SPELL_AVATAROFFLAME:
DoCastSelf(SPELL_AVATAROFFLAME);
events.ScheduleEvent(SPELL_AVATAROFFLAME, 23s, 27s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_draganthaurissan() void AddSC_boss_draganthaurissan()
{ {
new boss_emperor_dagran_thaurissan(); RegisterBlackrockDepthsCreatureAI(boss_emperor_dagran_thaurissan);
} }

View File

@@ -30,78 +30,65 @@ constexpr Milliseconds TIMER_SHADOWBOLT_VOLLEY = 7s;
constexpr Milliseconds TIMER_REND = 20s; constexpr Milliseconds TIMER_REND = 20s;
constexpr Milliseconds TIMER_SHIELD = 12s; constexpr Milliseconds TIMER_SHIELD = 12s;
class boss_eviscerator : public CreatureScript struct boss_eviscerator : public BossAI
{ {
public: boss_eviscerator(Creature* creature) : BossAI(creature, DATA_EVISCERATOR) {}
boss_eviscerator() : CreatureScript("boss_eviscerator") {}
CreatureAI* GetAI(Creature* creature) const override bool SpellShieldReady = false;
void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_evisceratorAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY / 5);
events.ScheduleEvent(SPELL_REND, TIMER_REND / 5);
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD / 5);
} }
struct boss_evisceratorAI : public BossAI void DamageTaken(Unit* /* doneBy */, uint32& /* damage */, DamageEffectType /* damagetype */, SpellSchoolMask damageSchoolMask) override
{ {
boss_evisceratorAI(Creature* creature) : BossAI(creature, DATA_EVISCERATOR) {} if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady)
bool SpellShieldReady = false;
void JustEngagedWith(Unit* /*who*/) override
{ {
_JustEngagedWith(); DoCast(SPELL_SHIELD);
events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY / 5); SpellShieldReady = false;
events.ScheduleEvent(SPELL_REND, TIMER_REND / 5); events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD);
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD / 5);
} }
}
void DamageTaken(Unit* /* doneBy */, uint32& /* damage */, DamageEffectType /* damagetype */, SpellSchoolMask damageSchoolMask) override 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())
{ {
if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady) switch (eventId)
{ {
DoCast(SPELL_SHIELD); case SPELL_SHADOWBOLT_VOLLEY:
SpellShieldReady = false; DoCastVictim(SPELL_SHADOWBOLT_VOLLEY);
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD); events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY - 2s, TIMER_SHADOWBOLT_VOLLEY + 2s);
break;
case SPELL_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(SPELL_REND, TIMER_REND - 2s, TIMER_REND + 2s);
break;
case SPELL_SHIELD:
SpellShieldReady = true;
break;
default:
break;
} }
} }
DoMeleeAttackIfReady();
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, TIMER_SHADOWBOLT_VOLLEY - 2s, TIMER_SHADOWBOLT_VOLLEY + 2s);
break;
case SPELL_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(SPELL_REND, TIMER_REND - 2s, TIMER_REND + 2s);
break;
case SPELL_SHIELD:
SpellShieldReady = true;
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_eviscerator() void AddSC_boss_eviscerator()
{ {
new boss_eviscerator(); RegisterBlackrockDepthsCreatureAI(boss_eviscerator);
} }

View File

@@ -26,108 +26,94 @@ enum Spells
SPELL_CLEAVE = 20691 SPELL_CLEAVE = 20691
}; };
class boss_general_angerforge : public CreatureScript struct boss_general_angerforge : public ScriptedAI
{ {
public: boss_general_angerforge(Creature* creature) : ScriptedAI(creature) { }
boss_general_angerforge() : CreatureScript("boss_general_angerforge") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockDepthsAI<boss_general_angerforgeAI>(creature); _mightyBlowTimer = 8000;
_hamStringTimer = 12000;
_cleaveTimer = 16000;
_addsTimer = 0;
_medics = false;
} }
struct boss_general_angerforgeAI : public ScriptedAI void JustEngagedWith(Unit* /*who*/) override { }
void SummonAdds(Unit* victim)
{ {
boss_general_angerforgeAI(Creature* creature) : ScriptedAI(creature) { } if (Creature* SummonedAdd = DoSpawnCreature(8901, float(irand(-14, 14)), float(irand(-14, 14)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000))
SummonedAdd->AI()->AttackStart(victim);
}
uint32 MightyBlow_Timer; void SummonMedics(Unit* victim)
uint32 HamString_Timer; {
uint32 Cleave_Timer; if (Creature* SummonedMedic = DoSpawnCreature(8894, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000))
uint32 Adds_Timer; SummonedMedic->AI()->AttackStart(victim);
bool Medics; }
void Reset() override void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
if (_mightyBlowTimer <= diff)
{ {
MightyBlow_Timer = 8000; DoCastVictim(SPELL_MIGHTYBLOW);
HamString_Timer = 12000; _mightyBlowTimer = 18000;
Cleave_Timer = 16000; }
Adds_Timer = 0; else _mightyBlowTimer -= diff;
Medics = false;
if (_hamStringTimer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
_hamStringTimer = 15000;
}
else _hamStringTimer -= diff;
if (_cleaveTimer <= diff)
{
DoCastVictim(SPELL_CLEAVE);
_cleaveTimer = 9000;
}
else _cleaveTimer -= diff;
if (HealthBelowPct(21))
{
if (_addsTimer <= diff)
{
// summon 3 Adds every 25s
SummonAdds(me->GetVictim());
SummonAdds(me->GetVictim());
SummonAdds(me->GetVictim());
_addsTimer = 25000;
}
else _addsTimer -= diff;
} }
void JustEngagedWith(Unit* /*who*/) override { } //Summon Medics
if (!_medics && HealthBelowPct(21))
void SummonAdds(Unit* victim)
{ {
if (Creature* SummonedAdd = DoSpawnCreature(8901, float(irand(-14, 14)), float(irand(-14, 14)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000)) SummonMedics(me->GetVictim());
SummonedAdd->AI()->AttackStart(victim); SummonMedics(me->GetVictim());
_medics = true;
} }
void SummonMedics(Unit* victim) DoMeleeAttackIfReady();
{ }
if (Creature* SummonedMedic = DoSpawnCreature(8894, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000))
SummonedMedic->AI()->AttackStart(victim);
}
void UpdateAI(uint32 diff) override private:
{ uint32 _mightyBlowTimer;
//Return since we have no target uint32 _hamStringTimer;
if (!UpdateVictim()) uint32 _cleaveTimer;
return; uint32 _addsTimer;
bool _medics;
//MightyBlow_Timer
if (MightyBlow_Timer <= diff)
{
DoCastVictim(SPELL_MIGHTYBLOW);
MightyBlow_Timer = 18000;
}
else MightyBlow_Timer -= diff;
//HamString_Timer
if (HamString_Timer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
HamString_Timer = 15000;
}
else HamString_Timer -= diff;
//Cleave_Timer
if (Cleave_Timer <= diff)
{
DoCastVictim(SPELL_CLEAVE);
Cleave_Timer = 9000;
}
else Cleave_Timer -= diff;
//Adds_Timer
if (HealthBelowPct(21))
{
if (Adds_Timer <= diff)
{
// summon 3 Adds every 25s
SummonAdds(me->GetVictim());
SummonAdds(me->GetVictim());
SummonAdds(me->GetVictim());
Adds_Timer = 25000;
}
else Adds_Timer -= diff;
}
//Summon Medics
if (!Medics && HealthBelowPct(21))
{
SummonMedics(me->GetVictim());
SummonMedics(me->GetVictim());
Medics = true;
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_general_angerforge() void AddSC_boss_general_angerforge()
{ {
new boss_general_angerforge(); RegisterBlackrockDepthsCreatureAI(boss_general_angerforge);
} }

View File

@@ -30,78 +30,65 @@ constexpr Milliseconds TIMER_WHIRLWIND = 12s;
constexpr Milliseconds TIMER_MORTAL = 22s; constexpr Milliseconds TIMER_MORTAL = 22s;
constexpr Milliseconds TIMER_BLOODLUST = 30s; constexpr Milliseconds TIMER_BLOODLUST = 30s;
class boss_gorosh_the_dervish : public CreatureScript struct boss_gorosh_the_dervish : public BossAI
{ {
public: boss_gorosh_the_dervish(Creature* creature) : BossAI(creature, DATA_GOROSH) { }
boss_gorosh_the_dervish() : CreatureScript("boss_gorosh_the_dervish") { }
CreatureAI* GetAI(Creature* creature) const override Milliseconds nextWhirlwindTime;
void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_gorosh_the_dervishAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_WHIRLWIND, TIMER_WHIRLWIND / 5);
events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL / 5);
events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST / 5);
} }
struct boss_gorosh_the_dervishAI : public BossAI void UpdateAI(uint32 diff) override
{ {
boss_gorosh_the_dervishAI(Creature* creature) : BossAI(creature, DATA_GOROSH) { } // Return since we have no target
if (!UpdateVictim())
return;
Milliseconds nextWhirlwindTime; events.Update(diff);
void JustEngagedWith(Unit* /*who*/) override if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustEngagedWith(); switch (eventId)
events.ScheduleEvent(SPELL_WHIRLWIND, TIMER_WHIRLWIND / 5);
events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL / 5);
events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST / 5);
}
void UpdateAI(uint32 diff) override
{
// Return since we have no target
if (!UpdateVictim())
{ {
return; case SPELL_WHIRLWIND:
} if (me->GetDistance2d(me->GetVictim()) < 10.0f)
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{ {
case SPELL_WHIRLWIND: DoCastVictim(SPELL_WHIRLWIND);
if (me->GetDistance2d(me->GetVictim()) < 10.0f) nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s);
{
DoCastVictim(SPELL_WHIRLWIND);
nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s);
}
else
{
// reschedule sooner
nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s) / 3;
}
events.ScheduleEvent(SPELL_WHIRLWIND, nextWhirlwindTime);
break;
case SPELL_MORTALSTRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL - 2s, TIMER_MORTAL + 2s);
break;
case SPELL_BLOODLUST:
DoCastSelf(SPELL_BLOODLUST);
events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST - 2s, TIMER_BLOODLUST + 2s);
break;
default:
break;
} }
else
{
// reschedule sooner
nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s) / 3;
}
events.ScheduleEvent(SPELL_WHIRLWIND, nextWhirlwindTime);
break;
case SPELL_MORTALSTRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL - 2s, TIMER_MORTAL + 2s);
break;
case SPELL_BLOODLUST:
DoCastSelf(SPELL_BLOODLUST);
events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST - 2s, TIMER_BLOODLUST + 2s);
break;
default:
break;
} }
DoMeleeAttackIfReady();
} }
}; DoMeleeAttackIfReady();
}
}; };
void AddSC_boss_gorosh_the_dervish() void AddSC_boss_gorosh_the_dervish()
{ {
new boss_gorosh_the_dervish(); RegisterBlackrockDepthsCreatureAI(boss_gorosh_the_dervish);
} }

View File

@@ -29,74 +29,60 @@ enum Grizzle
constexpr Milliseconds TIMER_GROUNDTREMOR = 10s; constexpr Milliseconds TIMER_GROUNDTREMOR = 10s;
constexpr Milliseconds TIMER_FRENZY = 15s; constexpr Milliseconds TIMER_FRENZY = 15s;
class boss_grizzle : public CreatureScript struct boss_grizzle : public BossAI
{ {
public: boss_grizzle(Creature* creature) : BossAI(creature, DATA_GRIZZLE) {}
boss_grizzle() : CreatureScript("boss_grizzle") { }
CreatureAI* GetAI(Creature* creature) const override Milliseconds nextTremorTime;
void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_grizzleAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_GROUNDTREMOR, TIMER_GROUNDTREMOR / 5);
events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY / 5);
} }
struct boss_grizzleAI : public BossAI void UpdateAI(uint32 diff) override
{ {
boss_grizzleAI(Creature* creature) : BossAI(creature, DATA_GRIZZLE) {} //Return since we have no target
if (!UpdateVictim())
return;
Milliseconds nextTremorTime; events.Update(diff);
void JustEngagedWith(Unit* /*who*/) override if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustEngagedWith(); switch (eventId)
events.ScheduleEvent(SPELL_GROUNDTREMOR, TIMER_GROUNDTREMOR / 5);
events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY / 5);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{ {
return; case SPELL_GROUNDTREMOR:
} if (me->GetDistance2d(me->GetVictim()) < 10.0f)
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{ {
case SPELL_GROUNDTREMOR: DoCastVictim(SPELL_GROUNDTREMOR);
if (me->GetDistance2d(me->GetVictim()) < 10.0f) nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s);
{
DoCastVictim(SPELL_GROUNDTREMOR);
nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s);
}
else
{
nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s) / 3;
}
events.ScheduleEvent(SPELL_GROUNDTREMOR, nextTremorTime);
break;
case SPELL_FRENZY:
DoCastSelf(SPELL_FRENZY);
events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY - 2s, TIMER_FRENZY + 2s);
Talk(EMOTE_FRENZY_KILL);
break;
default:
break;
} }
else
{
nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s) / 3;
}
events.ScheduleEvent(SPELL_GROUNDTREMOR, nextTremorTime);
break;
case SPELL_FRENZY:
DoCastSelf(SPELL_FRENZY);
events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY - 2s, TIMER_FRENZY + 2s);
Talk(EMOTE_FRENZY_KILL);
break;
default:
break;
} }
DoMeleeAttackIfReady();
} }
}; DoMeleeAttackIfReady();
}
}; };
void AddSC_boss_grizzle() void AddSC_boss_grizzle()
{ {
new boss_grizzle(); RegisterBlackrockDepthsCreatureAI(boss_grizzle);
} }

View File

@@ -30,70 +30,55 @@ constexpr Milliseconds TIMER_PARALYZING = 20s;
constexpr Milliseconds TIMER_BANEFUL = 24s; constexpr Milliseconds TIMER_BANEFUL = 24s;
constexpr Milliseconds TIMER_WEB_EXPLOSION = 20s; constexpr Milliseconds TIMER_WEB_EXPLOSION = 20s;
class boss_hedrum : public CreatureScript struct boss_hedrum : public BossAI
{ {
public: boss_hedrum(Creature* creature) : BossAI(creature, DATA_HEDRUM) {}
boss_hedrum() : CreatureScript("boss_hedrum") {}
CreatureAI* GetAI(Creature* creature) const override void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_hedrumAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING / 5);
events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL / 5);
events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION / 5);
} }
struct boss_hedrumAI : public BossAI void UpdateAI(uint32 diff) override
{ {
boss_hedrumAI(Creature* creature) : BossAI(creature, DATA_HEDRUM) {} // Return since we have no target
if (!UpdateVictim())
return;
void JustEngagedWith(Unit* /*who*/) override events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustEngagedWith(); switch (eventId)
events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING / 5); {
events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL / 5); case SPELL_PARALYZING:
events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION / 5); DoCastVictim(SPELL_PARALYZING);
events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING - 2s, TIMER_PARALYZING + 2s);
break;
case SPELL_BANEFUL:
DoCastVictim(SPELL_BANEFUL);
events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL - 2s, TIMER_BANEFUL + 2s);
break;
case SPELL_WEB_EXPLOSION:
if (me->GetDistance2d(me->GetVictim()) < 100.0f)
DoCast(SPELL_WEB_EXPLOSION);
events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION - 2s, TIMER_WEB_EXPLOSION + 2s);
break;
default:
break;
}
} }
DoMeleeAttackIfReady();
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, TIMER_PARALYZING - 2s, TIMER_PARALYZING + 2s);
break;
case SPELL_BANEFUL:
DoCastVictim(SPELL_BANEFUL);
events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL - 2s, TIMER_BANEFUL + 2s);
break;
case SPELL_WEB_EXPLOSION:
if (me->GetDistance2d(me->GetVictim()) < 100.0f)
{
DoCast(SPELL_WEB_EXPLOSION);
}
events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION - 2s, TIMER_WEB_EXPLOSION + 2s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_hedrum() void AddSC_boss_hedrum()
{ {
new boss_hedrum(); RegisterBlackrockDepthsCreatureAI(boss_hedrum);
} }

View File

@@ -27,81 +27,67 @@ enum Spells
SPELL_SHADOWSHIELD = 22417 SPELL_SHADOWSHIELD = 22417
}; };
class boss_high_interrogator_gerstahn : public CreatureScript struct boss_high_interrogator_gerstahn : public ScriptedAI
{ {
public: boss_high_interrogator_gerstahn(Creature* creature) : ScriptedAI(creature) { }
boss_high_interrogator_gerstahn() : CreatureScript("boss_high_interrogator_gerstahn") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockDepthsAI<boss_high_interrogator_gerstahnAI>(creature); _shadowWordPainTimer = 4000;
_manaBurnTimer = 14000;
_psychicScreamTimer = 32000;
_shadowShieldTimer = 8000;
} }
struct boss_high_interrogator_gerstahnAI : public ScriptedAI void JustEngagedWith(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{ {
boss_high_interrogator_gerstahnAI(Creature* creature) : ScriptedAI(creature) { } //Return since we have no target
if (!UpdateVictim())
return;
uint32 ShadowWordPain_Timer; if (_shadowWordPainTimer <= diff)
uint32 ManaBurn_Timer;
uint32 PsychicScream_Timer;
uint32 ShadowShield_Timer;
void Reset() override
{ {
ShadowWordPain_Timer = 4000; if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
ManaBurn_Timer = 14000; DoCast(target, SPELL_SHADOWWORDPAIN);
PsychicScream_Timer = 32000; _shadowWordPainTimer = 7000;
ShadowShield_Timer = 8000;
} }
else _shadowWordPainTimer -= diff;
void JustEngagedWith(Unit* /*who*/) override { } if (_manaBurnTimer <= diff)
void UpdateAI(uint32 diff) override
{ {
//Return since we have no target if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
if (!UpdateVictim()) DoCast(target, SPELL_MANABURN);
return; _manaBurnTimer = 10000;
//ShadowWordPain_Timer
if (ShadowWordPain_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_SHADOWWORDPAIN);
ShadowWordPain_Timer = 7000;
}
else ShadowWordPain_Timer -= diff;
//ManaBurn_Timer
if (ManaBurn_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_MANABURN);
ManaBurn_Timer = 10000;
}
else ManaBurn_Timer -= diff;
//PsychicScream_Timer
if (PsychicScream_Timer <= diff)
{
DoCastVictim(SPELL_PSYCHICSCREAM);
PsychicScream_Timer = 30000;
}
else PsychicScream_Timer -= diff;
//ShadowShield_Timer
if (ShadowShield_Timer <= diff)
{
DoCast(me, SPELL_SHADOWSHIELD);
ShadowShield_Timer = 25000;
}
else ShadowShield_Timer -= diff;
DoMeleeAttackIfReady();
} }
}; else _manaBurnTimer -= diff;
if (_psychicScreamTimer <= diff)
{
DoCastVictim(SPELL_PSYCHICSCREAM);
_psychicScreamTimer = 30000;
}
else _psychicScreamTimer -= diff;
if (_shadowShieldTimer <= diff)
{
DoCast(me, SPELL_SHADOWSHIELD);
_shadowShieldTimer = 25000;
}
else _shadowShieldTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 _shadowWordPainTimer;
uint32 _manaBurnTimer;
uint32 _psychicScreamTimer;
uint32 _shadowShieldTimer;
}; };
void AddSC_boss_high_interrogator_gerstahn() void AddSC_boss_high_interrogator_gerstahn()
{ {
new boss_high_interrogator_gerstahn(); RegisterBlackrockDepthsCreatureAI(boss_high_interrogator_gerstahn);
} }

View File

@@ -25,66 +25,54 @@ enum Spells
SPELL_WARSTOMP = 24375 SPELL_WARSTOMP = 24375
}; };
class boss_magmus : public CreatureScript struct boss_magmus : public BossAI
{ {
public: boss_magmus(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {}
boss_magmus() : CreatureScript("boss_magmus") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockDepthsAI<boss_magmusAI>(creature); _Reset();
instance->SetData(TYPE_IRON_HALL, NOT_STARTED);
} }
struct boss_magmusAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_magmusAI(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {} instance->SetData(TYPE_IRON_HALL, IN_PROGRESS);
_JustEngagedWith();
events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s);
events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s);
}
void Reset() override void UpdateAI(uint32 diff) override
{ {
_Reset(); //Return since we have no target
instance->SetData(TYPE_IRON_HALL, NOT_STARTED); if (!UpdateVictim())
} return;
void JustEngagedWith(Unit* /*who*/) override events.Update(diff);
{
instance->SetData(TYPE_IRON_HALL, IN_PROGRESS);
_JustEngagedWith();
events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s);
events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s);
}
void UpdateAI(uint32 diff) override while (uint32 eventId = events.ExecuteEvent())
{ {
//Return since we have no target switch (eventId)
if (!UpdateVictim())
{ {
return; case SPELL_WARSTOMP:
DoCastVictim(SPELL_WARSTOMP);
events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s);
break;
case SPELL_FIERYBURST:
DoCastVictim(SPELL_FIERYBURST);
events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s);
break;
default:
break;
} }
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_WARSTOMP:
DoCastVictim(SPELL_WARSTOMP);
events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s);
break;
case SPELL_FIERYBURST:
DoCastVictim(SPELL_FIERYBURST);
events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
} }
};
DoMeleeAttackIfReady();
}
}; };
void AddSC_boss_magmus() void AddSC_boss_magmus()
{ {
new boss_magmus(); RegisterBlackrockDepthsCreatureAI(boss_magmus);
} }

View File

@@ -34,10 +34,10 @@ constexpr Milliseconds TIMER_RENEW = 12s;
constexpr Milliseconds TIMER_SHADOWBOLT = 16s; constexpr Milliseconds TIMER_SHADOWBOLT = 16s;
constexpr Milliseconds TIMER_WORDPAIN = 12s; constexpr Milliseconds TIMER_WORDPAIN = 12s;
struct boss_moira_bronzebeardAI : public BossAI struct boss_moira_bronzebeard : public BossAI
{ {
// use a default value so we can inherit for priestess // use a default value so we can inherit for priestess
boss_moira_bronzebeardAI(Creature* creature, uint32 data = DATA_MOIRA) : BossAI(creature, data) {} boss_moira_bronzebeard(Creature* creature, uint32 data = DATA_MOIRA) : BossAI(creature, data) {}
void JustEngagedWith(Unit* /*who*/) override void JustEngagedWith(Unit* /*who*/) override
{ {
_JustEngagedWith(); _JustEngagedWith();
@@ -49,15 +49,13 @@ struct boss_moira_bronzebeardAI : public BossAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
@@ -83,22 +81,18 @@ struct boss_moira_bronzebeardAI : public BossAI
{ {
Creature* emperor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EMPEROR)); Creature* emperor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EMPEROR));
if (emperor && emperor->HealthBelowPct(90)) if (emperor && emperor->HealthBelowPct(90))
{
DoCast(emperor, spell); DoCast(emperor, spell);
}
else if (HealthBelowPct(90)) else if (HealthBelowPct(90))
{
DoCastSelf(spell); DoCastSelf(spell);
}
events.ScheduleEvent(spell, timer - 2s, timer + 2s); events.ScheduleEvent(spell, timer - 2s, timer + 2s);
} }
}; };
// high priestess should be fairly identical to Moira. // high priestess should be fairly identical to Moira.
// Running away when emperor dies is handled through GUID from emperor, therefore not relevant here. // Running away when emperor dies is handled through GUID from emperor, therefore not relevant here.
struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI struct boss_high_priestess_thaurissan : public boss_moira_bronzebeard
{ {
boss_high_priestess_thaurissanAI(Creature* creature) : boss_moira_bronzebeardAI(creature, DATA_PRIESTESS) {} boss_high_priestess_thaurissan(Creature* creature) : boss_moira_bronzebeard(creature, DATA_PRIESTESS) {}
void JustEngagedWith(Unit* /*who*/) override void JustEngagedWith(Unit* /*who*/) override
{ {
@@ -110,18 +104,16 @@ struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI
events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 2); events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 2);
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
@@ -148,34 +140,12 @@ struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI
} }
}; };
class boss_moira_bronzebeard : public CreatureScript
{
public:
boss_moira_bronzebeard() : CreatureScript("boss_moira_bronzebeard") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<boss_moira_bronzebeardAI>(creature);
}
};
class boss_high_priestess_thaurissan : public CreatureScript
{
public:
boss_high_priestess_thaurissan() : CreatureScript("boss_high_priestess_thaurissan") {}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockDepthsAI<boss_high_priestess_thaurissanAI>(creature);
}
};
void AddSC_boss_moira_bronzebeard() void AddSC_boss_moira_bronzebeard()
{ {
new boss_moira_bronzebeard(); RegisterBlackrockDepthsCreatureAI(boss_moira_bronzebeard);
} }
void AddSC_boss_high_priestess_thaurissan() void AddSC_boss_high_priestess_thaurissan()
{ {
new boss_high_priestess_thaurissan(); RegisterBlackrockDepthsCreatureAI(boss_high_priestess_thaurissan);
} }

View File

@@ -32,92 +32,74 @@ constexpr Milliseconds TIMER_ARCANE_EXPLOSION = 24s;
constexpr Milliseconds TIMER_POLYMORPH = 12s; constexpr Milliseconds TIMER_POLYMORPH = 12s;
constexpr Milliseconds TIMER_SLOW = 15s; constexpr Milliseconds TIMER_SLOW = 15s;
class boss_okthor : public CreatureScript struct boss_okthor : public BossAI
{ {
public: boss_okthor(Creature* creature) : BossAI(creature, DATA_OKTHOR) {}
boss_okthor() : CreatureScript("boss_okthor") {}
CreatureAI* GetAI(Creature* creature) const override void JustEngagedWith(Unit* /*who*/) override
{ {
return GetBlackrockDepthsAI<boss_okthorAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT / 5);
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, TIMER_ARCANE_EXPLOSION / 5);
events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH / 5);
events.ScheduleEvent(SPELL_SLOW, 500ms);
} }
struct boss_okthorAI : public BossAI void UpdateAI(uint32 diff) override
{ {
boss_okthorAI(Creature* creature) : BossAI(creature, DATA_OKTHOR) {} //Return since we have no target
if (!UpdateVictim())
return;
Milliseconds nextArcaneExplosionTime; events.Update(diff);
void JustEngagedWith(Unit* /*who*/) override if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustEngagedWith(); switch (eventId)
events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT / 5);
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, TIMER_ARCANE_EXPLOSION / 5);
events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH / 5);
events.ScheduleEvent(SPELL_SLOW, 500ms);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
{ {
return; case SPELL_ARCANE_BOLT:
} if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
events.Update(diff); DoCast(target, SPELL_ARCANE_BOLT);
events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT - 2s, TIMER_ARCANE_BOLT + 2s);
if (me->HasUnitState(UNIT_STATE_CASTING)) break;
{ case SPELL_ARCANE_EXPLOSION:
return; if (me->GetDistance2d(me->GetVictim()) < 50.0f)
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{ {
case SPELL_ARCANE_BOLT: DoCast(SPELL_ARCANE_EXPLOSION);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) _nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s);
{
DoCast(target, SPELL_ARCANE_BOLT);
}
events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT - 2s, TIMER_ARCANE_BOLT + 2s);
break;
case SPELL_ARCANE_EXPLOSION:
if (me->GetDistance2d(me->GetVictim()) < 50.0f)
{
DoCast(SPELL_ARCANE_EXPLOSION);
nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s);
}
else
{
nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s) / 3;
}
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, nextArcaneExplosionTime);
break;
case SPELL_POLYMORPH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
DoCast(target, SPELL_POLYMORPH);
}
events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH - 2s, TIMER_POLYMORPH + 2s);
break;
case SPELL_SLOW:
if (me->GetDistance2d(me->GetVictim()) < 50.0f)
{
DoCast(SPELL_SLOW);
}
events.ScheduleEvent(SPELL_SLOW, TIMER_SLOW);
break;
default:
break;
} }
else
{
_nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s) / 3;
}
events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, _nextArcaneExplosionTime);
break;
case SPELL_POLYMORPH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_POLYMORPH);
events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH - 2s, TIMER_POLYMORPH + 2s);
break;
case SPELL_SLOW:
if (me->GetDistance2d(me->GetVictim()) < 50.0f)
DoCast(SPELL_SLOW);
events.ScheduleEvent(SPELL_SLOW, TIMER_SLOW);
break;
default:
break;
} }
DoMeleeAttackIfReady();
} }
}; DoMeleeAttackIfReady();
}
private:
Milliseconds _nextArcaneExplosionTime;
}; };
void AddSC_boss_okthor() void AddSC_boss_okthor()
{ {
new boss_okthor(); RegisterBlackrockDepthsCreatureAI(boss_okthor);
} }

View File

@@ -53,19 +53,18 @@ enum Gossip
SAY_QUEST_COMPLETED_END = 2606, // You have shown me your desire, and have payed with precious stone. I will teach you... SAY_QUEST_COMPLETED_END = 2606, // You have shown me your desire, and have payed with precious stone. I will teach you...
}; };
class boss_gloomrel : public CreatureScript struct boss_gloomrel : public ScriptedAI
{ {
public: boss_gloomrel(Creature* creature) : ScriptedAI(creature) { }
boss_gloomrel() : CreatureScript("boss_gloomrel") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
switch (action) switch (action)
{ {
case GOSSIP_ACTION_INFO_DEF+1: case GOSSIP_ACTION_INFO_DEF+1:
AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11);
SendGossipMenuFor(player, SAY_QUEST_COMPLETED_END, creature->GetGUID()); SendGossipMenuFor(player, SAY_QUEST_COMPLETED_END, me->GetGUID());
break; break;
case GOSSIP_ACTION_INFO_DEF+11: case GOSSIP_ACTION_INFO_DEF+11:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
@@ -73,33 +72,29 @@ public:
break; break;
case GOSSIP_ACTION_INFO_DEF+2: case GOSSIP_ACTION_INFO_DEF+2:
AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22);
SendGossipMenuFor(player, SAY_QUEST_ACCEPTED, creature->GetGUID()); SendGossipMenuFor(player, SAY_QUEST_ACCEPTED, me->GetGUID());
break; break;
case GOSSIP_ACTION_INFO_DEF+22: case GOSSIP_ACTION_INFO_DEF+22:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
if (InstanceScript* instance = creature->GetInstanceScript()) if (InstanceScript* instance = me->GetInstanceScript())
{
//are 5 minutes expected? go template may have data to despawn when used at quest //are 5 minutes expected? go template may have data to despawn when used at quest
instance->DoRespawnGameObject(instance->GetGuidData(DATA_GO_CHALICE), MINUTE * 5); instance->DoRespawnGameObject(instance->GetGuidData(DATA_GO_CHALICE), MINUTE * 5);
}
break; break;
} }
return true;
} }
bool OnGossipHello(Player* player, Creature* creature) override void sGossipHello(Player* player) override
{ {
if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 1 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN && !player->HasSpell(SPELL_SMELT_DARK_IRON)) if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 1 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN && !player->HasSpell(SPELL_SMELT_DARK_IRON))
{ {
AddGossipItemFor(player, GOSSIP_GROOMREL, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); AddGossipItemFor(player, GOSSIP_GROOMREL, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, SAY_QUEST_COMPLETED, creature->GetGUID()); SendGossipMenuFor(player, SAY_QUEST_COMPLETED, me->GetGUID());
} }
if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 0 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN) if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 0 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN)
AddGossipItemFor(player, GOSSIP_GROOMREL, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); AddGossipItemFor(player, GOSSIP_GROOMREL, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID());
return true;
} }
}; };
@@ -120,145 +115,124 @@ enum DoomrelEvents
EVENT_SPELL_SUMMON_VOIDWALKERS = 5, EVENT_SPELL_SUMMON_VOIDWALKERS = 5,
}; };
class boss_doomrel : public CreatureScript struct boss_doomrel : public ScriptedAI
{ {
public: boss_doomrel(Creature* creature) : ScriptedAI(creature)
boss_doomrel() : CreatureScript("boss_doomrel") { } {
instance = creature->GetInstanceScript();
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override InstanceScript* instance;
EventMap _events;
bool Voidwalkers;
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
switch (action) switch (action)
{ {
case GOSSIP_ACTION_INFO_DEF+1: case GOSSIP_ACTION_INFO_DEF+1:
AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, SAY_QUEST_COMPLETED, creature->GetGUID()); SendGossipMenuFor(player, SAY_QUEST_COMPLETED, me->GetGUID());
break; break;
case GOSSIP_ACTION_INFO_DEF+2: case GOSSIP_ACTION_INFO_DEF+2:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
// Start encounter // Start encounter
InstanceScript* instance = creature->GetInstanceScript();
if (instance) if (instance)
{
instance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS); instance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS);
} Talk(SAY_START_FIGHT);
creature->AI()->Talk(SAY_START_FIGHT);
break; break;
} }
return true;
} }
bool OnGossipHello(Player* player, Creature* creature) override void sGossipHello(Player* player) override
{ {
AddGossipItemFor(player, GOSSIP_DOOMREL_START_COMBAT, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); AddGossipItemFor(player, GOSSIP_DOOMREL_START_COMBAT, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, SAY_DOOMREL_HELLO, creature->GetGUID()); SendGossipMenuFor(player, SAY_DOOMREL_HELLO, me->GetGUID());
return true;
} }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockDepthsAI<boss_doomrelAI>(creature); Voidwalkers = false;
me->SetFaction(FACTION_FRIENDLY);
// was set before event start, so set again
me->SetImmuneToPC(true);
if (instance->GetData(TYPE_TOMB_OF_SEVEN) == DONE) // what is this trying to do? Probably some kind of crash recovery
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE);
else
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP);
} }
struct boss_doomrelAI : public ScriptedAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_doomrelAI(Creature* creature) : ScriptedAI(creature) _events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 10s);
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 18s);
_events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 5s);
_events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 16s);
_events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
me->LoadCreaturesAddon(true);
if (me->IsAlive())
me->GetMotionMaster()->MoveTargetedHome();
me->SetLootRecipient(nullptr);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
switch (_events.ExecuteEvent())
{ {
instance = creature->GetInstanceScript(); case EVENT_SPELL_SHADOWBOLTVOLLEY:
DoCastVictim(SPELL_SHADOWBOLTVOLLEY);
_events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 12s);
break;
case EVENT_SPELL_IMMOLATE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
DoCast(target, SPELL_IMMOLATE);
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 25s);
}
// Didn't get a target, try again in 1s
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 1s);
break;
case EVENT_SPELL_CURSEOFWEAKNESS:
DoCastVictim(SPELL_CURSEOFWEAKNESS);
_events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 45s);
break;
case EVENT_SPELL_DEMONARMOR:
DoCast(me, SPELL_DEMONARMOR);
_events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 300s);
break;
case EVENT_SPELL_SUMMON_VOIDWALKERS:
if (!Voidwalkers && HealthBelowPct(51))
{
DoCastVictim(SPELL_SUMMON_VOIDWALKERS, true);
Voidwalkers = true;
}
// Not ready yet, try again in 1s
_events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s);
break;
} }
InstanceScript* instance; DoMeleeAttackIfReady();
EventMap _events; }
bool Voidwalkers;
void Reset() override
{
Voidwalkers = false;
me->SetFaction(FACTION_FRIENDLY);
// was set before event start, so set again
me->SetImmuneToPC(true);
if (instance->GetData(TYPE_TOMB_OF_SEVEN) == DONE) // what is this trying to do? Probably some kind of crash recovery
{
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE);
}
else
{
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 10s);
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 18s);
_events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 5s);
_events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 16s);
_events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
me->LoadCreaturesAddon(true);
if (me->IsAlive())
me->GetMotionMaster()->MoveTargetedHome();
me->SetLootRecipient(nullptr);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
switch (_events.ExecuteEvent())
{
case EVENT_SPELL_SHADOWBOLTVOLLEY:
DoCastVictim(SPELL_SHADOWBOLTVOLLEY);
_events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 12s);
break;
case EVENT_SPELL_IMMOLATE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
DoCast(target, SPELL_IMMOLATE);
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 25s);
}
// Didn't get a target, try again in 1s
_events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 1s);
break;
case EVENT_SPELL_CURSEOFWEAKNESS:
DoCastVictim(SPELL_CURSEOFWEAKNESS);
_events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 45s);
break;
case EVENT_SPELL_DEMONARMOR:
DoCast(me, SPELL_DEMONARMOR);
_events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 300s);
break;
case EVENT_SPELL_SUMMON_VOIDWALKERS:
if (!Voidwalkers && HealthBelowPct(51))
{
DoCastVictim(SPELL_SUMMON_VOIDWALKERS, true);
Voidwalkers = true;
}
// Not ready yet, try again in 1s
_events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s);
break;
}
DoMeleeAttackIfReady();
}
};
}; };
void AddSC_boss_tomb_of_seven() void AddSC_boss_tomb_of_seven()
{ {
new boss_gloomrel(); RegisterBlackrockDepthsCreatureAI(boss_gloomrel);
new boss_doomrel(); RegisterBlackrockDepthsCreatureAI(boss_doomrel);
} }

View File

@@ -155,5 +155,6 @@ inline AI* GetBlackrockSpireAI(T* obj)
} }
#define RegisterBlackrockSpireCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackrockSpireAI) #define RegisterBlackrockSpireCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackrockSpireAI)
#define RegisterBlackrockSpireGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackrockSpireAI)
#endif #endif

View File

@@ -40,98 +40,85 @@ enum Events
EVENT_CHECK_CONFLAGRATION_TARGET EVENT_CHECK_CONFLAGRATION_TARGET
}; };
class boss_drakkisath : public CreatureScript struct boss_drakkisath : public BossAI
{ {
public: boss_drakkisath(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH)
boss_drakkisath() : CreatureScript("boss_drakkisath") { }
struct boss_drakkisathAI : public BossAI
{ {
boss_drakkisathAI(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH) _conflagrateThreat = 0.0f;
{
_conflagrateThreat = 0.0f;
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s);
events.ScheduleEvent(EVENT_CLEAVE, 8s);
events.ScheduleEvent(EVENT_CONFLAGRATION, 15s);
events.ScheduleEvent(EVENT_THUNDERCLAP, 17s);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, 5s);
events.ScheduleEvent(EVENT_RAGE, 1s);
}
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 EVENT_FLAMESTRIKE:
DoCastAOE(SPELL_FLAMESTRIKE);
events.ScheduleEvent(EVENT_FLAMESTRIKE, 10s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 8s);
break;
case EVENT_CONFLAGRATION:
DoCastVictim(SPELL_CONFLAGRATION);
if (Unit* target = me->GetVictim())
{
_conflagrateTarget = me->GetVictim()->GetGUID();
_conflagrateThreat = me->GetThreatMgr().GetThreat(me->GetVictim());
me->GetThreatMgr().ModifyThreatByPercent(target, -100);
}
events.ScheduleEvent(EVENT_CONFLAGRATION, 18s, 25s);
events.ScheduleEvent(EVENT_CHECK_CONFLAGRATION_TARGET, 10s);
break;
case EVENT_THUNDERCLAP:
DoCastVictim(SPELL_THUNDERCLAP);
events.ScheduleEvent(EVENT_THUNDERCLAP, 20s);
break;
case EVENT_PIERCE_ARMOR:
DoCastVictim(SPELL_PIERCE_ARMOR);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, 40s);
break;
case EVENT_RAGE:
DoCastSelf(SPELL_RAGE);
events.ScheduleEvent(EVENT_RAGE, 35s);
break;
case EVENT_CHECK_CONFLAGRATION_TARGET:
if (Unit* target = ObjectAccessor::GetUnit(*me, _conflagrateTarget))
{
me->GetThreatMgr().AddThreat(target, _conflagrateThreat);
}
break;
}
}
DoMeleeAttackIfReady();
}
private:
float _conflagrateThreat;
ObjectGuid _conflagrateTarget;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_drakkisathAI>(creature);
} }
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s);
events.ScheduleEvent(EVENT_CLEAVE, 8s);
events.ScheduleEvent(EVENT_CONFLAGRATION, 15s);
events.ScheduleEvent(EVENT_THUNDERCLAP, 17s);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, 5s);
events.ScheduleEvent(EVENT_RAGE, 1s);
}
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 EVENT_FLAMESTRIKE:
DoCastAOE(SPELL_FLAMESTRIKE);
events.ScheduleEvent(EVENT_FLAMESTRIKE, 10s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 8s);
break;
case EVENT_CONFLAGRATION:
DoCastVictim(SPELL_CONFLAGRATION);
if (Unit* target = me->GetVictim())
{
_conflagrateTarget = me->GetVictim()->GetGUID();
_conflagrateThreat = me->GetThreatMgr().GetThreat(me->GetVictim());
me->GetThreatMgr().ModifyThreatByPercent(target, -100);
}
events.ScheduleEvent(EVENT_CONFLAGRATION, 18s, 25s);
events.ScheduleEvent(EVENT_CHECK_CONFLAGRATION_TARGET, 10s);
break;
case EVENT_THUNDERCLAP:
DoCastVictim(SPELL_THUNDERCLAP);
events.ScheduleEvent(EVENT_THUNDERCLAP, 20s);
break;
case EVENT_PIERCE_ARMOR:
DoCastVictim(SPELL_PIERCE_ARMOR);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, 40s);
break;
case EVENT_RAGE:
DoCastSelf(SPELL_RAGE);
events.ScheduleEvent(EVENT_RAGE, 35s);
break;
case EVENT_CHECK_CONFLAGRATION_TARGET:
if (Unit* target = ObjectAccessor::GetUnit(*me, _conflagrateTarget))
me->GetThreatMgr().AddThreat(target, _conflagrateThreat);
break;
}
}
DoMeleeAttackIfReady();
}
private:
float _conflagrateThreat;
ObjectGuid _conflagrateTarget;
}; };
void AddSC_boss_drakkisath() void AddSC_boss_drakkisath()
{ {
new boss_drakkisath(); RegisterBlackrockSpireCreatureAI(boss_drakkisath);
} }

View File

@@ -51,125 +51,114 @@ enum Events
EVENT_SUMMONED_2 = 6 EVENT_SUMMONED_2 = 6
}; };
class boss_gyth : public CreatureScript struct boss_gyth : public BossAI
{ {
public: boss_gyth(Creature* creature) : BossAI(creature, DATA_GYTH) { }
boss_gyth() : CreatureScript("boss_gyth") { }
struct boss_gythAI : public BossAI void Reset() override
{ {
boss_gythAI(Creature* creature) : BossAI(creature, DATA_GYTH) { } if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
void Reset() override
{ {
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) instance->SetBossState(DATA_GYTH, NOT_STARTED);
{ summons.DespawnAll();
instance->SetBossState(DATA_GYTH, NOT_STARTED); me->DespawnOrUnsummon();
summons.DespawnAll();
me->DespawnOrUnsummon();
}
SetInvincibility(true); // Don't let boss die before summoning Rend.
ScheduleHealthCheckEvent(25, [&] {
DoCastAOE(SPELL_SUMMON_REND, true);
me->RemoveAura(SPELL_REND_MOUNTS);
SetInvincibility(false);
});
} }
void JustEngagedWith(Unit* /*who*/) override SetInvincibility(true); // Don't let boss die before summoning Rend.
ScheduleHealthCheckEvent(25, [&] {
DoCastAOE(SPELL_SUMMON_REND, true);
me->RemoveAura(SPELL_REND_MOUNTS);
SetInvincibility(false);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_CORROSIVE_ACID, 8s, 16s);
events.ScheduleEvent(EVENT_FREEZE, 8s, 16s);
events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 16s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s, 18s);
}
void EnterEvadeMode(EvadeReason why) override
{
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
BossAI::EnterEvadeMode(why);
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
events.ScheduleEvent(EVENT_SUMMONED_1, 1s);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->AI()->AttackStart(me->SelectVictim());
}
// Prevent clearing summon list, otherwise Rend despawns if the drake is killed first.
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_GYTH, DONE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{ {
_JustEngagedWith();
events.ScheduleEvent(EVENT_CORROSIVE_ACID, 8s, 16s);
events.ScheduleEvent(EVENT_FREEZE, 8s, 16s);
events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 16s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s, 18s);
}
void EnterEvadeMode(EvadeReason why) override
{
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
BossAI::EnterEvadeMode(why);
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
events.ScheduleEvent(EVENT_SUMMONED_1, 1s);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->AI()->AttackStart(me->SelectVictim());
}
// Prevent clearing summon list, otherwise Rend despawns if the drake is killed first.
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_GYTH, DONE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUMMONED_1:
me->AddAura(SPELL_REND_MOUNTS, me);
if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 40.0f))
portcullis->UseDoorOrButton();
events.ScheduleEvent(EVENT_SUMMONED_2, 2s);
break;
case EVENT_SUMMONED_2:
me->GetMotionMaster()->MoveWaypoint(GYTH_PATH_1, false);
break;
default:
break;
}
}
return;
}
events.Update(diff); events.Update(diff);
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_CORROSIVE_ACID: case EVENT_SUMMONED_1:
DoCast(me, SPELL_CORROSIVE_ACID); me->AddAura(SPELL_REND_MOUNTS, me);
events.ScheduleEvent(EVENT_CORROSIVE_ACID, 10s, 16s); if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 40.0f))
portcullis->UseDoorOrButton();
events.ScheduleEvent(EVENT_SUMMONED_2, 2s);
break; break;
case EVENT_FREEZE: case EVENT_SUMMONED_2:
DoCast(me, SPELL_FREEZE); me->GetMotionMaster()->MoveWaypoint(GYTH_PATH_1, false);
events.ScheduleEvent(EVENT_FREEZE, 10s, 16s);
break;
case EVENT_FLAME_BREATH:
DoCast(me, SPELL_FLAMEBREATH);
events.ScheduleEvent(EVENT_FLAME_BREATH, 10s, 16s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCK_AWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s, 20s);
break; break;
default: default:
break; break;
} }
} }
DoMeleeAttackIfReady(); return;
} }
};
CreatureAI* GetAI(Creature* creature) const override events.Update(diff);
{
return GetBlackrockSpireAI<boss_gythAI>(creature); while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CORROSIVE_ACID:
DoCast(me, SPELL_CORROSIVE_ACID);
events.ScheduleEvent(EVENT_CORROSIVE_ACID, 10s, 16s);
break;
case EVENT_FREEZE:
DoCast(me, SPELL_FREEZE);
events.ScheduleEvent(EVENT_FREEZE, 10s, 16s);
break;
case EVENT_FLAME_BREATH:
DoCast(me, SPELL_FLAMEBREATH);
events.ScheduleEvent(EVENT_FLAME_BREATH, 10s, 16s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCK_AWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s, 20s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
} }
}; };
@@ -231,6 +220,6 @@ class spell_gyth_chromatic_protection : public AuraScript
void AddSC_boss_gyth() void AddSC_boss_gyth()
{ {
new boss_gyth(); RegisterBlackrockSpireCreatureAI(boss_gyth);
RegisterSpellScript(spell_gyth_chromatic_protection); RegisterSpellScript(spell_gyth_chromatic_protection);
} }

View File

@@ -38,70 +38,59 @@ enum Events
const Position SummonLocation = { -167.9561f, -411.7844f, 76.23057f, 1.53589f }; const Position SummonLocation = { -167.9561f, -411.7844f, 76.23057f, 1.53589f };
class boss_halycon : public CreatureScript struct boss_halycon : public BossAI
{ {
public: boss_halycon(Creature* creature) : BossAI(creature, DATA_HALYCON) { }
boss_halycon() : CreatureScript("boss_halycon") { }
struct boss_halyconAI : public BossAI void Reset() override
{ {
boss_halyconAI(Creature* creature) : BossAI(creature, DATA_HALYCON) { } _Reset();
}
void Reset() override void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_REND, 17s, 20s);
events.ScheduleEvent(EVENT_THRASH, 10s, 12s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
me->SummonCreature(NPC_GIZRUL_THE_SLAVENER, SummonLocation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
Talk(EMOTE_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_Reset(); switch (eventId)
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_REND, 17s, 20s);
events.ScheduleEvent(EVENT_THRASH, 10s, 12s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
me->SummonCreature(NPC_GIZRUL_THE_SLAVENER, SummonLocation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
Talk(EMOTE_DEATH);
}
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 EVENT_REND:
{ DoCastVictim(SPELL_REND);
case EVENT_REND: events.ScheduleEvent(EVENT_REND, 8s, 10s);
DoCastVictim(SPELL_REND); break;
events.ScheduleEvent(EVENT_REND, 8s, 10s); case EVENT_THRASH:
break; DoCast(me, SPELL_THRASH);
case EVENT_THRASH: break;
DoCast(me, SPELL_THRASH); default:
break; break;
default:
break;
}
} }
DoMeleeAttackIfReady();
} }
}; DoMeleeAttackIfReady();
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_halyconAI>(creature);
} }
}; };
void AddSC_boss_halycon() void AddSC_boss_halycon()
{ {
new boss_halycon(); RegisterBlackrockSpireCreatureAI(boss_halycon);
} }

View File

@@ -31,69 +31,58 @@ enum Events
EVENT_KNOCK_AWAY = 2 EVENT_KNOCK_AWAY = 2
}; };
class boss_highlord_omokk : public CreatureScript struct boss_highlord_omokk : public BossAI
{ {
public: boss_highlord_omokk(Creature* creature) : BossAI(creature, DATA_HIGHLORD_OMOKK) { }
boss_highlord_omokk() : CreatureScript("boss_highlord_omokk") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockSpireAI<boss_highlordomokkAI>(creature); _Reset();
} }
struct boss_highlordomokkAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_highlordomokkAI(Creature* creature) : BossAI(creature, DATA_HIGHLORD_OMOKK) { } _JustEngagedWith();
events.ScheduleEvent(EVENT_FRENZY, 20s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 18s);
}
void Reset() override void JustDied(Unit* /*killer*/) override
{
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_Reset(); switch (eventId)
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_FRENZY, 20s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 18s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
}
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 EVENT_FRENZY:
{ DoCastVictim(SPELL_FRENZY);
case EVENT_FRENZY: events.ScheduleEvent(EVENT_FRENZY, 60s);
DoCastVictim(SPELL_FRENZY); break;
events.ScheduleEvent(EVENT_FRENZY, 60s); case EVENT_KNOCK_AWAY:
break; DoCastVictim(SPELL_KNOCK_AWAY);
case EVENT_KNOCK_AWAY: events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s);
DoCastVictim(SPELL_KNOCK_AWAY); break;
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s); default:
break; break;
default:
break;
}
} }
DoMeleeAttackIfReady();
} }
}; DoMeleeAttackIfReady();
}
}; };
void AddSC_boss_highlordomokk() void AddSC_boss_highlordomokk()
{ {
new boss_highlord_omokk(); RegisterBlackrockSpireCreatureAI(boss_highlord_omokk);
} }

View File

@@ -49,145 +49,130 @@ enum EventPhase
EVENT_PHASE_FIGHT = 2 EVENT_PHASE_FIGHT = 2
}; };
class boss_lord_valthalak : public CreatureScript struct boss_lord_valthalak : public BossAI
{ {
public: boss_lord_valthalak(Creature* creature) : BossAI(creature, DATA_LORD_VALTHALAK) { }
boss_lord_valthalak() : CreatureScript("boss_lord_valthalak") { }
struct boss_lord_valthalakAI : public BossAI void Reset() override
{ {
boss_lord_valthalakAI(Creature* creature) : BossAI(creature, DATA_LORD_VALTHALAK) { } BossAI::Reset();
void Reset() override me->SetReactState(REACT_AGGRESSIVE);
{ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
BossAI::Reset();
me->SetReactState(REACT_AGGRESSIVE); _frenzy40 = false;
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); _frenzy15 = false;
frenzy40 = false;
frenzy15 = false;
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
StartTalking(TALK_SUMMON, 8s);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(TALK_AGGRO);
events.SetPhase(EVENT_PHASE_FIGHT);
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 6s, 8s, 0, EVENT_PHASE_FIGHT);
events.ScheduleEvent(EVENT_SHADOW_WRATH, 9s, 18s, 0, EVENT_PHASE_FIGHT);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
instance->SetData(DATA_LORD_VALTHALAK, DONE);
}
void StartTalking(uint32 talkGroupId, Milliseconds timer)
{
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->AttackStop();
Talk(talkGroupId);
events.SetPhase(EVENT_PHASE_TALK);
events.ScheduleEvent(EVENT_FIGHT, timer, 0, EVENT_PHASE_TALK);
}
void StartFighting()
{
events.SetPhase(EVENT_PHASE_FIGHT);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
DoZoneInCombat();
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!frenzy40 && me->HealthBelowPctDamaged(40, damage))
{
frenzy40 = true;
DoCast(me, SPELL_FRENZY);
events.CancelEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN);
StartTalking(TALK_40_HP, 5s);
}
if (!frenzy15 && me->HealthBelowPctDamaged(15, damage))
{
frenzy15 = true;
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 12s, 19s, 0, EVENT_PHASE_FIGHT);
StartTalking(TALK_15_HP, 5s);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && !events.IsInPhase(EVENT_PHASE_TALK))
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FIGHT:
StartFighting();
break;
case EVENT_SUMMON_SPECTRAL_ASSASSIN:
DoCast(me, SPELL_SUMMON_SPECTRAL_ASSASSIN);
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 30s, 35s, 0, EVENT_PHASE_FIGHT);
break;
case EVENT_SHADOW_BOLT_VOLLEY:
DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 4s, 6s, 0, EVENT_PHASE_FIGHT);
break;
case EVENT_SHADOW_WRATH:
DoCastVictim(SPELL_SHADOW_WRATH);
events.ScheduleEvent(EVENT_SHADOW_WRATH, 19s, 24s, 0, EVENT_PHASE_FIGHT);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool frenzy40;
bool frenzy15;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_lord_valthalakAI>(creature);
} }
void IsSummonedBy(WorldObject* /*summoner*/) override
{
StartTalking(TALK_SUMMON, 8s);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(TALK_AGGRO);
events.SetPhase(EVENT_PHASE_FIGHT);
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 6s, 8s, 0, EVENT_PHASE_FIGHT);
events.ScheduleEvent(EVENT_SHADOW_WRATH, 9s, 18s, 0, EVENT_PHASE_FIGHT);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
instance->SetData(DATA_LORD_VALTHALAK, DONE);
}
void StartTalking(uint32 talkGroupId, Milliseconds timer)
{
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->AttackStop();
Talk(talkGroupId);
events.SetPhase(EVENT_PHASE_TALK);
events.ScheduleEvent(EVENT_FIGHT, timer, 0, EVENT_PHASE_TALK);
}
void StartFighting()
{
events.SetPhase(EVENT_PHASE_FIGHT);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
DoZoneInCombat();
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_frenzy40 && me->HealthBelowPctDamaged(40, damage))
{
_frenzy40 = true;
DoCast(me, SPELL_FRENZY);
events.CancelEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN);
StartTalking(TALK_40_HP, 5s);
}
if (!_frenzy15 && me->HealthBelowPctDamaged(15, damage))
{
_frenzy15 = true;
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 12s, 19s, 0, EVENT_PHASE_FIGHT);
StartTalking(TALK_15_HP, 5s);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && !events.IsInPhase(EVENT_PHASE_TALK))
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FIGHT:
StartFighting();
break;
case EVENT_SUMMON_SPECTRAL_ASSASSIN:
DoCast(me, SPELL_SUMMON_SPECTRAL_ASSASSIN);
events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 30s, 35s, 0, EVENT_PHASE_FIGHT);
break;
case EVENT_SHADOW_BOLT_VOLLEY:
DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 4s, 6s, 0, EVENT_PHASE_FIGHT);
break;
case EVENT_SHADOW_WRATH:
DoCastVictim(SPELL_SHADOW_WRATH);
events.ScheduleEvent(EVENT_SHADOW_WRATH, 19s, 24s, 0, EVENT_PHASE_FIGHT);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _frenzy40;
bool _frenzy15;
}; };
void AddSC_boss_lord_valthalak() void AddSC_boss_lord_valthalak()
{ {
new boss_lord_valthalak(); RegisterBlackrockSpireCreatureAI(boss_lord_valthalak);
} }

View File

@@ -96,13 +96,9 @@ struct boss_mor_grayhoof : public BossAI
case PHASE_HUMAN: case PHASE_HUMAN:
spell = Acore::Containers::SelectRandomContainerElement(humanSpells); spell = Acore::Containers::SelectRandomContainerElement(humanSpells);
if (spell == SPELL_REJUVENATION || spell == SPELL_HEALING_TOUCH) if (spell == SPELL_REJUVENATION || spell == SPELL_HEALING_TOUCH)
{
DoCastSelf(spell); DoCastSelf(spell);
}
else else
{
DoCastAOE(spell); DoCastAOE(spell);
}
break; break;
case PHASE_BEAR: case PHASE_BEAR:
spell = Acore::Containers::SelectRandomContainerElement(bearSpells); spell = Acore::Containers::SelectRandomContainerElement(bearSpells);
@@ -155,9 +151,7 @@ struct boss_mor_grayhoof : public BossAI
{ {
CastRandomSpell(PHASE_BEAR); CastRandomSpell(PHASE_BEAR);
if (context.GetRepeatCounter() <= 3) if (context.GetRepeatCounter() <= 3)
{
context.Repeat(); context.Repeat();
}
}); });
} }
else if (_phase == PHASE_BEAR && me->HealthBelowPct(50.f)) else if (_phase == PHASE_BEAR && me->HealthBelowPct(50.f))
@@ -170,9 +164,7 @@ struct boss_mor_grayhoof : public BossAI
{ {
CastRandomSpell(PHASE_CAT); CastRandomSpell(PHASE_CAT);
if (context.GetRepeatCounter() <= 3) if (context.GetRepeatCounter() <= 3)
{
context.Repeat(); context.Repeat();
}
}); });
} }
else if (_phase == PHASE_CAT && me->HealthBelowPct(25.f)) else if (_phase == PHASE_CAT && me->HealthBelowPct(25.f))
@@ -203,9 +195,7 @@ struct boss_mor_grayhoof : public BossAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
_scheduler.Update(diff, [this] _scheduler.Update(diff, [this]
{ {

View File

@@ -46,93 +46,83 @@ constexpr uint32 CALL_HELP = 0;
const Position SummonLocation1 = {-49.43f, -455.82f, 77.82f, 4.61f}; const Position SummonLocation1 = {-49.43f, -455.82f, 77.82f, 4.61f};
const Position SummonLocation2 = {-58.48f, -456.29f, 77.82f, 4.613f}; const Position SummonLocation2 = {-58.48f, -456.29f, 77.82f, 4.613f};
class boss_overlord_wyrmthalak : public CreatureScript struct boss_overlord_wyrmthalak : public BossAI
{ {
public: boss_overlord_wyrmthalak(Creature* creature) : BossAI(creature, DATA_OVERLORD_WYRMTHALAK) { }
boss_overlord_wyrmthalak() : CreatureScript("boss_overlord_wyrmthalak") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockSpireAI<boss_overlordwyrmthalakAI>(creature); _Reset();
_summoned = false;
} }
struct boss_overlordwyrmthalakAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_overlordwyrmthalakAI(Creature* creature) : BossAI(creature, DATA_OVERLORD_WYRMTHALAK) { } _JustEngagedWith();
events.ScheduleEvent(EVENT_BLAST_WAVE, 20s);
events.ScheduleEvent(EVENT_SHOUT, 2s);
events.ScheduleEvent(EVENT_CLEAVE, 6s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s);
}
bool Summoned; void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_OVERLORD_WYRMTHALAK, DONE);
}
void Reset() override void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (!_summoned && HealthBelowPct(51))
{ {
_Reset(); Talk(CALL_HELP);
Summoned = false; if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_BLAST_WAVE, 20s);
events.ScheduleEvent(EVENT_SHOUT, 2s);
events.ScheduleEvent(EVENT_CLEAVE, 6s);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s);
}
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_OVERLORD_WYRMTHALAK, DONE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (!Summoned && HealthBelowPct(51))
{ {
Talk(CALL_HELP); if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) warlord->AI()->AttackStart(target);
{ if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS)) berserker->AI()->AttackStart(target);
warlord->AI()->AttackStart(target); _summoned = true;
if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
berserker->AI()->AttackStart(target);
Summoned = true;
}
} }
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BLAST_WAVE:
DoCastVictim(SPELL_BLASTWAVE);
events.ScheduleEvent(EVENT_BLAST_WAVE, 20s);
break;
case EVENT_SHOUT:
DoCastVictim(SPELL_SHOUT);
events.ScheduleEvent(EVENT_SHOUT, 10s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 7s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCKAWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s);
break;
}
}
DoMeleeAttackIfReady();
} }
};
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BLAST_WAVE:
DoCastVictim(SPELL_BLASTWAVE);
events.ScheduleEvent(EVENT_BLAST_WAVE, 20s);
break;
case EVENT_SHOUT:
DoCastVictim(SPELL_SHOUT);
events.ScheduleEvent(EVENT_SHOUT, 10s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 7s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCKAWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s);
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _summoned;
}; };
void AddSC_boss_overlordwyrmthalak() void AddSC_boss_overlordwyrmthalak()
{ {
new boss_overlord_wyrmthalak(); RegisterBlackrockSpireCreatureAI(boss_overlord_wyrmthalak);
} }

View File

@@ -68,241 +68,226 @@ enum Events
EVENT_ENTER_COMBAT = 10 EVENT_ENTER_COMBAT = 10
}; };
class boss_pyroguard_emberseer : public CreatureScript struct boss_pyroguard_emberseer : public BossAI
{ {
public: boss_pyroguard_emberseer(Creature* creature) : BossAI(creature, DATA_PYROGAURD_EMBERSEER) { }
boss_pyroguard_emberseer() : CreatureScript("boss_pyroguard_emberseer") { }
struct boss_pyroguard_emberseerAI : public BossAI void Reset() override
{ {
boss_pyroguard_emberseerAI(Creature* creature) : BossAI(creature, DATA_PYROGAURD_EMBERSEER) { } me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(true);
events.Reset();
// Apply auras on spawn and reset
// DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); // Need to find this in old DBC if possible
me->RemoveAura(SPELL_EMBERSEER_FULL_STRENGTH);
me->RemoveAura(SPELL_EMBERSEER_GROWING);
me->RemoveAura(SPELL_EMBERSEER_GROWING_TRIGGER);
events.ScheduleEvent(EVENT_RESPAWN, 5s);
// Hack for missing trigger spell
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
void Reset() override // Open doors on reset
if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS)
OpenDoors(false); // Opens 2 entrance doors
}
void SetData(uint32 /*type*/, uint32 data) override
{
switch (data)
{ {
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); case 1:
me->SetImmuneToPC(true); events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
events.Reset(); instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
// Apply auras on spawn and reset break;
// DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); // Need to find this in old DBC if possible case 2:
me->RemoveAura(SPELL_EMBERSEER_FULL_STRENGTH); // Close these two doors on Blackhand Incarcerators aggro
me->RemoveAura(SPELL_EMBERSEER_GROWING); if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN)))
me->RemoveAura(SPELL_EMBERSEER_GROWING_TRIGGER); if (door1->GetGoState() == GO_STATE_ACTIVE)
events.ScheduleEvent(EVENT_RESPAWN, 5s); door1->SetGoState(GO_STATE_READY);
// Hack for missing trigger spell if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS)))
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); if (door2->GetGoState() == GO_STATE_ACTIVE)
door2->SetGoState(GO_STATE_READY);
// Open doors on reset break;
if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS) case 3:
OpenDoors(false); // Opens 2 entrance doors Reset();
break;
default:
break;
} }
}
void SetData(uint32 /*type*/, uint32 data) override void JustEngagedWith(Unit* /*who*/) override
{
// ### TODO Check combat timing ###
events.ScheduleEvent(EVENT_FIRENOVA, 6s);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 3s);
events.ScheduleEvent(EVENT_PYROBLAST, 14s);
}
void JustDied(Unit* /*killer*/) override
{
// Activate all the runes
UpdateRunes(GO_STATE_READY);
// Opens all 3 doors
OpenDoors(true);
// Complete encounter
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, DONE);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_ENCAGE_EMBERSEER)
if (!me->GetAuraCount(SPELL_ENCAGED_EMBERSEER))
me->CastSpell(me, SPELL_ENCAGED_EMBERSEER);
if (spell->Id == SPELL_EMBERSEER_GROWING_TRIGGER)
{ {
switch (data) if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 10)
Talk(EMOTE_TEN_STACK);
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20)
{ {
case 1: events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS); // Schedule out the pre-combat scene
break; events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s);
case 2: events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s);
// Close these two doors on Blackhand Incarcerators aggro events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s);
if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN)))
if (door1->GetGoState() == GO_STATE_ACTIVE)
door1->SetGoState(GO_STATE_READY);
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS)))
if (door2->GetGoState() == GO_STATE_ACTIVE)
door2->SetGoState(GO_STATE_READY);
break;
case 3:
Reset();
break;
default:
break;
} }
} }
}
void JustEngagedWith(Unit* /*who*/) override void OpenDoors(bool Boss_Killed)
{
// These two doors reopen on reset or boss kill
if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN)))
door1->SetGoState(GO_STATE_ACTIVE);
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS)))
door2->SetGoState(GO_STATE_ACTIVE);
// This door opens on boss kill
if (Boss_Killed)
if (GameObject* door3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_OUT)))
door3->SetGoState(GO_STATE_ACTIVE);
}
void UpdateRunes(GOState state)
{
// update all runes
if (GameObject* rune1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_1)))
rune1->SetGoState(state);
if (GameObject* rune2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_2)))
rune2->SetGoState(state);
if (GameObject* rune3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_3)))
rune3->SetGoState(state);
if (GameObject* rune4 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_4)))
rune4->SetGoState(state);
if (GameObject* rune5 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_5)))
rune5->SetGoState(state);
if (GameObject* rune6 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_6)))
rune6->SetGoState(state);
if (GameObject* rune7 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_7)))
rune7->SetGoState(state);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{ {
// ### TODO Check combat timing ###
events.ScheduleEvent(EVENT_FIRENOVA, 6s);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 3s);
events.ScheduleEvent(EVENT_PYROBLAST, 14s);
}
void JustDied(Unit* /*killer*/) override
{
// Activate all the runes
UpdateRunes(GO_STATE_READY);
// Opens all 3 doors
OpenDoors(true);
// Complete encounter
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, DONE);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_ENCAGE_EMBERSEER)
{
if (!me->GetAuraCount(SPELL_ENCAGED_EMBERSEER))
me->CastSpell(me, SPELL_ENCAGED_EMBERSEER);
}
if (spell->Id == SPELL_EMBERSEER_GROWING_TRIGGER)
{
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 10)
Talk(EMOTE_TEN_STACK);
if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20)
{
events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start
// Schedule out the pre-combat scene
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s);
events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s);
events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s);
}
}
}
void OpenDoors(bool Boss_Killed)
{
// These two doors reopen on reset or boss kill
if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN)))
door1->SetGoState(GO_STATE_ACTIVE);
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS)))
door2->SetGoState(GO_STATE_ACTIVE);
// This door opens on boss kill
if (Boss_Killed)
if (GameObject* door3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_OUT)))
door3->SetGoState(GO_STATE_ACTIVE);
}
void UpdateRunes(GOState state)
{
// update all runes
if (GameObject* rune1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_1)))
rune1->SetGoState(state);
if (GameObject* rune2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_2)))
rune2->SetGoState(state);
if (GameObject* rune3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_3)))
rune3->SetGoState(state);
if (GameObject* rune4 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_4)))
rune4->SetGoState(state);
if (GameObject* rune5 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_5)))
rune5->SetGoState(state);
if (GameObject* rune6 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_6)))
rune6->SetGoState(state);
if (GameObject* rune7 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_7)))
rune7->SetGoState(state);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RESPAWN:
{
// Respawn all Blackhand Incarcerators
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
if (Creature* creature = *itr)
{
if (!creature->IsAlive())
creature->Respawn();
creature->AI()->SetData(1, 2);
}
me->AddAura(SPELL_ENCAGED_EMBERSEER, me);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, NOT_STARTED);
break;
}
case EVENT_PRE_FIGHT_1:
{
// Set data on all Blackhand Incarcerators
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
if (Creature* creature = *itr)
creature->AI()->SetData(1, 1);
}
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s);
break;
}
case EVENT_PRE_FIGHT_2:
me->CastSpell(me, SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_GROWING);
Talk(EMOTE_ONE_STACK);
break;
case EVENT_FIRE_SHIELD:
// #### Spell isn't doing any damage ??? ####
DoCast(me, SPELL_FIRE_SHIELD);
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
break;
case EVENT_PRE_ENTER_COMBAT_1:
me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
me->RemoveAura(SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
Talk(EMOTE_FREE_OF_BONDS);
break;
case EVENT_PRE_ENTER_COMBAT_2:
Talk(YELL_FREE_OF_BONDS);
break;
case EVENT_ENTER_COMBAT:
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
DoZoneInCombat();
// re-enable fire shield
events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s);
break;
default:
break;
}
}
return;
}
events.Update(diff); events.Update(diff);
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_RESPAWN:
{
// Respawn all Blackhand Incarcerators
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
if (Creature* creature = *itr)
{
if (!creature->IsAlive())
creature->Respawn();
creature->AI()->SetData(1, 2);
}
me->AddAura(SPELL_ENCAGED_EMBERSEER, me);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, NOT_STARTED);
break;
}
case EVENT_PRE_FIGHT_1:
{
// Set data on all Blackhand Incarcerators
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
if (Creature* creature = *itr)
creature->AI()->SetData(1, 1);
events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s);
break;
}
case EVENT_PRE_FIGHT_2:
me->CastSpell(me, SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_GROWING);
Talk(EMOTE_ONE_STACK);
break;
case EVENT_FIRE_SHIELD: case EVENT_FIRE_SHIELD:
// #### Spell isn't doing any damage ??? ####
DoCast(me, SPELL_FIRE_SHIELD); DoCast(me, SPELL_FIRE_SHIELD);
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
break; break;
case EVENT_FIRENOVA: case EVENT_PRE_ENTER_COMBAT_1:
DoCast(me, SPELL_FIRENOVA); me->RemoveAura(SPELL_ENCAGED_EMBERSEER);
events.ScheduleEvent(EVENT_FIRENOVA, 6s); me->RemoveAura(SPELL_FREEZE_ANIM);
me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH);
Talk(EMOTE_FREE_OF_BONDS);
break; break;
case EVENT_FLAMEBUFFET: case EVENT_PRE_ENTER_COMBAT_2:
DoCast(me, SPELL_FLAMEBUFFET); Talk(YELL_FREE_OF_BONDS);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 14s);
break; break;
case EVENT_PYROBLAST: case EVENT_ENTER_COMBAT:
DoCastRandomTarget(SPELL_PYROBLAST, 0, 100.0f); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
events.ScheduleEvent(EVENT_PYROBLAST, 15s); me->SetImmuneToPC(false);
DoZoneInCombat();
// re-enable fire shield
events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s);
break; break;
default: default:
break; break;
} }
} }
DoMeleeAttackIfReady(); return;
} }
};
CreatureAI* GetAI(Creature* creature) const override events.Update(diff);
{
return GetBlackrockSpireAI<boss_pyroguard_emberseerAI>(creature); while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FIRE_SHIELD:
DoCast(me, SPELL_FIRE_SHIELD);
events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s);
break;
case EVENT_FIRENOVA:
DoCast(me, SPELL_FIRENOVA);
events.ScheduleEvent(EVENT_FIRENOVA, 6s);
break;
case EVENT_FLAMEBUFFET:
DoCast(me, SPELL_FLAMEBUFFET);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 14s);
break;
case EVENT_PYROBLAST:
DoCastRandomTarget(SPELL_PYROBLAST, 0, 100.0f);
events.ScheduleEvent(EVENT_PYROBLAST, 15s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
} }
}; };
@@ -321,127 +306,114 @@ enum IncarceratorData
EMOTE_FLEE = 0 EMOTE_FLEE = 0
}; };
class npc_blackhand_incarcerator : public CreatureScript struct npc_blackhand_incarcerator : public ScriptedAI
{ {
public: npc_blackhand_incarcerator(Creature* creature) : ScriptedAI(creature)
npc_blackhand_incarcerator() : CreatureScript("npc_blackhand_incarcerator") { }
struct npc_blackhand_incarceratorAI : public ScriptedAI
{ {
npc_blackhand_incarceratorAI(Creature* creature) : ScriptedAI(creature) _fleedForAssistance = false;
}
void Reset() override
{
me->SetImmuneToAll(true);
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
Emberseer->AI()->SetData(1, 3);
_fleedForAssistance = false;
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage))
{ {
_fleedForAssistance = false; _fleedForAssistance = true;
me->DoFleeToGetAssistance();
Talk(EMOTE_FLEE);
}
}
void SetData(uint32 data, uint32 value) override
{
if (data == 1 && value == 1)
{
me->SetImmuneToAll(false);
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
DoZoneInCombat();
_events.CancelEvent(EVENT_ENCAGED_EMBERSEER);
} }
void Reset() override if (data == 1 && value == 2)
_events.ScheduleEvent(EVENT_ENCAGED_EMBERSEER, 1s);
}
void JustEngagedWith(Unit* /*who*/) override
{
// Used to close doors
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
Emberseer->AI()->SetData(1, 2);
// Had to do this because CallForHelp will ignore any npcs without LOS
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 60.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
if (Creature* creature = *itr)
creature->SetInCombatWithZone(); // AI()->AttackStart(me->GetVictim());
_events.ScheduleEvent(EVENT_STRIKE, 8s, 16s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{ {
me->SetImmuneToAll(true);
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
Emberseer->AI()->SetData(1, 3);
_fleedForAssistance = false;
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage))
{
_fleedForAssistance = true;
me->DoFleeToGetAssistance();
Talk(EMOTE_FLEE);
}
}
void SetData(uint32 data, uint32 value) override
{
if (data == 1 && value == 1)
{
me->SetImmuneToAll(false);
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
DoZoneInCombat();
_events.CancelEvent(EVENT_ENCAGED_EMBERSEER);
}
if (data == 1 && value == 2)
_events.ScheduleEvent(EVENT_ENCAGED_EMBERSEER, 1s);
}
void JustEngagedWith(Unit* /*who*/) override
{
// Used to close doors
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
Emberseer->AI()->SetData(1, 2);
// Had to do this because CallForHelp will ignore any npcs without LOS
std::list<Creature*> creatureList;
GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 60.0f);
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
if (Creature* creature = *itr)
creature->SetInCombatWithZone(); // AI()->AttackStart(me->GetVictim());
}
_events.ScheduleEvent(EVENT_STRIKE, 8s, 16s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ENCAGED_EMBERSEER:
{
if (me->GetPositionX() == me->GetHomePosition().GetPositionX())
if (!me->HasAura(SPELL_ENCAGE_EMBERSEER))
if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
DoCast(Emberseer, SPELL_ENCAGE_EMBERSEER);
break;
}
}
}
return;
}
_events.Update(diff); _events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent()) while (uint32 eventId = _events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_STRIKE: case EVENT_ENCAGED_EMBERSEER:
DoCastVictim(SPELL_STRIKE, true); {
_events.ScheduleEvent(EVENT_STRIKE, 14s, 23s); if (me->GetPositionX() == me->GetHomePosition().GetPositionX())
break; if (!me->HasAura(SPELL_ENCAGE_EMBERSEER))
case EVENT_ENCAGE: if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true))
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), EVENT_ENCAGE, true); DoCast(Emberseer, SPELL_ENCAGE_EMBERSEER);
_events.ScheduleEvent(EVENT_ENCAGE, 6s, 12s); break;
break; }
default:
break;
} }
} }
return;
DoMeleeAttackIfReady();
} }
private: _events.Update(diff);
EventMap _events;
bool _fleedForAssistance;
};
CreatureAI* GetAI(Creature* creature) const override while (uint32 eventId = _events.ExecuteEvent())
{ {
return GetBlackrockSpireAI<npc_blackhand_incarceratorAI>(creature); switch (eventId)
{
case EVENT_STRIKE:
DoCastVictim(SPELL_STRIKE, true);
_events.ScheduleEvent(EVENT_STRIKE, 14s, 23s);
break;
case EVENT_ENCAGE:
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), EVENT_ENCAGE, true);
_events.ScheduleEvent(EVENT_ENCAGE, 6s, 12s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
} }
private:
EventMap _events;
bool _fleedForAssistance;
}; };
void AddSC_boss_pyroguard_emberseer() void AddSC_boss_pyroguard_emberseer()
{ {
new boss_pyroguard_emberseer(); RegisterBlackrockSpireCreatureAI(boss_pyroguard_emberseer);
new npc_blackhand_incarcerator(); RegisterBlackrockSpireCreatureAI(npc_blackhand_incarcerator);
} }

View File

@@ -87,16 +87,12 @@ struct boss_quartermaster_zigris : public BossAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
@@ -135,9 +131,7 @@ struct boss_quartermaster_zigris : public BossAI
} }
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();

View File

@@ -99,346 +99,327 @@ enum Events
EVENT_MORTAL_STRIKE = 32, EVENT_MORTAL_STRIKE = 32,
}; };
class boss_rend_blackhand : public CreatureScript struct boss_rend_blackhand : public BossAI
{ {
public: boss_rend_blackhand(Creature* creature) : BossAI(creature, DATA_WARCHIEF_REND_BLACKHAND) { }
boss_rend_blackhand() : CreatureScript("boss_rend_blackhand") { }
struct boss_rend_blackhandAI : public BossAI void Reset() override
{ {
boss_rend_blackhandAI(Creature* creature) : BossAI(creature, DATA_WARCHIEF_REND_BLACKHAND) { } _Reset();
void Reset() override if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
{ {
_Reset(); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION);
me->SetImmuneToAll(false);
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) return;
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION);
me->SetImmuneToAll(false);
return;
}
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION);
me->SetImmuneToAll(true);
gythEvent = false;
victorGUID.Clear();
waveDoorGUID.Clear();
_currentWave = 0;
summons.DespawnAll();
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f, true))
victor->Respawn(true);
if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
exitDoor->SetGoState(GO_STATE_ACTIVE);
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, NOT_STARTED);
} }
void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION);
me->SetImmuneToAll(true);
_gythEvent = false;
_victorGUID.Clear();
_waveDoorGUID.Clear();
_currentWave = 0;
summons.DespawnAll();
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f, true))
victor->Respawn(true);
if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
exitDoor->SetGoState(GO_STATE_ACTIVE);
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, NOT_STARTED);
}
void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override
{
if (!summons.IsAnyCreatureAlive())
events.ScheduleEvent(EVENT_WAVES_TEXT_1 + _currentWave, 10s);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() == NPC_GYTH)
{ {
if (!summons.IsAnyCreatureAlive())
{
events.ScheduleEvent(EVENT_WAVES_TEXT_1 + _currentWave, 10s);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() == NPC_GYTH)
{
me->DespawnOrUnsummon();
return;
}
summon->AI()->DoZoneInCombat(nullptr, 100.0f);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 15s);
events.ScheduleEvent(EVENT_CLEAVE, 15s, 17s);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 17s, 19s);
}
void EnterEvadeMode(EvadeReason why) override
{
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
instance->SetBossState(DATA_GYTH, FAIL);
BossAI::EnterEvadeMode(why);
me->DespawnOrUnsummon(); me->DespawnOrUnsummon();
return;
} }
void IsSummonedBy(WorldObject* /*summoner*/) override summon->AI()->DoZoneInCombat(nullptr, 100.0f);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 15s);
events.ScheduleEvent(EVENT_CLEAVE, 15s, 17s);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 17s, 19s);
}
void EnterEvadeMode(EvadeReason why) override
{
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
instance->SetBossState(DATA_GYTH, FAIL);
BossAI::EnterEvadeMode(why);
me->DespawnOrUnsummon();
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
Talk(EMOTE_BLACKHAND_DISMOUNT);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true))
victor->AI()->SetData(1, 2);
if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
exitDoor->SetGoState(GO_STATE_ACTIVE);
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, DONE);
}
void SummonedCreatureDespawn(Creature* creature) override
{
if (creature->IsAlive() && !summons.IsAnyCreatureInCombat())
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
BossAI::SummonedCreatureDespawn(creature);
}
void SetData(uint32 type, uint32 data) override
{
if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM)
{ {
Talk(EMOTE_BLACKHAND_DISMOUNT); if (!_gythEvent)
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true))
victor->AI()->SetData(1, 2);
if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
exitDoor->SetGoState(GO_STATE_ACTIVE);
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, DONE);
}
void SummonedCreatureDespawn(Creature* creature) override
{
if (creature->IsAlive() && !summons.IsAnyCreatureInCombat())
{ {
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); _gythEvent = true;
}
BossAI::SummonedCreatureDespawn(creature); if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f))
}
void SetData(uint32 type, uint32 data) override
{
if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM)
{
if (!gythEvent)
{ {
gythEvent = true; if (!victor->IsAlive())
victor->Respawn(true);
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f)) _victorGUID = victor->GetGUID();
{
if (!victor->IsAlive())
{
victor->Respawn(true);
}
victorGUID = victor->GetGUID();
}
if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 50.0f))
waveDoorGUID = portcullis->GetGUID();
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
events.ScheduleEvent(EVENT_START_1, 1s);
} }
if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 50.0f))
_waveDoorGUID = portcullis->GetGUID();
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
events.ScheduleEvent(EVENT_START_1, 1s);
} }
} }
}
void MovementInform(uint32 type, uint32 id) override void MovementInform(uint32 type, uint32 id) override
{
if (type == WAYPOINT_MOTION_TYPE)
{ {
if (type == WAYPOINT_MOTION_TYPE) switch (id)
{ {
switch (id) case 6:
{ events.ScheduleEvent(EVENT_TELEPORT_1, 2s);
case 6: break;
events.ScheduleEvent(EVENT_TELEPORT_1, 2s);
break;
}
} }
} }
}
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{
if (_gythEvent)
{ {
if (gythEvent)
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_START_1:
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, IN_PROGRESS);
instance->SetData(DATA_VAELASTRASZ, NOT_STARTED);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_0);
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
door2->SetGoState(GO_STATE_READY);
events.ScheduleEvent(EVENT_START_2, 4s);
break;
case EVENT_START_2:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
events.ScheduleEvent(EVENT_START_3, 4s);
break;
case EVENT_START_3:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_1);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 2s);
events.ScheduleEvent(EVENT_TURN_TO_REND, 4s);
break;
case EVENT_TURN_TO_REND:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
{
victor->SetFacingToObject(me);
victor->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
}
break;
case EVENT_TURN_TO_PLAYER:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
if (Unit* player = victor->SelectNearestPlayer(60.0f))
victor->SetFacingToObject(player);
break;
case EVENT_TURN_TO_FACING_1:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->SetFacingTo(1.518436f);
break;
case EVENT_TURN_TO_FACING_2:
me->SetFacingTo(1.658063f);
break;
case EVENT_TURN_TO_FACING_3:
me->SetFacingTo(1.500983f);
break;
case EVENT_WAVES_EMOTE_1:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION);
break;
case EVENT_WAVES_EMOTE_2:
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
break;
case EVENT_WAVES_TEXT_1:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_2);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_WAVES_EMOTE_1, 5s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_2:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_3);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_3:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_4);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_4:
Talk(SAY_BLACKHAND_1);
events.ScheduleEvent(EVENT_WAVES_EMOTE_2, 4s);
events.ScheduleEvent(EVENT_TURN_TO_FACING_3, 8s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_5:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_5);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_COMPLETE_TEXT_1:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_6);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_2, 13s);
break;
case EVENT_WAVES_COMPLETE_TEXT_2:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_7);
Talk(SAY_BLACKHAND_2);
events.ScheduleEvent(EVENT_PATH_REND, 1s);
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_3, 4s);
break;
case EVENT_WAVES_COMPLETE_TEXT_3:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_8);
events.ScheduleEvent(EVENT_PATH_NEFARIUS, 1s);
events.ScheduleEvent(EVENT_PATH_REND, 1s);
break;
case EVENT_PATH_NEFARIUS:
if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID))
victor->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_1, true);
break;
case EVENT_PATH_REND:
me->GetMotionMaster()->MoveWaypoint(REND_PATH_1, false);
break;
case EVENT_TELEPORT_1:
me->NearTeleportTo(194.2993f, -474.0814f, 121.4505f, -0.01225555f);
events.ScheduleEvent(EVENT_TELEPORT_2, 13s);
break;
case EVENT_TELEPORT_2:
me->NearTeleportTo(216.485f, -434.93f, 110.888f, -0.01225555f);
me->SummonCreature(NPC_GYTH, 211.762f, -397.5885f, 111.1817f, 4.747295f);
break;
case EVENT_SPAWN_WAVE:
SummonWave();
break;
default:
break;
}
}
}
if (!UpdateVictim())
return;
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_WHIRLWIND: case EVENT_START_1:
DoCast(SPELL_WHIRLWIND); instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, IN_PROGRESS);
events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 18s); instance->SetData(DATA_VAELASTRASZ, NOT_STARTED);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_0);
if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR)))
door2->SetGoState(GO_STATE_READY);
events.ScheduleEvent(EVENT_START_2, 4s);
break; break;
case EVENT_CLEAVE: case EVENT_START_2:
DoCastVictim(SPELL_CLEAVE); events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
events.ScheduleEvent(EVENT_CLEAVE, 10s, 14s); if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
events.ScheduleEvent(EVENT_START_3, 4s);
break; break;
case EVENT_MORTAL_STRIKE: case EVENT_START_3:
DoCastVictim(SPELL_MORTAL_STRIKE); if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 14s, 18s); victor->AI()->Talk(SAY_NEFARIUS_1);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 2s);
events.ScheduleEvent(EVENT_TURN_TO_REND, 4s);
break;
case EVENT_TURN_TO_REND:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
{
victor->SetFacingToObject(me);
victor->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
}
break;
case EVENT_TURN_TO_PLAYER:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
if (Unit* player = victor->SelectNearestPlayer(60.0f))
victor->SetFacingToObject(player);
break;
case EVENT_TURN_TO_FACING_1:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->SetFacingTo(1.518436f);
break;
case EVENT_TURN_TO_FACING_2:
me->SetFacingTo(1.658063f);
break;
case EVENT_TURN_TO_FACING_3:
me->SetFacingTo(1.500983f);
break;
case EVENT_WAVES_EMOTE_1:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION);
break;
case EVENT_WAVES_EMOTE_2:
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
break;
case EVENT_WAVES_TEXT_1:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_2);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_WAVES_EMOTE_1, 5s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_2:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_3);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_3:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_4);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_4:
Talk(SAY_BLACKHAND_1);
events.ScheduleEvent(EVENT_WAVES_EMOTE_2, 4s);
events.ScheduleEvent(EVENT_TURN_TO_FACING_3, 8s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_TEXT_5:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_5);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s);
break;
case EVENT_WAVES_COMPLETE_TEXT_1:
events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms);
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_6);
events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s);
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_2, 13s);
break;
case EVENT_WAVES_COMPLETE_TEXT_2:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_7);
Talk(SAY_BLACKHAND_2);
events.ScheduleEvent(EVENT_PATH_REND, 1s);
events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_3, 4s);
break;
case EVENT_WAVES_COMPLETE_TEXT_3:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->AI()->Talk(SAY_NEFARIUS_8);
events.ScheduleEvent(EVENT_PATH_NEFARIUS, 1s);
events.ScheduleEvent(EVENT_PATH_REND, 1s);
break;
case EVENT_PATH_NEFARIUS:
if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID))
victor->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_1, true);
break;
case EVENT_PATH_REND:
me->GetMotionMaster()->MoveWaypoint(REND_PATH_1, false);
break;
case EVENT_TELEPORT_1:
me->NearTeleportTo(194.2993f, -474.0814f, 121.4505f, -0.01225555f);
events.ScheduleEvent(EVENT_TELEPORT_2, 13s);
break;
case EVENT_TELEPORT_2:
me->NearTeleportTo(216.485f, -434.93f, 110.888f, -0.01225555f);
me->SummonCreature(NPC_GYTH, 211.762f, -397.5885f, 111.1817f, 4.747295f);
break;
case EVENT_SPAWN_WAVE:
SummonWave();
break;
default:
break; break;
} }
} }
DoMeleeAttackIfReady();
} }
void SummonWave() if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
me->SummonCreatureGroup(_currentWave); switch (eventId)
if (GameObject* waveDoor = me->GetMap()->GetGameObject(waveDoorGUID))
{ {
waveDoor->UseDoorOrButton(); case EVENT_WHIRLWIND:
DoCast(SPELL_WHIRLWIND);
events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 18s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 10s, 14s);
break;
case EVENT_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTAL_STRIKE);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 14s, 18s);
break;
} }
++_currentWave;
} }
DoMeleeAttackIfReady();
private:
bool gythEvent;
uint8 _currentWave;
ObjectGuid victorGUID;
ObjectGuid waveDoorGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_rend_blackhandAI>(creature);
} }
void SummonWave()
{
me->SummonCreatureGroup(_currentWave);
if (GameObject* waveDoor = me->GetMap()->GetGameObject(_waveDoorGUID))
waveDoor->UseDoorOrButton();
++_currentWave;
}
private:
bool _gythEvent;
uint8 _currentWave;
ObjectGuid _victorGUID;
ObjectGuid _waveDoorGUID;
}; };
void AddSC_boss_rend_blackhand() void AddSC_boss_rend_blackhand()
{ {
new boss_rend_blackhand(); RegisterBlackrockSpireCreatureAI(boss_rend_blackhand);
} }

View File

@@ -38,211 +38,178 @@ enum Says
SAY_SUMMON = 0, SAY_SUMMON = 0,
}; };
class npc_rookery_hatcher : public CreatureScript struct npc_rookery_hatcher : public CreatureAI
{ {
public: npc_rookery_hatcher(Creature* creature) : CreatureAI(creature) {}
npc_rookery_hatcher() : CreatureScript("npc_rookery_hatcher") {}
CreatureAI* GetAI(Creature* creature) const override EventMap events;
GameObject* targetEgg;
Position targetPosition;
void InitializeAI() override
{ {
return GetBlackrockSpireAI<npc_rookery_hatcherAI>(creature); CreatureAI::InitializeAI();
DoZoneInCombat(nullptr, 100.0f);
targetEgg = nullptr;
} }
struct npc_rookery_hatcherAI : public CreatureAI void JustEngagedWith(Unit* /*who*/) override
{ {
npc_rookery_hatcherAI(Creature* creature) : CreatureAI(creature) {} events.ScheduleEvent(SPELL_HATCH_EGG, 1s);
}
EventMap events; void UpdateAI(uint32 diff) override
{
std::list<GameObject*> nearbyEggs; std::list<GameObject*> nearbyEggs;
GameObject* targetEgg; float tempDist = 20;
Position targetPosition; float minDist = 25;
std::list<Creature*> nearbyWhelps;
void InitializeAI() override if (!UpdateVictim())
return;
GetCreatureListWithEntryInGrid(nearbyWhelps, me, NPC_ROOKERY_WHELP, RANGE_WHELP_CALL_HELP);
for (auto const& whelp : nearbyWhelps)
{ {
CreatureAI::InitializeAI(); if (!whelp->IsInCombat())
DoZoneInCombat(nullptr, 100.0f);
nearbyEggs.clear();
targetEgg = nullptr;
}
void JustEngagedWith(Unit* /*who*/) override
{
events.ScheduleEvent(SPELL_HATCH_EGG, 1s);
}
void UpdateAI(uint32 diff) override
{
std::list<GameObject*> nearbyEggs;
float tempDist = 20;
float minDist = 25;
std::list<Creature*> nearbyWhelps;
if (!UpdateVictim())
{ {
return; whelp->SetInCombatWith(me->GetVictim());
whelp->AI()->AttackStart(me->GetVictim());
} }
GetCreatureListWithEntryInGrid(nearbyWhelps, me, NPC_ROOKERY_WHELP, RANGE_WHELP_CALL_HELP);
for (auto const& whelp : nearbyWhelps)
{
if (!whelp->IsInCombat())
{
whelp->SetInCombatWith(me->GetVictim());
whelp->AI()->AttackStart(me->GetVictim());
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_HATCH_EGG:
if (!targetEgg) // no target, try to find one
{
minDist = 50;
tempDist = 50;
me->GetGameObjectListWithEntryInGrid(nearbyEggs, GO_ROOKERY_EGG, 40);
for (auto const& egg : nearbyEggs)
{
if (egg->isSpawned() && egg->getLootState() == GO_READY)
{
tempDist = me->GetDistance2d(egg);
if (tempDist < minDist)
{
minDist = tempDist;
targetEgg = egg;
}
}
}
}
if (targetEgg) //have a target, go to it and cast it
{
me->GetMotionMaster()->MovePoint(0, targetEgg->GetPosition());
}
break;
default:
break;
}
}
// cast takes 1.5second, during which we don't have a target
if (targetEgg && targetEgg->getLootState() == GO_READY && me->GetDistance2d(targetEgg) < RANGE_SPELL_HATCH_EGG)
{
me->StopMovingOnCurrentPos();
me->SetFacingToObject(targetEgg);
targetPosition = me->GetPosition();
DoCast(SPELL_HATCH_EGG);
targetEgg = nullptr;
events.ScheduleEvent(SPELL_HATCH_EGG, 6s, 8s);
}
else if (!me->HasUnitState(UNIT_STATE_CASTING) && !targetEgg)
{
if (Unit* victim = me->GetVictim())
{
AttackStart(victim);
}
if (me->GetDistance2d(me->GetVictim()) > me->GetMeleeReach())
{
me->GetMotionMaster()->MovePoint(0, me->GetVictim()->GetPosition()); // a bit hacky, but needed to start moving once we've summoned an egg
}
}
DoMeleeAttackIfReady();
}
};
};
class boss_solakar_flamewreath : public CreatureScript
{
public:
boss_solakar_flamewreath() : CreatureScript("boss_solakar_flamewreath") { }
struct boss_solakar_flamewreathAI : public BossAI
{
boss_solakar_flamewreathAI(Creature* creature) : BossAI(creature, DATA_SOLAKAR_FLAMEWREATH) {}
uint32 resetTimer;
void Reset() override
{
_Reset();
resetTimer = 10000;
} }
void InitializeAI() override if (me->HasUnitState(UNIT_STATE_CASTING))
{ return;
BossAI::InitializeAI(); events.Update(diff);
Talk(SAY_SUMMON);
DoZoneInCombat(nullptr, 100.0f);
}
void JustEngagedWith(Unit* /*who*/) override while (uint32 eventId = events.ExecuteEvent())
{
_JustEngagedWith();
events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s);
resetTimer = 0;
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, DONE);
}
void ExecuteEvent(uint32 eventId) override
{ {
switch (eventId) switch (eventId)
{ {
case SPELL_WAR_STOMP: case SPELL_HATCH_EGG:
DoCastVictim(SPELL_WAR_STOMP); if (!targetEgg) // no target, try to find one
events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s); {
break; minDist = 50;
tempDist = 50;
me->GetGameObjectListWithEntryInGrid(nearbyEggs, GO_ROOKERY_EGG, 40);
for (auto const& egg : nearbyEggs)
{
if (egg->isSpawned() && egg->getLootState() == GO_READY)
{
tempDist = me->GetDistance2d(egg);
if (tempDist < minDist)
{
minDist = tempDist;
targetEgg = egg;
}
}
}
}
if (targetEgg) //have a target, go to it and cast it
me->GetMotionMaster()->MovePoint(0, targetEgg->GetPosition());
break;
default: default:
break; break;
} }
} }
void UpdateAI(uint32 diff) override // cast takes 1.5second, during which we don't have a target
if (targetEgg && targetEgg->getLootState() == GO_READY && me->GetDistance2d(targetEgg) < RANGE_SPELL_HATCH_EGG)
{ {
if (!UpdateVictim()) me->StopMovingOnCurrentPos();
{ me->SetFacingToObject(targetEgg);
resetTimer -= diff; targetPosition = me->GetPosition();
if (resetTimer < diff) DoCast(SPELL_HATCH_EGG);
{ targetEgg = nullptr;
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL); events.ScheduleEvent(SPELL_HATCH_EGG, 6s, 8s);
}
return;
}
resetTimer = 10000;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
ExecuteEvent(eventId);
}
DoMeleeAttackIfReady();
} }
}; else if (!me->HasUnitState(UNIT_STATE_CASTING) && !targetEgg)
{
if (Unit* victim = me->GetVictim())
AttackStart(victim);
CreatureAI* GetAI(Creature* creature) const override if (me->GetDistance2d(me->GetVictim()) > me->GetMeleeReach())
me->GetMotionMaster()->MovePoint(0, me->GetVictim()->GetPosition()); // a bit hacky, but needed to start moving once we've summoned an egg
}
DoMeleeAttackIfReady();
}
};
struct boss_solakar_flamewreath : public BossAI
{
boss_solakar_flamewreath(Creature* creature) : BossAI(creature, DATA_SOLAKAR_FLAMEWREATH) {}
uint32 resetTimer;
void Reset() override
{ {
return GetBlackrockSpireAI<boss_solakar_flamewreathAI>(creature); _Reset();
resetTimer = 10000;
}
void InitializeAI() override
{
BossAI::InitializeAI();
Talk(SAY_SUMMON);
DoZoneInCombat(nullptr, 100.0f);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s);
resetTimer = 0;
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, DONE);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case SPELL_WAR_STOMP:
DoCastVictim(SPELL_WAR_STOMP);
events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
if (resetTimer <= diff)
{
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL);
return;
}
resetTimer -= diff;
return;
}
resetTimer = 10000;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
ExecuteEvent(eventId);
}
DoMeleeAttackIfReady();
} }
}; };
void AddSC_boss_solakar_flamewreath() void AddSC_boss_solakar_flamewreath()
{ {
new boss_solakar_flamewreath(); RegisterBlackrockSpireCreatureAI(boss_solakar_flamewreath);
new npc_rookery_hatcher(); RegisterBlackrockSpireCreatureAI(npc_rookery_hatcher);
} }

View File

@@ -90,185 +90,152 @@ private:
// Used to make Hodir disengage whenever he leaves his room // Used to make Hodir disengage whenever he leaves his room
constexpr static float FirewalPositionY = -505.f; constexpr static float FirewalPositionY = -505.f;
class boss_the_beast : public CreatureScript struct boss_the_beast : public BossAI
{ {
public: boss_the_beast(Creature* creature) : BossAI(creature, DATA_THE_BEAST), _beastReached(false), _orcYelled(false) {}
boss_the_beast() : CreatureScript("boss_the_beast") { }
CreatureAI* GetAI(Creature* creature) const override void Reset() override
{ {
return GetBlackrockSpireAI<boss_thebeastAI>(creature); _Reset();
if (_beastReached)
me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true);
} }
struct boss_thebeastAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_thebeastAI(Creature* creature) : BossAI(creature, DATA_THE_BEAST), _beastReached(false), _orcYelled(false) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_FLAME_BREAK, 12s);
events.ScheduleEvent(EVENT_IMMOLATE, 3s);
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 23s);
events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 2s);
events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s);
events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s);
}
void Reset() override void SetData(uint32 type, uint32 /*data*/) override
{
switch (type)
{ {
_Reset(); case DATA_BEAST_ROOM:
if (_beastReached)
{ {
me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true); if (!_orcYelled)
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_FLAME_BREAK, 12s);
events.ScheduleEvent(EVENT_IMMOLATE, 3s);
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 23s);
events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 2s);
events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s);
events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s);
}
void SetData(uint32 type, uint32 /*data*/) override
{
switch (type)
{
case DATA_BEAST_ROOM:
{ {
if (!_orcYelled) if (_nearbyOrcsGUIDs.empty())
FindNearbyOrcs();
//! vector still empty, creatures are missing
if (_nearbyOrcsGUIDs.empty())
return;
_orcYelled = true;
bool yelled = false;
for (ObjectGuid guid : _nearbyOrcsGUIDs)
{ {
if (_nearbyOrcsGUIDs.empty()) if (Creature* orc = ObjectAccessor::GetCreature(*me, guid))
{ {
FindNearbyOrcs(); if (!yelled)
}
//! vector still empty, creatures are missing
if (_nearbyOrcsGUIDs.empty())
{
return;
}
_orcYelled = true;
bool yelled = false;
for (ObjectGuid guid : _nearbyOrcsGUIDs)
{
if (Creature* orc = ObjectAccessor::GetCreature(*me, guid))
{ {
if (!yelled) yelled = true;
{ orc->AI()->Talk(SAY_BLACKHAND_DOOMED);
yelled = true;
orc->AI()->Talk(SAY_BLACKHAND_DOOMED);
}
orc->m_Events.AddEventAtOffset(new OrcMoveEvent(orc), 3s);
orc->m_Events.AddEventAtOffset(new OrcDeathEvent(orc), 9s);
} }
orc->m_Events.AddEventAtOffset(new OrcMoveEvent(orc), 3s);
orc->m_Events.AddEventAtOffset(new OrcDeathEvent(orc), 9s);
} }
} }
break;
} }
case DATA_BEAST_REACHED: break;
}
case DATA_BEAST_REACHED:
{
if (!_beastReached)
{ {
if (!_beastReached) _beastReached = true;
{ me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true);
_beastReached = true;
me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true);
// There is a chance player logged in between areatriggers (realm crash or restart) // There is a chance player logged in between areatriggers (realm crash or restart)
// executing part of script which happens when player enters boss room // executing part of script which happens when player enters boss room
// otherwise we will see weird behaviour when someone steps on the previous areatrigger (dead mob yelling/moving) // otherwise we will see weird behaviour when someone steps on the previous areatrigger (dead mob yelling/moving)
SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM); SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM);
}
break;
} }
break;
} }
} }
}
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (me->GetPositionY() > FirewalPositionY)
{ {
if (!UpdateVictim()) EnterEvadeMode();
{ return;
return; }
}
if (me->GetPositionY() > FirewalPositionY) events.Update(diff);
{
EnterEvadeMode();
return;
}
events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FLAME_BREAK:
DoCastVictim(SPELL_FLAMEBREAK);
events.ScheduleEvent(EVENT_FLAME_BREAK, 10s);
break;
case EVENT_IMMOLATE:
DoCastRandomTarget(SPELL_IMMOLATE, 0, 100.0f);
events.ScheduleEvent(EVENT_IMMOLATE, 8s);
break;
case EVENT_TERRIFYING_ROAR:
DoCastVictim(SPELL_TERRIFYINGROAR);
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 20s);
break;
case EVENT_BERSERKER_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 38.f, true))
DoCast(target, SPELL_BERSERKER_CHARGE);
events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 15s, 23s);
break;
case EVENT_FIREBALL:
DoCastVictim(SPELL_FIREBALL);
events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s);
if (events.GetTimeUntilEvent(EVENT_FIREBLAST) < 3s)
events.RescheduleEvent(EVENT_FIREBLAST, 3s);
break;
case EVENT_FIREBLAST:
DoCastVictim(SPELL_FIREBLAST);
events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s);
if (events.GetTimeUntilEvent(EVENT_FIREBALL) < 3s)
events.RescheduleEvent(EVENT_FIREBALL, 3s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_FLAME_BREAK:
DoCastVictim(SPELL_FLAMEBREAK);
events.ScheduleEvent(EVENT_FLAME_BREAK, 10s);
break;
case EVENT_IMMOLATE:
DoCastRandomTarget(SPELL_IMMOLATE, 0, 100.0f);
events.ScheduleEvent(EVENT_IMMOLATE, 8s);
break;
case EVENT_TERRIFYING_ROAR:
DoCastVictim(SPELL_TERRIFYINGROAR);
events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 20s);
break;
case EVENT_BERSERKER_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 38.f, true))
{
DoCast(target, SPELL_BERSERKER_CHARGE);
}
events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 15s, 23s);
break;
case EVENT_FIREBALL:
DoCastVictim(SPELL_FIREBALL);
events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s);
if (events.GetTimeUntilEvent(EVENT_FIREBLAST) < 3s)
{
events.RescheduleEvent(EVENT_FIREBLAST, 3s);
}
break;
case EVENT_FIREBLAST:
DoCastVictim(SPELL_FIREBLAST);
events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s);
if (events.GetTimeUntilEvent(EVENT_FIREBALL) < 3s)
{
events.RescheduleEvent(EVENT_FIREBALL, 3s);
}
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
} }
void FindNearbyOrcs() DoMeleeAttackIfReady();
{ }
std::list<Creature*> temp;
me->GetCreatureListWithEntryInGrid(temp, NPC_BLACKHAND_ELITE, 50.0f);
for (Creature* creature : temp)
{
if (creature->IsAlive())
{
_nearbyOrcsGUIDs.push_back(creature->GetGUID());
}
}
}
private: void FindNearbyOrcs()
bool _beastReached; {
bool _orcYelled; std::list<Creature*> temp;
GuidVector _nearbyOrcsGUIDs; me->GetCreatureListWithEntryInGrid(temp, NPC_BLACKHAND_ELITE, 50.0f);
}; for (Creature* creature : temp)
if (creature->IsAlive())
_nearbyOrcsGUIDs.push_back(creature->GetGUID());
}
private:
bool _beastReached;
bool _orcYelled;
GuidVector _nearbyOrcsGUIDs;
}; };
//! The beast room areatrigger, this one triggers boss pathing. (AT Id 2066) //! The beast room areatrigger, this one triggers boss pathing. (AT Id 2066)
@@ -280,16 +247,12 @@ public:
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{ {
if (player->IsGameMaster()) if (player->IsGameMaster())
{
return false; return false;
}
if (InstanceScript* instance = player->GetInstanceScript()) if (InstanceScript* instance = player->GetInstanceScript())
{ {
if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST))) if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST)))
{
beast->AI()->SetData(DATA_BEAST_REACHED, DATA_BEAST_REACHED); beast->AI()->SetData(DATA_BEAST_REACHED, DATA_BEAST_REACHED);
}
return true; return true;
} }
@@ -306,16 +269,12 @@ public:
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{ {
if (player->IsGameMaster()) if (player->IsGameMaster())
{
return false; return false;
}
if (InstanceScript* instance = player->GetInstanceScript()) if (InstanceScript* instance = player->GetInstanceScript())
{ {
if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST))) if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST)))
{
beast->AI()->SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM); beast->AI()->SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM);
}
return true; return true;
} }
@@ -326,7 +285,7 @@ public:
void AddSC_boss_thebeast() void AddSC_boss_thebeast()
{ {
new boss_the_beast(); RegisterBlackrockSpireCreatureAI(boss_the_beast);
new at_trigger_the_beast_movement(); new at_trigger_the_beast_movement();
new at_the_beast_room(); new at_the_beast_room();
} }

View File

@@ -40,82 +40,67 @@ enum Events
EVENT_INTIMIDATING_ROAR = 3 EVENT_INTIMIDATING_ROAR = 3
}; };
class boss_urok_doomhowl : public CreatureScript struct boss_urok_doomhowl : public BossAI
{ {
public: boss_urok_doomhowl(Creature* creature) : BossAI(creature, DATA_UROK_DOOMHOWL) {}
boss_urok_doomhowl() : CreatureScript("boss_urok_doomhowl") { }
struct boss_urok_doomhowlAI : public BossAI void InitializeAI() override
{ {
boss_urok_doomhowlAI(Creature* creature) : BossAI(creature, DATA_UROK_DOOMHOWL) {} me->CastSpell(me, SPELL_UROK_SPAWN, true);
BossAI::InitializeAI();
Talk(SAY_SUMMON);
DoZoneInCombat(nullptr, 100.0f);
void InitializeAI() override if (GameObject* challenge = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_CHALLENGE)))
{ challenge->Delete();
me->CastSpell(me, SPELL_UROK_SPAWN, true);
BossAI::InitializeAI();
Talk(SAY_SUMMON);
DoZoneInCombat(nullptr, 100.0f);
if (GameObject* challenge = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_CHALLENGE))) if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE)))
{ pile->DespawnOrUnsummon(0ms, Seconds(MONTH));
challenge->Delete(); }
}
if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE))) void JustEngagedWith(Unit* /*who*/) override
{
pile->DespawnOrUnsummon(0ms, Seconds(MONTH));
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(SPELL_REND, 17s, 20s);
events.ScheduleEvent(SPELL_STRIKE, 10s, 12s);
events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 25s, 30s);
}
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_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(SPELL_REND, 8s, 10s);
break;
case SPELL_STRIKE:
DoCastVictim(SPELL_STRIKE);
events.ScheduleEvent(SPELL_STRIKE, 8s, 10s);
break;
case SPELL_INTIMIDATING_ROAR:
DoCastVictim(SPELL_INTIMIDATING_ROAR);
events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 40s, 45s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetBlackrockSpireAI<boss_urok_doomhowlAI>(creature); _JustEngagedWith();
events.ScheduleEvent(SPELL_REND, 17s, 20s);
events.ScheduleEvent(SPELL_STRIKE, 10s, 12s);
events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 25s, 30s);
}
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_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(SPELL_REND, 8s, 10s);
break;
case SPELL_STRIKE:
DoCastVictim(SPELL_STRIKE);
events.ScheduleEvent(SPELL_STRIKE, 8s, 10s);
break;
case SPELL_INTIMIDATING_ROAR:
DoCastVictim(SPELL_INTIMIDATING_ROAR);
events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 40s, 45s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
} }
}; };
void AddSC_boss_urok_doomhowl() void AddSC_boss_urok_doomhowl()
{ {
new boss_urok_doomhowl(); RegisterBlackrockSpireCreatureAI(boss_urok_doomhowl);
} }

View File

@@ -55,86 +55,75 @@ enum EventGroups
GROUP_WARMASTER GROUP_WARMASTER
}; };
class boss_warmaster_voone : public CreatureScript struct boss_warmaster_voone : public BossAI
{ {
public: boss_warmaster_voone(Creature* creature) : BossAI(creature, DATA_WARMASTER_VOONE) { }
boss_warmaster_voone() : CreatureScript("boss_warmaster_voone") { }
struct boss_warmastervooneAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_warmastervooneAI(Creature* creature) : BossAI(creature, DATA_WARMASTER_VOONE) { } _JustEngagedWith();
void JustEngagedWith(Unit* /*who*/) override events.SetPhase(PHASE_BRAWLER);
{ events.ScheduleEvent(EVENT_THRASH, 3s, GROUP_BRAWLER, PHASE_BRAWLER);
_JustEngagedWith(); events.ScheduleEvent(EVENT_THROW_AXE, 1s, GROUP_BRAWLER, PHASE_BRAWLER);
}
events.SetPhase(PHASE_BRAWLER); void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
events.ScheduleEvent(EVENT_THRASH, 3s, GROUP_BRAWLER, PHASE_BRAWLER);
events.ScheduleEvent(EVENT_THROW_AXE, 1s, GROUP_BRAWLER, PHASE_BRAWLER);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
{
if (me->HealthBelowPctDamaged(65, damage) && events.IsInPhase(PHASE_BRAWLER))
{
events.SetPhase(PHASE_THRASHER);
events.CancelEventGroup(GROUP_BRAWLER);
events.ScheduleEvent(EVENT_CLEAVE, 14s, GROUP_THRASHER, PHASE_THRASHER);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 12s, GROUP_THRASHER, PHASE_THRASHER);
}
else if (me->HealthBelowPctDamaged(40, damage) && events.IsInPhase(PHASE_THRASHER))
{
events.SetPhase(PHASE_WARMASTER);
events.CancelEventGroup(GROUP_THRASHER);
events.ScheduleEvent(EVENT_SNAP_KICK, 8s, GROUP_WARMASTER, PHASE_WARMASTER);
events.ScheduleEvent(EVENT_UPPERCUT, 20s, GROUP_WARMASTER, PHASE_WARMASTER);
events.ScheduleEvent(EVENT_PUMMEL, 32s, GROUP_WARMASTER, PHASE_WARMASTER);
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SNAP_KICK:
DoCastVictim(SPELL_SNAPKICK);
events.Repeat(6s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.Repeat(12s);
break;
case EVENT_UPPERCUT:
DoCastVictim(SPELL_UPPERCUT);
events.Repeat(14s);
break;
case EVENT_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.Repeat(10s);
break;
case EVENT_PUMMEL:
DoCastVictim(SPELL_PUMMEL);
events.Repeat(16s);
break;
case EVENT_THROW_AXE:
DoCastRandomTarget(SPELL_THROWAXE);
events.Repeat(8s);
break;
case EVENT_THRASH:
DoCastSelf(SPELL_THRASH);
events.Repeat(10s);
break;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetBlackrockSpireAI<boss_warmastervooneAI>(creature); if (me->HealthBelowPctDamaged(65, damage) && events.IsInPhase(PHASE_BRAWLER))
{
events.SetPhase(PHASE_THRASHER);
events.CancelEventGroup(GROUP_BRAWLER);
events.ScheduleEvent(EVENT_CLEAVE, 14s, GROUP_THRASHER, PHASE_THRASHER);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 12s, GROUP_THRASHER, PHASE_THRASHER);
}
else if (me->HealthBelowPctDamaged(40, damage) && events.IsInPhase(PHASE_THRASHER))
{
events.SetPhase(PHASE_WARMASTER);
events.CancelEventGroup(GROUP_THRASHER);
events.ScheduleEvent(EVENT_SNAP_KICK, 8s, GROUP_WARMASTER, PHASE_WARMASTER);
events.ScheduleEvent(EVENT_UPPERCUT, 20s, GROUP_WARMASTER, PHASE_WARMASTER);
events.ScheduleEvent(EVENT_PUMMEL, 32s, GROUP_WARMASTER, PHASE_WARMASTER);
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SNAP_KICK:
DoCastVictim(SPELL_SNAPKICK);
events.Repeat(6s);
break;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.Repeat(12s);
break;
case EVENT_UPPERCUT:
DoCastVictim(SPELL_UPPERCUT);
events.Repeat(14s);
break;
case EVENT_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.Repeat(10s);
break;
case EVENT_PUMMEL:
DoCastVictim(SPELL_PUMMEL);
events.Repeat(16s);
break;
case EVENT_THROW_AXE:
DoCastRandomTarget(SPELL_THROWAXE);
events.Repeat(8s);
break;
case EVENT_THRASH:
DoCastSelf(SPELL_THRASH);
events.Repeat(10s);
break;
}
} }
}; };
void AddSC_boss_warmastervoone() void AddSC_boss_warmastervoone()
{ {
new boss_warmaster_voone(); RegisterBlackrockSpireCreatureAI(boss_warmaster_voone);
} }

View File

@@ -127,5 +127,6 @@ inline AI* GetBlackwingLairAI(T* obj)
} }
#define RegisterBlackwingLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackwingLairAI) #define RegisterBlackwingLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackwingLairAI)
#define RegisterBlackwingLairGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackwingLairAI)
#endif #endif

View File

@@ -58,196 +58,157 @@ enum Actions
ACTION_DISARMED = 1 ACTION_DISARMED = 1
}; };
class boss_broodlord : public CreatureScript struct boss_broodlord : public BossAI
{ {
public: boss_broodlord(Creature* creature) : BossAI(creature, DATA_BROODLORD_LASHLAYER) { }
boss_broodlord() : CreatureScript("boss_broodlord") { }
struct boss_broodlordAI : public BossAI void JustEngagedWith(Unit* who) override
{ {
boss_broodlordAI(Creature* creature) : BossAI(creature, DATA_BROODLORD_LASHLAYER) { } BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
void JustEngagedWith(Unit* who) override events.ScheduleEvent(EVENT_CLEAVE, 8s);
{ events.ScheduleEvent(EVENT_BLASTWAVE, 12s);
BossAI::JustEngagedWith(who); events.ScheduleEvent(EVENT_MORTALSTRIKE, 20s);
Talk(SAY_AGGRO); events.ScheduleEvent(EVENT_KNOCKBACK, 30s);
events.ScheduleEvent(EVENT_CHECK, 1s);
events.ScheduleEvent(EVENT_CLEAVE, 8s);
events.ScheduleEvent(EVENT_BLASTWAVE, 12s);
events.ScheduleEvent(EVENT_MORTALSTRIKE, 20s);
events.ScheduleEvent(EVENT_KNOCKBACK, 30s);
events.ScheduleEvent(EVENT_CHECK, 1s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
std::list<GameObject*> _goList;
GetGameObjectListWithEntryInGrid(_goList, me, GO_SUPPRESSION_DEVICE, 200.0f);
for (std::list<GameObject*>::const_iterator itr = _goList.begin(); itr != _goList.end(); itr++)
{
((*itr)->AI()->DoAction(ACTION_DEACTIVATE));
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 7s);
break;
case EVENT_BLASTWAVE:
DoCastVictim(SPELL_BLASTWAVE);
events.ScheduleEvent(EVENT_BLASTWAVE, 20s, 35s);
break;
case EVENT_MORTALSTRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.ScheduleEvent(EVENT_MORTALSTRIKE, 25s, 35s);
break;
case EVENT_KNOCKBACK:
DoCastVictim(SPELL_KNOCKBACK);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatByPercent(me->GetVictim(), -50);
events.ScheduleEvent(EVENT_KNOCKBACK, 15s, 30s);
break;
case EVENT_CHECK:
if (me->GetDistance(me->GetHomePosition()) > 150.0f)
{
Talk(SAY_LEASH);
EnterEvadeMode();
}
events.ScheduleEvent(EVENT_CHECK, 1s);
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_broodlordAI>(creature);
} }
};
class go_suppression_device : public GameObjectScript void JustDied(Unit* /*killer*/) override
{ {
public: _JustDied();
go_suppression_device() : GameObjectScript("go_suppression_device") { }
void OnLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override std::list<GameObject*> _goList;
GetGameObjectListWithEntryInGrid(_goList, me, GO_SUPPRESSION_DEVICE, 200.0f);
for (std::list<GameObject*>::const_iterator itr = _goList.begin(); itr != _goList.end(); itr++)
((*itr)->AI()->DoAction(ACTION_DEACTIVATE));
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{ {
switch (state) switch (eventId)
{ {
case GO_JUST_DEACTIVATED: // This case prevents the Gameobject despawn by Disarm Trap case EVENT_CLEAVE:
go->SetLootState(GO_READY); DoCastVictim(SPELL_CLEAVE);
[[fallthrough]]; events.ScheduleEvent(EVENT_CLEAVE, 7s);
case GO_ACTIVATED: break;
go->AI()->DoAction(ACTION_DISARMED); case EVENT_BLASTWAVE:
DoCastVictim(SPELL_BLASTWAVE);
events.ScheduleEvent(EVENT_BLASTWAVE, 20s, 35s);
break;
case EVENT_MORTALSTRIKE:
DoCastVictim(SPELL_MORTALSTRIKE);
events.ScheduleEvent(EVENT_MORTALSTRIKE, 25s, 35s);
break;
case EVENT_KNOCKBACK:
DoCastVictim(SPELL_KNOCKBACK);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatByPercent(me->GetVictim(), -50);
events.ScheduleEvent(EVENT_KNOCKBACK, 15s, 30s);
break;
case EVENT_CHECK:
if (me->GetDistance(me->GetHomePosition()) > 150.0f)
{
Talk(SAY_LEASH);
EnterEvadeMode();
}
events.ScheduleEvent(EVENT_CHECK, 1s);
break; break;
} }
} }
struct go_suppression_deviceAI : public GameObjectAI DoMeleeAttackIfReady();
}
};
struct go_suppression_device : public GameObjectAI
{
go_suppression_device(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()), _active(true) { }
void InitializeAI() override
{
if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) == DONE)
{ {
go_suppression_deviceAI(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()), _active(true) { } Deactivate();
return;
void InitializeAI() override
{
if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) == DONE)
{
Deactivate();
return;
}
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUPPRESSION_CAST:
if (me->GetGoState() == GO_STATE_READY)
{
me->CastSpell(nullptr, SPELL_SUPPRESSION_AURA);
me->SendCustomAnim(0);
}
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
break;
case EVENT_SUPPRESSION_RESET:
Activate();
break;
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_DEACTIVATE)
{
_events.CancelEvent(EVENT_SUPPRESSION_RESET);
}
else if (action == ACTION_DISARMED)
{
Deactivate();
_events.CancelEvent(EVENT_SUPPRESSION_CAST);
if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) != DONE)
{
_events.ScheduleEvent(EVENT_SUPPRESSION_RESET, 30s, 120s);
}
}
}
void Activate()
{
if (_active)
return;
_active = true;
if (me->GetGoState() == GO_STATE_ACTIVE)
me->SetGoState(GO_STATE_READY);
me->SetLootState(GO_READY);
me->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
me->Respawn();
}
void Deactivate()
{
if (!_active)
return;
_active = false;
me->SetGoState(GO_STATE_ACTIVE);
me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
_events.CancelEvent(EVENT_SUPPRESSION_CAST);
}
private:
InstanceScript* _instance;
EventMap _events;
bool _active;
};
GameObjectAI* GetAI(GameObject* go) const override
{
return new go_suppression_deviceAI(go);
} }
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUPPRESSION_CAST:
if (me->GetGoState() == GO_STATE_READY)
{
me->CastSpell(nullptr, SPELL_SUPPRESSION_AURA);
me->SendCustomAnim(0);
}
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
break;
case EVENT_SUPPRESSION_RESET:
Activate();
break;
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_DEACTIVATE)
{
_events.CancelEvent(EVENT_SUPPRESSION_RESET);
}
else if (action == ACTION_DISARMED)
{
Deactivate();
_events.CancelEvent(EVENT_SUPPRESSION_CAST);
if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) != DONE)
_events.ScheduleEvent(EVENT_SUPPRESSION_RESET, 30s, 120s);
}
}
void Activate()
{
if (_active)
return;
_active = true;
if (me->GetGoState() == GO_STATE_ACTIVE)
me->SetGoState(GO_STATE_READY);
me->SetLootState(GO_READY);
me->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
_events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s);
me->Respawn();
}
void Deactivate()
{
if (!_active)
return;
_active = false;
me->SetGoState(GO_STATE_ACTIVE);
me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
_events.CancelEvent(EVENT_SUPPRESSION_CAST);
}
private:
InstanceScript* _instance;
EventMap _events;
bool _active;
}; };
class spell_suppression_aura : public SpellScript class spell_suppression_aura : public SpellScript
@@ -271,7 +232,7 @@ class spell_suppression_aura : public SpellScript
void AddSC_boss_broodlord() void AddSC_boss_broodlord()
{ {
new boss_broodlord(); RegisterBlackwingLairCreatureAI(boss_broodlord);
new go_suppression_device(); RegisterBlackwingLairGameObjectAI(go_suppression_device);
RegisterSpellScript(spell_suppression_aura); RegisterSpellScript(spell_suppression_aura);
} }

View File

@@ -70,203 +70,171 @@ enum Misc
Position const homePos = { -7491.1587f, -1069.718f, 476.59094, 476.59094f }; Position const homePos = { -7491.1587f, -1069.718f, 476.59094, 476.59094f };
class boss_chromaggus : public CreatureScript struct boss_chromaggus : public BossAI
{ {
public: boss_chromaggus(Creature* creature) : BossAI(creature, DATA_CHROMAGGUS)
boss_chromaggus() : CreatureScript("boss_chromaggus") { }
struct boss_chromaggusAI : public BossAI
{ {
boss_chromaggusAI(Creature* creature) : BossAI(creature, DATA_CHROMAGGUS) Initialize();
// Select the 2 breaths that we are going to use until despawned so we don't end up casting 2 of the same breath.
_breathSpells = { SPELL_INCINERATE, SPELL_TIMELAPSE, SPELL_CORROSIVEACID, SPELL_IGNITEFLESH, SPELL_FROSTBURN };
Acore::Containers::RandomResize(_breathSpells, 2);
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
creature->SetImmuneToAll(true);
}
void Initialize()
{
Enraged = false;
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SHIMMER, 1s);
events.ScheduleEvent(EVENT_BREATH, 30s);
events.ScheduleEvent(EVENT_BREATH, 60s);
events.ScheduleEvent(EVENT_AFFLICTION, 10s);
events.ScheduleEvent(EVENT_FRENZY, 15s);
}
bool CanAIAttack(Unit const* victim) const override
{
return !victim->HasAura(SPELL_TIMELAPSE);
}
void SetGUID(ObjectGuid const& guid, int32 id) override
{
if (id == GUID_LEVER_USER)
{ {
Initialize(); _playerGUID = guid;
// Select the 2 breaths that we are going to use until despawned so we don't end up casting 2 of the same breath.
_breathSpells = { SPELL_INCINERATE, SPELL_TIMELAPSE, SPELL_CORROSIVEACID, SPELL_IGNITEFLESH, SPELL_FROSTBURN };
Acore::Containers::RandomResize(_breathSpells, 2);
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed. // Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
creature->SetImmuneToAll(true); me->SetImmuneToAll(false);
} }
}
void Initialize() void PathEndReached(uint32 /*pathId*/) override
{
if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID))
me->SetInCombatWith(player);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
Enraged = false; switch (eventId)
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SHIMMER, 1s);
events.ScheduleEvent(EVENT_BREATH, 30s);
events.ScheduleEvent(EVENT_BREATH, 60s);
events.ScheduleEvent(EVENT_AFFLICTION, 10s);
events.ScheduleEvent(EVENT_FRENZY, 15s);
}
bool CanAIAttack(Unit const* victim) const override
{
return !victim->HasAura(SPELL_TIMELAPSE);
}
void SetGUID(ObjectGuid const& guid, int32 id) override
{
if (id == GUID_LEVER_USER)
{ {
_playerGUID = guid; case EVENT_SHIMMER:
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed. {
me->SetImmuneToAll(false); // Cast new random vulnerabilty on self
DoCast(me, SPELL_ELEMENTAL_SHIELD);
Talk(EMOTE_SHIMMER);
events.ScheduleEvent(EVENT_SHIMMER, 17s, 25s);
break;
}
case EVENT_BREATH:
DoCastVictim(_breathSpells.front());
_breathSpells.reverse();
events.ScheduleEvent(EVENT_BREATH, 60s);
break;
case EVENT_AFFLICTION:
{
uint32 afflictionSpellID = RAND(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN);
std::vector<Player*> playerTargets;
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()->ToPlayer())
if (!player->IsGameMaster() && !player->IsSpectator() && player->IsAlive())
playerTargets.push_back(player);
if (playerTargets.size() > 12)
Acore::Containers::RandomResize(playerTargets, 12);
for (Player* player : playerTargets)
{
DoCast(player, afflictionSpellID, true);
if (player->HasAllAuras(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN))
DoCast(player, SPELL_CHROMATIC_MUT_1);
}
}
events.ScheduleEvent(EVENT_AFFLICTION, 10s);
break;
case EVENT_FRENZY:
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 10s, 15s);
break;
} }
}
void PathEndReached(uint32 /*pathId*/) override
{
if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID))
{
me->SetInCombatWith(player);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHIMMER:
{
// Cast new random vulnerabilty on self
DoCast(me, SPELL_ELEMENTAL_SHIELD);
Talk(EMOTE_SHIMMER);
events.ScheduleEvent(EVENT_SHIMMER, 17s, 25s);
break;
}
case EVENT_BREATH:
DoCastVictim(_breathSpells.front());
_breathSpells.reverse();
events.ScheduleEvent(EVENT_BREATH, 60s);
break;
case EVENT_AFFLICTION:
{
uint32 afflictionSpellID = RAND(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN);
std::vector<Player*> playerTargets;
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
if (Player* player = itr->GetSource()->ToPlayer())
{
if (!player->IsGameMaster() && !player->IsSpectator() && player->IsAlive())
{
playerTargets.push_back(player);
}
}
}
if (playerTargets.size() > 12)
{
Acore::Containers::RandomResize(playerTargets, 12);
}
for (Player* player : playerTargets)
{
DoCast(player, afflictionSpellID, true);
if (player->HasAllAuras(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN))
DoCast(player, SPELL_CHROMATIC_MUT_1);
}
}
events.ScheduleEvent(EVENT_AFFLICTION, 10s);
break;
case EVENT_FRENZY:
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 10s, 15s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
// Enrage if not already enraged and below 20%
if (!Enraged && HealthBelowPct(20))
{
DoCast(me, SPELL_ENRAGE);
Enraged = true;
}
DoMeleeAttackIfReady();
} }
private: // Enrage if not already enraged and below 20%
std::list<uint32> _breathSpells; if (!Enraged && HealthBelowPct(20))
bool Enraged; {
ObjectGuid _playerGUID; DoCast(me, SPELL_ENRAGE);
}; Enraged = true;
}
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetBlackwingLairAI<boss_chromaggusAI>(creature);
} }
private:
std::list<uint32> _breathSpells;
bool Enraged;
ObjectGuid _playerGUID;
}; };
class go_chromaggus_lever : public GameObjectScript struct go_chromaggus_lever : public GameObjectAI
{ {
public: go_chromaggus_lever(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { }
go_chromaggus_lever() : GameObjectScript("go_chromaggus_lever") { }
struct go_chromaggus_leverAI : public GameObjectAI bool GossipHello(Player* player, bool reportUse) override
{
if (reportUse)
{ {
go_chromaggus_leverAI(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { } if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS)
bool GossipHello(Player* player, bool reportUse) override
{ {
if (reportUse) if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS))
{ {
if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS) creature->SetHomePosition(homePos);
{ creature->GetMotionMaster()->MoveWaypoint(creature->GetEntry() * 10, false);
if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS)) creature->AI()->SetGUID(player->GetGUID(), GUID_LEVER_USER);
{
creature->SetHomePosition(homePos);
creature->GetMotionMaster()->MoveWaypoint(creature->GetEntry() * 10, false);
creature->AI()->SetGUID(player->GetGUID(), GUID_LEVER_USER);
}
if (GameObject* go = _instance->GetGameObject(DATA_GO_CHROMAGGUS_DOOR))
_instance->HandleGameObject(ObjectGuid::Empty, true, go);
}
me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_IN_USE);
me->SetGoState(GO_STATE_ACTIVE);
} }
return true; if (GameObject* go = _instance->GetGameObject(DATA_GO_CHROMAGGUS_DOOR))
_instance->HandleGameObject(ObjectGuid::Empty, true, go);
} }
private: me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_IN_USE);
InstanceScript* _instance; me->SetGoState(GO_STATE_ACTIVE);
};
GameObjectAI* GetAI(GameObject* go) const override
{
return GetBlackwingLairAI<go_chromaggus_leverAI>(go);
} }
return true;
}
private:
InstanceScript* _instance;
}; };
enum ElementalShieldSpells enum ElementalShieldSpells
@@ -306,9 +274,7 @@ class spell_gen_elemental_shield : public SpellScript
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{ {
for (uint32 spell = SPELL_FIRE_ELEMENTAL_SHIELD; spell <= SPELL_ARCANE_ELEMENTAL_SHIELD; ++spell) for (uint32 spell = SPELL_FIRE_ELEMENTAL_SHIELD; spell <= SPELL_ARCANE_ELEMENTAL_SHIELD; ++spell)
{
caster->RemoveAurasDueToSpell(spell); caster->RemoveAurasDueToSpell(spell);
}
caster->CastSpell(caster, SPELL_FIRE_ELEMENTAL_SHIELD + urand(0, 4), true); caster->CastSpell(caster, SPELL_FIRE_ELEMENTAL_SHIELD + urand(0, 4), true);
} }
@@ -341,9 +307,7 @@ class spell_gen_brood_power : public SpellScript
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{ {
for (uint32 spell = SPELL_RED_BROOD_POWER; spell <= SPELL_GREEN_BROOD_POWER; ++spell) for (uint32 spell = SPELL_RED_BROOD_POWER; spell <= SPELL_GREEN_BROOD_POWER; ++spell)
{
caster->RemoveAurasDueToSpell(spell); caster->RemoveAurasDueToSpell(spell);
}
caster->CastSpell(caster, RAND(SPELL_RED_BROOD_POWER, SPELL_BLUE_BROOD_POWER, SPELL_BRONZE_BROOD_POWER, SPELL_BLACK_BROOD_POWER, SPELL_GREEN_BROOD_POWER), true); caster->CastSpell(caster, RAND(SPELL_RED_BROOD_POWER, SPELL_BLUE_BROOD_POWER, SPELL_BRONZE_BROOD_POWER, SPELL_BLACK_BROOD_POWER, SPELL_GREEN_BROOD_POWER), true);
} }
@@ -357,8 +321,8 @@ class spell_gen_brood_power : public SpellScript
void AddSC_boss_chromaggus() void AddSC_boss_chromaggus()
{ {
new boss_chromaggus(); RegisterBlackwingLairCreatureAI(boss_chromaggus);
new go_chromaggus_lever(); RegisterBlackwingLairGameObjectAI(go_chromaggus_lever);
RegisterSpellScript(spell_gen_elemental_shield); RegisterSpellScript(spell_gen_elemental_shield);
RegisterSpellScript(spell_gen_brood_power); RegisterSpellScript(spell_gen_brood_power);
} }

View File

@@ -33,82 +33,69 @@ enum Events
EVENT_SHADOWOFEBONROC = 3 EVENT_SHADOWOFEBONROC = 3
}; };
class boss_ebonroc : public CreatureScript struct boss_ebonroc : public BossAI
{ {
public: boss_ebonroc(Creature* creature) : BossAI(creature, DATA_EBONROC) { }
boss_ebonroc() : CreatureScript("boss_ebonroc") { }
struct boss_ebonrocAI : public BossAI void MovementInform(uint32 type, uint32 id) override
{ {
boss_ebonrocAI(Creature* creature) : BossAI(creature, DATA_EBONROC) { } if (type != WAYPOINT_MOTION_TYPE || id != 13)
return;
void MovementInform(uint32 type, uint32 id) override me->GetMotionMaster()->MoveRandom(10.f);
me->m_Events.AddEventAtOffset([this]()
{ {
if (type != WAYPOINT_MOTION_TYPE || id != 13) me->GetMotionMaster()->Initialize();
}, 15s);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SHADOWFLAME, 18s);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s);
}
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)
{ {
return; case EVENT_SHADOWFLAME:
DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
break;
case EVENT_WINGBUFFET:
DoCastVictim(SPELL_WINGBUFFET);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
case EVENT_SHADOWOFEBONROC:
DoCastVictim(SPELL_SHADOWOFEBONROC);
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s);
break;
} }
me->GetMotionMaster()->MoveRandom(10.f);
me->m_Events.AddEventAtOffset([this]()
{
me->GetMotionMaster()->Initialize();
}, 15s);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SHADOWFLAME, 18s);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOWFLAME:
DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
break;
case EVENT_WINGBUFFET:
DoCastVictim(SPELL_WINGBUFFET);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
case EVENT_SHADOWOFEBONROC:
DoCastVictim(SPELL_SHADOWOFEBONROC);
events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
} }
};
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetBlackwingLairAI<boss_ebonrocAI>(creature);
} }
}; };
void AddSC_boss_ebonroc() void AddSC_boss_ebonroc()
{ {
new boss_ebonroc(); RegisterBlackwingLairCreatureAI(boss_ebonroc);
} }

View File

@@ -33,69 +33,58 @@ enum Events
EVENT_FLAMEBUFFET = 3 EVENT_FLAMEBUFFET = 3
}; };
class boss_firemaw : public CreatureScript struct boss_firemaw : public BossAI
{ {
public: boss_firemaw(Creature* creature) : BossAI(creature, DATA_FIREMAW) { }
boss_firemaw() : CreatureScript("boss_firemaw") { }
struct boss_firemawAI : public BossAI void JustEngagedWith(Unit* who) override
{ {
boss_firemawAI(Creature* creature) : BossAI(creature, DATA_FIREMAW) { } BossAI::JustEngagedWith(who);
void JustEngagedWith(Unit* who) override events.ScheduleEvent(EVENT_SHADOWFLAME, 18s);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
BossAI::JustEngagedWith(who); switch (eventId)
{
events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); case EVENT_SHADOWFLAME:
events.ScheduleEvent(EVENT_WINGBUFFET, 30s); DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s); events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
} break;
case EVENT_WINGBUFFET:
void UpdateAI(uint32 diff) override DoCastVictim(SPELL_WINGBUFFET);
{ if (DoGetThreat(me->GetVictim()))
if (!UpdateVictim()) DoModifyThreatByPercent(me->GetVictim(), -75);
return; events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
events.Update(diff); case EVENT_FLAMEBUFFET:
DoCastVictim(SPELL_FLAMEBUFFET);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOWFLAME:
DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
break;
case EVENT_WINGBUFFET:
DoCastVictim(SPELL_WINGBUFFET);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatByPercent(me->GetVictim(), -75);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
case EVENT_FLAMEBUFFET:
DoCastVictim(SPELL_FLAMEBUFFET);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
} }
};
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetBlackwingLairAI<boss_firemawAI>(creature);
} }
}; };
void AddSC_boss_firemaw() void AddSC_boss_firemaw()
{ {
new boss_firemaw(); RegisterBlackwingLairCreatureAI(boss_firemaw);
} }

View File

@@ -38,70 +38,59 @@ enum Events
EVENT_FRENZY = 3 EVENT_FRENZY = 3
}; };
class boss_flamegor : public CreatureScript struct boss_flamegor : public BossAI
{ {
public: boss_flamegor(Creature* creature) : BossAI(creature, DATA_FLAMEGOR) { }
boss_flamegor() : CreatureScript("boss_flamegor") { }
struct boss_flamegorAI : public BossAI void JustEngagedWith(Unit* who) override
{ {
boss_flamegorAI(Creature* creature) : BossAI(creature, DATA_FLAMEGOR) { } BossAI::JustEngagedWith(who);
void JustEngagedWith(Unit* who) override events.ScheduleEvent(EVENT_SHADOWFLAME, 18s);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
events.ScheduleEvent(EVENT_FRENZY, 10s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
BossAI::JustEngagedWith(who); switch (eventId)
{
events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); case EVENT_SHADOWFLAME:
events.ScheduleEvent(EVENT_WINGBUFFET, 30s); DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_FRENZY, 10s); events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
} break;
case EVENT_WINGBUFFET:
void UpdateAI(uint32 diff) override DoCastVictim(SPELL_WINGBUFFET);
{ if (DoGetThreat(me->GetVictim()))
if (!UpdateVictim()) DoModifyThreatByPercent(me->GetVictim(), -75);
return; events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
events.Update(diff); case EVENT_FRENZY:
Talk(EMOTE_FRENZY);
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 8s, 10s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOWFLAME:
DoCastVictim(SPELL_SHADOWFLAME);
events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s);
break;
case EVENT_WINGBUFFET:
DoCastVictim(SPELL_WINGBUFFET);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatByPercent(me->GetVictim(), -75);
events.ScheduleEvent(EVENT_WINGBUFFET, 30s);
break;
case EVENT_FRENZY:
Talk(EMOTE_FRENZY);
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 8s, 10s);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
} }
};
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetBlackwingLairAI<boss_flamegorAI>(creature);
} }
}; };
void AddSC_boss_flamegor() void AddSC_boss_flamegor()
{ {
new boss_flamegor(); RegisterBlackwingLairCreatureAI(boss_flamegor);
} }

View File

@@ -214,14 +214,10 @@ struct ClassCallSelector : public Acore::unary_function<Unit*, bool>
bool operator()(Unit const* target) const bool operator()(Unit const* target) const
{ {
if (!_me || !target || !target->IsPlayer()) if (!_me || !target || !target->IsPlayer())
{
return false; return false;
}
if (target->getClass() != _targetClass) if (target->getClass() != _targetClass)
{
return false; return false;
}
return true; return true;
} }
@@ -231,304 +227,291 @@ private:
uint8 _targetClass; uint8 _targetClass;
}; };
class boss_victor_nefarius : public CreatureScript struct boss_victor_nefarius : public BossAI
{ {
public: boss_victor_nefarius(Creature* creature) : BossAI(creature, DATA_NEFARIAN)
boss_victor_nefarius() : CreatureScript("boss_victor_nefarius") { }
struct boss_victor_nefariusAI : public BossAI
{ {
boss_victor_nefariusAI(Creature* creature) : BossAI(creature, DATA_NEFARIAN) Initialize();
_nefarianLeftTunnel = instance->GetData(DATA_NEFARIAN_LEFT_TUNNEL);
_nefarianRightTunnel = instance->GetData(DATA_NEFARIAN_RIGHT_TUNNEL);
if (!_nefarianLeftTunnel || !_nefarianRightTunnel)
{ {
Initialize(); // Victor Nefarius weekly mechanic drakonid spawn
// Pick 2 drakonids and keep them for the whole save duration (the drakonids can't be repeated).
std::vector<uint32> nefarianDrakonidSpawners = { NPC_BLACK_SPAWNER, NPC_BLUE_SPAWNER, NPC_BRONZE_SPAWNER, NPC_GREEN_SPAWNER, NPC_RED_SPAWNER };
Acore::Containers::RandomResize(nefarianDrakonidSpawners, 2);
_nefarianLeftTunnel = instance->GetData(DATA_NEFARIAN_LEFT_TUNNEL); _nefarianRightTunnel = nefarianDrakonidSpawners[0];
_nefarianRightTunnel = instance->GetData(DATA_NEFARIAN_RIGHT_TUNNEL); _nefarianLeftTunnel = nefarianDrakonidSpawners[1];
if (!_nefarianLeftTunnel || !_nefarianRightTunnel) // save it to instance
{ instance->SetData(DATA_NEFARIAN_LEFT_TUNNEL, _nefarianLeftTunnel);
// Victor Nefarius weekly mechanic drakonid spawn instance->SetData(DATA_NEFARIAN_RIGHT_TUNNEL, _nefarianRightTunnel);
// Pick 2 drakonids and keep them for the whole save duration (the drakonids can't be repeated).
std::vector<uint32> nefarianDrakonidSpawners = { NPC_BLACK_SPAWNER, NPC_BLUE_SPAWNER, NPC_BRONZE_SPAWNER, NPC_GREEN_SPAWNER, NPC_RED_SPAWNER };
Acore::Containers::RandomResize(nefarianDrakonidSpawners, 2);
_nefarianRightTunnel = nefarianDrakonidSpawners[0];
_nefarianLeftTunnel = nefarianDrakonidSpawners[1];
// save it to instance
instance->SetData(DATA_NEFARIAN_LEFT_TUNNEL, _nefarianLeftTunnel);
instance->SetData(DATA_NEFARIAN_RIGHT_TUNNEL, _nefarianRightTunnel);
}
} }
}
void Initialize() void Initialize()
{
_killedAdds = 0;
}
void Reset() override
{
Initialize();
if (me->GetMapId() == MAP_BLACKWING_LAIR)
{ {
KilledAdds = 0; if (Creature* nefarian = me->FindNearestCreature(NPC_NEFARIAN, 1000.0f, true))
}
void Reset() override
{
Initialize();
if (me->GetMapId() == MAP_BLACKWING_LAIR)
{ {
if (Creature* nefarian = me->FindNearestCreature(NPC_NEFARIAN, 1000.0f, true)) // Nefarian is spawned and he didn't finish his intro path yet, despawn it manually.
if (nefarian->GetMotionMaster()->GetCurrentMovementGeneratorType() == MovementGeneratorType::WAYPOINT_MOTION_TYPE)
{ {
// Nefarian is spawned and he didn't finish his intro path yet, despawn it manually. nefarian->DespawnOrUnsummon();
if (nefarian->GetMotionMaster()->GetCurrentMovementGeneratorType() == MovementGeneratorType::WAYPOINT_MOTION_TYPE)
{
nefarian->DespawnOrUnsummon();
}
std::list<GameObject*> drakonidBones;
me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& bones : drakonidBones)
{
bones->DespawnOrUnsummon();
}
} }
else std::list<GameObject*> drakonidBones;
me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& bones : drakonidBones)
{ {
_Reset(); bones->DespawnOrUnsummon();
}
me->SetVisible(true);
me->SetPhaseMask(1, true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_FRIENDLY);
me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR);
me->RemoveAura(SPELL_NEFARIANS_BARRIER);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
}
void JustReachedHome() override
{
Reset();
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_NEFARIAN)
{
BossAI::JustSummoned(summon);
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override
{
if (summon->GetEntry() == NPC_NEFARIAN)
{
summons.DespawnEntry(_nefarianLeftTunnel);
summons.DespawnEntry(_nefarianRightTunnel);
me->KillSelf();
}
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET)
{
me->RemoveAura(SPELL_ROOT_SELF);
summons.DespawnAll();
}
if (action == ACTION_ADD_KILLED)
{
KilledAdds++;
if (KilledAdds == MAX_DRAKONID_KILLED)
{
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn))
{
nefarian->setActive(true);
nefarian->SetCanFly(true);
nefarian->SetDisableGravity(true);
nefarian->GetMotionMaster()->MoveWaypoint(NEFARIAN_PATH, false);
}
events.Reset();
DoCastSelf(SPELL_ROOT_SELF, true);
me->SetVisible(false);
// Stop spawning adds
EntryCheckPredicate pred(_nefarianRightTunnel);
summons.DoAction(ACTION_SPAWNER_STOP, pred);
EntryCheckPredicate pred2(_nefarianLeftTunnel);
summons.DoAction(ACTION_SPAWNER_STOP, pred2);
} }
} }
} else
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_NEFARIAN, DONE);
instance->SaveToDB();
}
void BeginEvent()
{
_JustEngagedWith();
Talk(SAY_GAMESBEGIN_2);
DoCast(me, SPELL_NEFARIANS_BARRIER);
me->SetCombatMovement(false);
me->SetImmuneToPC(false);
AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 13s, 15s);
events.ScheduleEvent(EVENT_FEAR, 10s, 20s);
events.ScheduleEvent(EVENT_SILENCE, 20s, 25s);
events.ScheduleEvent(EVENT_MIND_CONTROL, 30s, 35s);
events.ScheduleEvent(EVENT_SPAWN_ADDS, 10s);
}
void SetData(uint32 type, uint32 data) override
{
if (type == 1 && data == 1)
{ {
me->StopMoving(); _Reset();
events.ScheduleEvent(EVENT_PATH_2, 9s);
} }
if (type == 1 && data == 2) me->SetVisible(true);
events.ScheduleEvent(EVENT_SUCCESS_1, 5s); me->SetPhaseMask(1, true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_FRIENDLY);
me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR);
me->RemoveAura(SPELL_NEFARIANS_BARRIER);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
}
void JustReachedHome() override
{
Reset();
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_NEFARIAN)
BossAI::JustSummoned(summon);
}
void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override
{
if (summon->GetEntry() == NPC_NEFARIAN)
{
summons.DespawnEntry(_nefarianLeftTunnel);
summons.DespawnEntry(_nefarianRightTunnel);
me->KillSelf();
}
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET)
{
me->RemoveAura(SPELL_ROOT_SELF);
summons.DespawnAll();
} }
void UpdateAI(uint32 diff) override if (action == ACTION_ADD_KILLED)
{ {
if (!UpdateVictim()) _killedAdds++;
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent()) if (_killedAdds == MAX_DRAKONID_KILLED)
{
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn))
{ {
switch (eventId) nefarian->setActive(true);
{ nefarian->SetCanFly(true);
case EVENT_PATH_2: nefarian->SetDisableGravity(true);
me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_2, false); nefarian->GetMotionMaster()->MoveWaypoint(NEFARIAN_PATH, false);
events.ScheduleEvent(EVENT_CHAOS_1, 7s);
break;
case EVENT_CHAOS_1:
if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 75.0f, true))
{
me->SetFacingToObject(gyth);
Talk(SAY_CHAOS_SPELL);
}
events.ScheduleEvent(EVENT_CHAOS_2, 2s);
break;
case EVENT_CHAOS_2:
DoCast(SPELL_CHROMATIC_CHAOS);
me->SetFacingTo(1.570796f);
break;
case EVENT_SUCCESS_1:
if (Unit* player = me->SelectNearestPlayer(60.0f))
{
me->SetFacingToObject(player);
Talk(SAY_SUCCESS);
if (GameObject* portcullis1 = me->FindNearestGameObject(GO_PORTCULLIS_ACTIVE, 65.0f))
portcullis1->SetGoState(GO_STATE_ACTIVE);
if (GameObject* portcullis2 = me->FindNearestGameObject(GO_PORTCULLIS_TOBOSSROOMS, 80.0f))
portcullis2->SetGoState(GO_STATE_ACTIVE);
}
events.ScheduleEvent(EVENT_SUCCESS_2, 4s);
break;
case EVENT_SUCCESS_2:
DoCast(me, SPELL_VAELASTRASZZ_SPAWN);
me->DespawnOrUnsummon(1s);
break;
case EVENT_PATH_3:
me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_3, false);
break;
case EVENT_START_EVENT:
BeginEvent();
break;
default:
break;
}
} }
events.Reset();
DoCastSelf(SPELL_ROOT_SELF, true);
me->SetVisible(false);
// Stop spawning adds
EntryCheckPredicate pred(_nefarianRightTunnel);
summons.DoAction(ACTION_SPAWNER_STOP, pred);
EntryCheckPredicate pred2(_nefarianLeftTunnel);
summons.DoAction(ACTION_SPAWNER_STOP, pred2);
}
}
}
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_NEFARIAN, DONE);
instance->SaveToDB();
}
void BeginEvent()
{
_JustEngagedWith();
Talk(SAY_GAMESBEGIN_2);
DoCast(me, SPELL_NEFARIANS_BARRIER);
me->SetCombatMovement(false);
me->SetImmuneToPC(false);
AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 13s, 15s);
events.ScheduleEvent(EVENT_FEAR, 10s, 20s);
events.ScheduleEvent(EVENT_SILENCE, 20s, 25s);
events.ScheduleEvent(EVENT_MIND_CONTROL, 30s, 35s);
events.ScheduleEvent(EVENT_SPAWN_ADDS, 10s);
}
void SetData(uint32 type, uint32 data) override
{
if (type == 1 && data == 1)
{
me->StopMoving();
events.ScheduleEvent(EVENT_PATH_2, 9s);
}
if (type == 1 && data == 2)
events.ScheduleEvent(EVENT_SUCCESS_1, 5s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_PATH_2:
me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_2, false);
events.ScheduleEvent(EVENT_CHAOS_1, 7s);
break;
case EVENT_CHAOS_1:
if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 75.0f, true))
{
me->SetFacingToObject(gyth);
Talk(SAY_CHAOS_SPELL);
}
events.ScheduleEvent(EVENT_CHAOS_2, 2s);
break;
case EVENT_CHAOS_2:
DoCast(SPELL_CHROMATIC_CHAOS);
me->SetFacingTo(1.570796f);
break;
case EVENT_SUCCESS_1:
if (Unit* player = me->SelectNearestPlayer(60.0f))
{
me->SetFacingToObject(player);
Talk(SAY_SUCCESS);
if (GameObject* portcullis1 = me->FindNearestGameObject(GO_PORTCULLIS_ACTIVE, 65.0f))
portcullis1->SetGoState(GO_STATE_ACTIVE);
if (GameObject* portcullis2 = me->FindNearestGameObject(GO_PORTCULLIS_TOBOSSROOMS, 80.0f))
portcullis2->SetGoState(GO_STATE_ACTIVE);
}
events.ScheduleEvent(EVENT_SUCCESS_2, 4s);
break;
case EVENT_SUCCESS_2:
DoCast(me, SPELL_VAELASTRASZZ_SPAWN);
me->DespawnOrUnsummon(1s);
break;
case EVENT_PATH_3:
me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_3, false);
break;
case EVENT_START_EVENT:
BeginEvent();
break;
default:
break;
}
}
return;
}
// Only do this if we haven't spawned nefarian yet
if (UpdateVictim() && _killedAdds <= MAX_DRAKONID_KILLED)
{
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
}
// Only do this if we haven't spawned nefarian yet while (uint32 eventId = events.ExecuteEvent())
if (UpdateVictim() && KilledAdds <= MAX_DRAKONID_KILLED)
{ {
events.Update(diff); switch (eventId)
{
case EVENT_SHADOW_BOLT:
DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2s, 4s);
break;
case EVENT_SHADOW_BOLT_VOLLEY:
DoCastAOE(SPELL_SHADOWBOLT_VOLLEY);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 19s, 25s);
break;
case EVENT_FEAR:
DoCastRandomTarget(SPELL_FEAR, 0, 40.0f);
events.ScheduleEvent(EVENT_FEAR, 10s, 20s);
break;
case EVENT_SILENCE:
DoCastRandomTarget(SPELL_SILENCE, 0, 150.f);
events.ScheduleEvent(EVENT_SILENCE, 14s,23s);
break;
case EVENT_MIND_CONTROL:
DoCastRandomTarget(SPELL_SHADOW_COMMAND, 0, 40.0f);
events.ScheduleEvent(EVENT_MIND_CONTROL, 24s, 30s);
break;
case EVENT_SHADOWBLINK:
DoCastSelf(SPELL_SHADOWBLINK);
events.ScheduleEvent(EVENT_SHADOWBLINK, 30s, 40s);
break;
case EVENT_SPAWN_ADDS:
// Spawn the spawners.
me->SummonCreature(_nefarianLeftTunnel, spawnerPositions[0]);
me->SummonCreature(_nefarianRightTunnel, spawnerPositions[1]);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOW_BOLT:
DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2s, 4s);
break;
case EVENT_SHADOW_BOLT_VOLLEY:
DoCastAOE(SPELL_SHADOWBOLT_VOLLEY);
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 19s, 25s);
break;
case EVENT_FEAR:
DoCastRandomTarget(SPELL_FEAR, 0, 40.0f);
events.ScheduleEvent(EVENT_FEAR, 10s, 20s);
break;
case EVENT_SILENCE:
DoCastRandomTarget(SPELL_SILENCE, 0, 150.f);
events.ScheduleEvent(EVENT_SILENCE, 14s,23s);
break;
case EVENT_MIND_CONTROL:
DoCastRandomTarget(SPELL_SHADOW_COMMAND, 0, 40.0f);
events.ScheduleEvent(EVENT_MIND_CONTROL, 24s, 30s);
break;
case EVENT_SHADOWBLINK:
DoCastSelf(SPELL_SHADOWBLINK);
events.ScheduleEvent(EVENT_SHADOWBLINK, 30s, 40s);
break;
case EVENT_SPAWN_ADDS:
// Spawn the spawners.
me->SummonCreature(_nefarianLeftTunnel, spawnerPositions[0]);
me->SummonCreature(_nefarianRightTunnel, spawnerPositions[1]);
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
} }
} }
void sGossipSelect(Player* player, uint32 sender, uint32 action) override
{
if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID)
{
// pussywizard:
InstanceScript* instance = player->GetInstanceScript();
if (!instance || instance->GetBossState(DATA_NEFARIAN) == DONE)
return;
CloseGossipMenuFor(player);
Talk(SAY_GAMESBEGIN_1);
events.ScheduleEvent(EVENT_START_EVENT, 4s);
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(true);
}
}
private:
uint32 KilledAdds;
uint32 _nefarianRightTunnel;
uint32 _nefarianLeftTunnel;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_victor_nefariusAI>(creature);
} }
void sGossipSelect(Player* player, uint32 sender, uint32 action) override
{
if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID)
{
// pussywizard:
InstanceScript* instance = player->GetInstanceScript();
if (!instance || instance->GetBossState(DATA_NEFARIAN) == DONE)
return;
CloseGossipMenuFor(player);
Talk(SAY_GAMESBEGIN_1);
events.ScheduleEvent(EVENT_START_EVENT, 4s);
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(true);
}
}
private:
uint32 _killedAdds;
uint32 _nefarianRightTunnel;
uint32 _nefarianLeftTunnel;
}; };
struct boss_nefarian : public BossAI struct boss_nefarian : public BossAI
@@ -545,12 +528,8 @@ struct boss_nefarian : public BossAI
{ {
_Reset(); _Reset();
if (Creature* victor = me->FindNearestCreature(NPC_VICTOR_NEFARIUS, 200.f, true)) if (Creature* victor = me->FindNearestCreature(NPC_VICTOR_NEFARIUS, 200.f, true))
{
if (victor->AI()) if (victor->AI())
{
victor->AI()->DoAction(ACTION_RESET); victor->AI()->DoAction(ACTION_RESET);
}
}
me->DespawnOrUnsummon(); me->DespawnOrUnsummon();
} }
@@ -578,9 +557,7 @@ struct boss_nefarian : public BossAI
void KilledUnit(Unit* victim) override void KilledUnit(Unit* victim) override
{ {
if (rand32() % 5) if (rand32() % 5)
{
return; return;
}
Talk(SAY_SLAY, victim); Talk(SAY_SLAY, victim);
} }
@@ -588,14 +565,10 @@ struct boss_nefarian : public BossAI
void MovementInform(uint32 type, uint32 id) override void MovementInform(uint32 type, uint32 id) override
{ {
if (type != WAYPOINT_MOTION_TYPE) if (type != WAYPOINT_MOTION_TYPE)
{
return; return;
}
if (id == 4) if (id == 4)
{
Talk(SAY_INTRO); Talk(SAY_INTRO);
}
if (id == 6) if (id == 6)
{ {
@@ -617,9 +590,7 @@ struct boss_nefarian : public BossAI
me->SetReactState(REACT_AGGRESSIVE); me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat(); DoZoneInCombat();
if (me->GetVictim()) if (me->GetVictim())
{
AttackStart(me->GetVictim()); AttackStart(me->GetVictim());
}
events.ScheduleEvent(EVENT_SHADOWFLAME, 12s); events.ScheduleEvent(EVENT_SHADOWFLAME, 12s);
events.ScheduleEvent(EVENT_FEAR, 25s, 35s); events.ScheduleEvent(EVENT_FEAR, 25s, 35s);
@@ -633,16 +604,12 @@ struct boss_nefarian : public BossAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
@@ -671,16 +638,10 @@ struct boss_nefarian : public BossAI
break; break;
case EVENT_CLASSCALL: case EVENT_CLASSCALL:
if (classesPresent.empty()) if (classesPresent.empty())
{
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList()) for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* victim = ref->GetVictim()) if (Unit* victim = ref->GetVictim())
{
if (victim->IsPlayer()) if (victim->IsPlayer())
classesPresent.insert(victim->getClass()); classesPresent.insert(victim->getClass());
}
}
}
uint8 targetClass = Acore::Containers::SelectRandomContainerElement(classesPresent); uint8 targetClass = Acore::Containers::SelectRandomContainerElement(classesPresent);
@@ -731,9 +692,7 @@ struct boss_nefarian : public BossAI
me->GetMap()->DoForAllPlayers([&](Player* p) me->GetMap()->DoForAllPlayers([&](Player* p)
{ {
if (!p->IsGameMaster()) if (!p->IsGameMaster())
{
me->CastSpell(p, SPELL_DEATH_KNIGHT, true); me->CastSpell(p, SPELL_DEATH_KNIGHT, true);
}
}); });
break; break;
default: default:
@@ -745,9 +704,7 @@ struct boss_nefarian : public BossAI
} }
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
@@ -783,9 +740,7 @@ struct npc_corrupted_totem : public ScriptedAI
{ {
me->AddUnitState(UNIT_STATE_ROOT); me->AddUnitState(UNIT_STATE_ROOT);
if (!me->HasAura(SPELL_ROOT_SELF)) if (!me->HasAura(SPELL_ROOT_SELF))
{
me->AddAura(SPELL_ROOT_SELF, me); me->AddAura(SPELL_ROOT_SELF, me);
}
me->AddAura(AURA_AVOIDANCE, me); me->AddAura(AURA_AVOIDANCE, me);
scheduler.CancelAll(); scheduler.CancelAll();
@@ -809,9 +764,7 @@ struct npc_corrupted_totem : public ScriptedAI
} }
if (!spellId) if (!spellId)
{
return; return;
}
std::vector<uint32> mobsEntries = std::vector<uint32> mobsEntries =
{ {
@@ -835,25 +788,19 @@ struct npc_corrupted_totem : public ScriptedAI
tmpMobList.pop_front(); tmpMobList.pop_front();
if (!curr->IsAlive()) if (!curr->IsAlive())
{
continue; continue;
}
if (apply && me->IsAlive()) if (apply && me->IsAlive())
{ {
if (me->IsWithinDistInMap(curr, 40.f)) if (me->IsWithinDistInMap(curr, 40.f))
{ {
if (!curr->HasAura(spellId)) if (!curr->HasAura(spellId))
{
curr->AddAura(spellId, curr); curr->AddAura(spellId, curr);
}
} }
else else
{ {
if (curr->HasAura(spellId)) if (curr->HasAura(spellId))
{
curr->RemoveAurasDueToSpell(spellId); curr->RemoveAurasDueToSpell(spellId);
}
} }
} }
else else
@@ -899,9 +846,7 @@ struct npc_corrupted_totem : public ScriptedAI
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (me->GetEntry() != NPC_TOTEM_C_FIRE_NOVA) if (me->GetEntry() != NPC_TOTEM_C_FIRE_NOVA)
{
SetAura(false); SetAura(false);
}
scheduler.CancelAll(); scheduler.CancelAll();
} }
@@ -909,9 +854,7 @@ struct npc_corrupted_totem : public ScriptedAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
scheduler.Update(diff); scheduler.Update(diff);
} }
@@ -952,9 +895,7 @@ struct npc_drakonid_spawner : public ScriptedAI
void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override
{ {
if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner)) if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner))
{
victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED); victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED);
}
ObjectGuid summonGuid = summon->GetGUID(); ObjectGuid summonGuid = summon->GetGUID();
@@ -1002,15 +943,11 @@ class spell_class_call_handler : public SpellScript
{ {
Player const* player = target->ToPlayer(); Player const* player = target->ToPlayer();
if (!player || player->IsClass(CLASS_DEATH_KNIGHT)) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x if (!player || player->IsClass(CLASS_DEATH_KNIGHT)) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x
{
return true; return true;
}
auto it = classCallSpells.find(spellInfo->Id); auto it = classCallSpells.find(spellInfo->Id);
if (it != classCallSpells.end()) // should never happen but only to be sure. if (it != classCallSpells.end()) // should never happen but only to be sure.
{
return target->ToPlayer()->getClass() != it->second; return target->ToPlayer()->getClass() != it->second;
}
return false; return false;
}); });
@@ -1022,9 +959,7 @@ class spell_class_call_handler : public SpellScript
Unit* caster = GetCaster(); Unit* caster = GetCaster();
Unit* target = GetHitUnit(); Unit* target = GetHitUnit();
if (!caster || !target) if (!caster || !target)
{
return; return;
}
Position tp = caster->GetFirstCollisionPosition(5.f, 0.f); Position tp = caster->GetFirstCollisionPosition(5.f, 0.f);
target->NearTeleportTo(tp.GetPositionX(), tp.GetPositionY(), tp.GetPositionZ(), tp.GetOrientation()); target->NearTeleportTo(tp.GetPositionX(), tp.GetPositionY(), tp.GetPositionZ(), tp.GetOrientation());
@@ -1033,9 +968,7 @@ class spell_class_call_handler : public SpellScript
void HandleOnHitWarlock() void HandleOnHitWarlock()
{ {
if (Unit* target = GetHitUnit()) if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_SUMMON_INFERNALS, true); target->CastSpell(target, SPELL_SUMMON_INFERNALS, true);
}
} }
void Register() override void Register() override
@@ -1065,9 +998,7 @@ class aura_class_call_wild_magic : public AuraScript
void HandlePeriodic(AuraEffect const* /*aurEff*/) void HandlePeriodic(AuraEffect const* /*aurEff*/)
{ {
if (!GetTarget()) if (!GetTarget())
{
return; return;
}
GetTarget()->CastSpell(GetTarget(), SPELL_POLYMORPH, true); GetTarget()->CastSpell(GetTarget(), SPELL_POLYMORPH, true);
} }
@@ -1092,12 +1023,8 @@ class aura_class_call_siphon_blessing : public AuraScript
PreventDefaultAction(); PreventDefaultAction();
if (Unit* target = GetTarget()) if (Unit* target = GetTarget())
{
if (Unit* nefarian = target->FindNearestCreature(NPC_NEFARIAN, 100.f)) if (Unit* nefarian = target->FindNearestCreature(NPC_NEFARIAN, 100.f))
{
target->CastSpell(nefarian, SPELL_BLESSING_PROTECTION, true); target->CastSpell(nefarian, SPELL_BLESSING_PROTECTION, true);
}
}
} }
void Register() override void Register() override
@@ -1154,9 +1081,7 @@ class spell_corrupted_totems : public SpellScript
{ {
PreventHitDefaultEffect(effIndex); PreventHitDefaultEffect(effIndex);
if (!GetCaster()) if (!GetCaster())
{
return; return;
}
std::list<uint32> spellList = { SPELL_CORRUPTED_FIRE_NOVA_TOTEM, SPELL_CORRUPTED_HEALING_TOTEM, SPELL_CORRUPTED_STONESKIN_TOTEM, SPELL_CORRUPTED_WINDFURY_TOTEM }; std::list<uint32> spellList = { SPELL_CORRUPTED_FIRE_NOVA_TOTEM, SPELL_CORRUPTED_HEALING_TOTEM, SPELL_CORRUPTED_STONESKIN_TOTEM, SPELL_CORRUPTED_WINDFURY_TOTEM };
uint32 spellId = Acore::Containers::SelectRandomContainerElement(spellList); uint32 spellId = Acore::Containers::SelectRandomContainerElement(spellList);
@@ -1207,15 +1132,11 @@ class spell_shadowblink : public SpellScript
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
if (!caster || !caster->ToCreature() || !caster->ToCreature()->AI()) if (!caster || !caster->ToCreature() || !caster->ToCreature()->AI())
{
return; return;
}
Unit* target = caster->ToCreature()->AI()->SelectTarget(SelectTargetMethod::Random, 0, 200.f, true); Unit* target = caster->ToCreature()->AI()->SelectTarget(SelectTargetMethod::Random, 0, 200.f, true);
if (!target) if (!target)
{
return; return;
}
for (auto& itr : spellPos) for (auto& itr : spellPos)
{ {
@@ -1252,9 +1173,7 @@ class spell_spawn_drakonid : public SpellScript
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
if (!caster) if (!caster)
{
return; return;
}
caster->CastSpell(caster, spawnerSpells[caster->GetEntry()], true); caster->CastSpell(caster, spawnerSpells[caster->GetEntry()], true);
} }
@@ -1267,7 +1186,7 @@ class spell_spawn_drakonid : public SpellScript
void AddSC_boss_nefarian() void AddSC_boss_nefarian()
{ {
new boss_victor_nefarius(); RegisterBlackwingLairCreatureAI(boss_victor_nefarius);
RegisterCreatureAI(boss_nefarian); RegisterCreatureAI(boss_nefarian);
RegisterCreatureAI(npc_corrupted_totem); RegisterCreatureAI(npc_corrupted_totem);
RegisterCreatureAI(npc_drakonid_spawner); RegisterCreatureAI(npc_drakonid_spawner);

View File

@@ -16,6 +16,8 @@
*/ */
#include "CreatureScript.h" #include "CreatureScript.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h" #include "GameObjectScript.h"
#include "Player.h" #include "Player.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
@@ -70,214 +72,190 @@ enum EVENTS
EVENT_CONFLAGRATION = 4 EVENT_CONFLAGRATION = 4
}; };
class boss_razorgore : public CreatureScript struct boss_razorgore : public BossAI
{ {
public: boss_razorgore(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { }
boss_razorgore() : CreatureScript("boss_razorgore") { }
struct boss_razorgoreAI : public BossAI void Reset() override
{ {
boss_razorgoreAI(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { } _Reset();
_charmerGUID.Clear();
void Reset() override secondPhase = false;
{ summons.DespawnAll();
_Reset(); instance->SetData(DATA_EGG_EVENT, NOT_STARTED);
_charmerGUID.Clear();
secondPhase = false;
summons.DespawnAll();
instance->SetData(DATA_EGG_EVENT, NOT_STARTED);
}
void JustDied(Unit* /*killer*/) override
{
if (secondPhase)
{
_JustDied();
}
else
{
// Respawn shorty in case of failure during phase 1.
me->SetCorpseRemoveTime(25);
me->SetRespawnTime(30);
me->SaveRespawnTime();
// Might not be required, safe measure.
me->SetLootRecipient(nullptr);
instance->SetData(DATA_EGG_EVENT, FAIL);
}
}
bool CanAIAttack(Unit const* target) const override
{
return !(target->IsCreature() && !secondPhase);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_CLEAVE, 15s);
events.ScheduleEvent(EVENT_STOMP, 35s);
events.ScheduleEvent(EVENT_FIREBALL, 7s);
events.ScheduleEvent(EVENT_CONFLAGRATION, 12s);
instance->SetData(DATA_EGG_EVENT, IN_PROGRESS);
}
void DoChangePhase()
{
secondPhase = true;
_charmerGUID.Clear();
me->RemoveAllAuras();
DoCastSelf(SPELL_WARMING_FLAMES, true);
if (Creature* troops = instance->GetCreature(DATA_NEFARIAN_TROOPS))
{
troops->AI()->Talk(EMOTE_TROOPS_RETREAT);
}
for (ObjectGuid const& guid : _summonGUIDS)
{
if (Creature* creature = ObjectAccessor::GetCreature(*me, guid))
{
if (creature->IsAlive())
{
creature->CombatStop(true);
creature->SetReactState(REACT_PASSIVE);
creature->GetMotionMaster()->MovePoint(0, Position(-7560.568848f, -1028.553345f, 408.491211f, 0.523858f));
}
}
}
}
void SetGUID(ObjectGuid const& guid, int32 /*id*/) override
{
_charmerGUID = guid;
}
void OnCharmed(bool apply) override
{
if (apply)
{
if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID))
{
charmer->CastSpell(charmer, SPELL_MIND_EXHAUSTION, true);
charmer->CastSpell(me, SPELL_MINDCONTROL_VISUAL, false);
}
}
else
{
if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID))
{
charmer->RemoveAurasDueToSpell(SPELL_MINDCONTROL_VISUAL);
me->EngageWithTarget(charmer);
me->AddThreat(charmer, 100.0f);
me->AI()->AttackStart(charmer);
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_PHASE_TWO)
{
DoChangePhase();
}
if (action == TALK_EGG_BROKEN_RAND)
{
Talk(urand(SAY_EGGS_BROKEN1, SAY_EGGS_BROKEN3));
}
}
void JustSummoned(Creature* summon) override
{
_summonGUIDS.push_back(summon->GetGUID());
summon->SetOwnerGUID(me->GetGUID());
summons.Summon(summon);
}
void SummonMovementInform(Creature* summon, uint32 movementType, uint32 /*pathId*/) override
{
if (movementType == POINT_MOTION_TYPE)
{
summon->DespawnOrUnsummon();
}
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!secondPhase && damage >= me->GetHealth())
{
Talk(SAY_DEATH);
DoCastAOE(SPELL_EXPLODE_ORB);
DoCastAOE(SPELL_EXPLOSION);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (!me->IsCharmed())
{
events.Update(diff);
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 7s, 10s);
break;
case EVENT_STOMP:
DoCastVictim(SPELL_WARSTOMP);
events.ScheduleEvent(EVENT_STOMP, 15s, 25s);
break;
case EVENT_FIREBALL:
DoCastVictim(SPELL_FIREBALLVOLLEY);
events.ScheduleEvent(EVENT_FIREBALL, 12s, 15s);
break;
case EVENT_CONFLAGRATION:
DoCastVictim(SPELL_CONFLAGRATION);
events.ScheduleEvent(EVENT_CONFLAGRATION, 30s);
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool secondPhase;
ObjectGuid _charmerGUID;
GuidVector _summonGUIDS;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_razorgoreAI>(creature);
} }
void JustDied(Unit* /*killer*/) override
{
if (secondPhase)
{
_JustDied();
}
else
{
// Respawn shorty in case of failure during phase 1.
me->SetCorpseRemoveTime(25);
me->SetRespawnTime(30);
me->SaveRespawnTime();
// Might not be required, safe measure.
me->SetLootRecipient(nullptr);
instance->SetData(DATA_EGG_EVENT, FAIL);
}
}
bool CanAIAttack(Unit const* target) const override
{
return !(target->IsCreature() && !secondPhase);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_CLEAVE, 15s);
events.ScheduleEvent(EVENT_STOMP, 35s);
events.ScheduleEvent(EVENT_FIREBALL, 7s);
events.ScheduleEvent(EVENT_CONFLAGRATION, 12s);
instance->SetData(DATA_EGG_EVENT, IN_PROGRESS);
}
void DoChangePhase()
{
secondPhase = true;
_charmerGUID.Clear();
me->RemoveAllAuras();
DoCastSelf(SPELL_WARMING_FLAMES, true);
if (Creature* troops = instance->GetCreature(DATA_NEFARIAN_TROOPS))
troops->AI()->Talk(EMOTE_TROOPS_RETREAT);
for (ObjectGuid const& guid : _summonGUIDS)
{
if (Creature* creature = ObjectAccessor::GetCreature(*me, guid))
if (creature->IsAlive())
{
creature->CombatStop(true);
creature->SetReactState(REACT_PASSIVE);
creature->GetMotionMaster()->MovePoint(0, Position(-7560.568848f, -1028.553345f, 408.491211f, 0.523858f));
}
}
}
void SetGUID(ObjectGuid const& guid, int32 /*id*/) override
{
_charmerGUID = guid;
}
void OnCharmed(bool apply) override
{
if (apply)
{
if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID))
{
charmer->CastSpell(charmer, SPELL_MIND_EXHAUSTION, true);
charmer->CastSpell(me, SPELL_MINDCONTROL_VISUAL, false);
}
}
else
{
if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID))
{
charmer->RemoveAurasDueToSpell(SPELL_MINDCONTROL_VISUAL);
me->EngageWithTarget(charmer);
me->AddThreat(charmer, 100.0f);
me->AI()->AttackStart(charmer);
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_PHASE_TWO)
DoChangePhase();
if (action == TALK_EGG_BROKEN_RAND)
Talk(urand(SAY_EGGS_BROKEN1, SAY_EGGS_BROKEN3));
}
void JustSummoned(Creature* summon) override
{
_summonGUIDS.push_back(summon->GetGUID());
summon->SetOwnerGUID(me->GetGUID());
summons.Summon(summon);
}
void SummonMovementInform(Creature* summon, uint32 movementType, uint32 /*pathId*/) override
{
if (movementType == POINT_MOTION_TYPE)
summon->DespawnOrUnsummon();
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!secondPhase && damage >= me->GetHealth())
{
Talk(SAY_DEATH);
DoCastAOE(SPELL_EXPLODE_ORB);
DoCastAOE(SPELL_EXPLOSION);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (!me->IsCharmed())
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 7s, 10s);
break;
case EVENT_STOMP:
DoCastVictim(SPELL_WARSTOMP);
events.ScheduleEvent(EVENT_STOMP, 15s, 25s);
break;
case EVENT_FIREBALL:
DoCastVictim(SPELL_FIREBALLVOLLEY);
events.ScheduleEvent(EVENT_FIREBALL, 12s, 15s);
break;
case EVENT_CONFLAGRATION:
DoCastVictim(SPELL_CONFLAGRATION);
events.ScheduleEvent(EVENT_CONFLAGRATION, 30s);
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool secondPhase;
ObjectGuid _charmerGUID;
GuidVector _summonGUIDS;
}; };
class go_orb_of_domination : public GameObjectScript struct go_orb_of_domination : public GameObjectAI
{ {
public: go_orb_of_domination(GameObject* go) : GameObjectAI(go) { }
go_orb_of_domination() : GameObjectScript("go_orb_of_domination") { }
bool OnGossipHello(Player* player, GameObject* go) override bool GossipHello(Player* player, bool /*reportUse*/) override
{ {
if (InstanceScript* instance = go->GetInstanceScript()) if (InstanceScript* instance = me->GetInstanceScript())
if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION) && !player->GetPet()) if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION) && !player->GetPet())
if (Creature* razor = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED))) if (Creature* razor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED)))
{ {
razor->AI()->SetGUID(player->GetGUID()); razor->AI()->SetGUID(player->GetGUID());
razor->Attack(player, true); razor->Attack(player, true);
@@ -294,12 +272,9 @@ class spell_egg_event : public SpellScript
void HandleOnHit() void HandleOnHit()
{ {
if (InstanceScript* instance = GetCaster()->GetInstanceScript()) if (InstanceScript* instance = GetCaster()->GetInstanceScript())
{
instance->SetData(DATA_EGG_EVENT, SPECIAL); instance->SetData(DATA_EGG_EVENT, SPECIAL);
}
if (Creature* razorgore = GetCaster()->ToCreature()) if (Creature* razorgore = GetCaster()->ToCreature())
{
if (GameObject* egg = GetHitGObj()) if (GameObject* egg = GetHitGObj())
{ {
razorgore->AI()->DoAction(TALK_EGG_BROKEN_RAND); razorgore->AI()->DoAction(TALK_EGG_BROKEN_RAND);
@@ -307,7 +282,6 @@ class spell_egg_event : public SpellScript
egg->UseDoorOrButton(10000); egg->UseDoorOrButton(10000);
egg->SetRespawnTime(WEEK); egg->SetRespawnTime(WEEK);
} }
}
} }
void Register() override void Register() override
@@ -318,7 +292,7 @@ class spell_egg_event : public SpellScript
void AddSC_boss_razorgore() void AddSC_boss_razorgore()
{ {
new boss_razorgore(); RegisterBlackwingLairCreatureAI(boss_razorgore);
new go_orb_of_domination(); RegisterBlackwingLairGameObjectAI(go_orb_of_domination);
RegisterSpellScript(spell_egg_event); RegisterSpellScript(spell_egg_event);
} }

View File

@@ -72,227 +72,214 @@ enum Events
EVENT_BURNING_ADRENALINE = 12, EVENT_BURNING_ADRENALINE = 12,
}; };
class boss_vaelastrasz : public CreatureScript struct boss_vaelastrasz : public BossAI
{ {
public: boss_vaelastrasz(Creature* creature) : BossAI(creature, DATA_VAELASTRAZ_THE_CORRUPT)
boss_vaelastrasz() : CreatureScript("boss_vaelastrasz") { }
struct boss_vaelAI : public BossAI
{ {
boss_vaelAI(Creature* creature) : BossAI(creature, DATA_VAELASTRAZ_THE_CORRUPT) Initialize();
}
void Initialize()
{
PlayerGUID.Clear();
HasYelled = false;
_introDone = false;
_burningAdrenalineCast = 0;
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
me->SetFaction(FACTION_FRIENDLY);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void Reset() override
{
_Reset();
me->SetHealth(me->CountPctFromMaxHealth(30));
if (!_introDone)
{ {
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->SetReactState(REACT_PASSIVE);
Initialize(); Initialize();
_eventsIntro.Reset();
} }
else
void Initialize()
{ {
PlayerGUID.Clear();
HasYelled = false; HasYelled = false;
_introDone = false;
_burningAdrenalineCast = 0; _burningAdrenalineCast = 0;
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
me->SetFaction(FACTION_FRIENDLY);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
} }
}
void Reset() override void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
DoCastAOE(SPELL_ESSENCE_OF_THE_RED);
// now drop damage requirement to be able to take loot
me->ResetPlayerDamageReq();
events.ScheduleEvent(EVENT_CLEAVE, 10s);
events.ScheduleEvent(EVENT_FLAME_BREATH, 15s);
events.ScheduleEvent(EVENT_FIRE_NOVA, 5s);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 11s);
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s);
}
void BeginSpeech(Unit* target)
{
PlayerGUID = target->GetGUID();
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_1, 1s);
}
void KilledUnit(Unit* victim) override
{
if (rand32() % 5)
return;
Talk(SAY_KILLTARGET, victim);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
_eventsIntro.Update(diff);
// Speech
if (!_introDone)
{ {
_Reset(); while (uint32 eventId = _eventsIntro.ExecuteEvent())
me->SetHealth(me->CountPctFromMaxHealth(30));
if (!_introDone)
{
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->SetReactState(REACT_PASSIVE);
Initialize();
_eventsIntro.Reset();
}
else
{
HasYelled = false;
_burningAdrenalineCast = 0;
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
DoCastAOE(SPELL_ESSENCE_OF_THE_RED);
// now drop damage requirement to be able to take loot
me->ResetPlayerDamageReq();
events.ScheduleEvent(EVENT_CLEAVE, 10s);
events.ScheduleEvent(EVENT_FLAME_BREATH, 15s);
events.ScheduleEvent(EVENT_FIRE_NOVA, 5s);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 11s);
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s);
}
void BeginSpeech(Unit* target)
{
PlayerGUID = target->GetGUID();
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_1, 1s);
}
void KilledUnit(Unit* victim) override
{
if (rand32() % 5)
return;
Talk(SAY_KILLTARGET, victim);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
_eventsIntro.Update(diff);
// Speech
if (!_introDone)
{
while (uint32 eventId = _eventsIntro.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPEECH_1:
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SummonCreature(NPC_VICTOR_NEFARIUS, aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], aNefariusSpawnLoc[2], aNefariusSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 26000);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_2, 1s);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
break;
case EVENT_SPEECH_2:
if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid))
{
nefarius->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY);
nefarius->Yell(SAY_NEFARIAN_VAEL_INTRO);
nefarius->SetStandState(UNIT_STAND_STATE_STAND);
}
_eventsIntro.ScheduleEvent(EVENT_SPEECH_3, 18s);
break;
case EVENT_SPEECH_3:
if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid))
nefarius->CastSpell(me, SPELL_RED_LIGHTNING, TRIGGERED_NONE);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_4, 2s);
break;
case EVENT_SPEECH_4:
Talk(SAY_LINE1);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_5, 12s);
break;
case EVENT_SPEECH_5:
Talk(SAY_LINE2);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_6, 12s);
break;
case EVENT_SPEECH_6:
Talk(SAY_LINE3);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_7, 17s);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
break;
case EVENT_SPEECH_7:
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
if (PlayerGUID && ObjectAccessor::GetUnit(*me, PlayerGUID))
AttackStart(ObjectAccessor::GetUnit(*me, PlayerGUID));
me->SetReactState(REACT_AGGRESSIVE);
_introDone = true;
break;
}
}
}
if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_CLEAVE: case EVENT_SPEECH_1:
events.ScheduleEvent(EVENT_CLEAVE, 15s); me->SetStandState(UNIT_STAND_STATE_STAND);
DoCastVictim(SPELL_CLEAVE); me->SummonCreature(NPC_VICTOR_NEFARIUS, aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], aNefariusSpawnLoc[2], aNefariusSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 26000);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_2, 1s);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
break; break;
case EVENT_FLAME_BREATH: case EVENT_SPEECH_2:
DoCastVictim(SPELL_FLAME_BREATH); if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid))
events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 14s);
break;
case EVENT_FIRE_NOVA:
DoCastVictim(SPELL_FIRE_NOVA);
events.ScheduleEvent(EVENT_FIRE_NOVA, 3s, 5s);
break;
case EVENT_TAIL_SWEEP:
DoCastAOE(SPELL_TAIL_SWEEP);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 15s);
break;
case EVENT_BURNING_ADRENALINE:
{
if (_burningAdrenalineCast < 2) // It's better to use TaskScheduler for this, but zzz
{ {
//selects a random target that isn't the current victim and is a mana user (selects mana users) but not pets nefarius->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY);
//it also ignores targets who have the aura. We don't want to place the debuff on the same target twice. nefarius->Yell(SAY_NEFARIAN_VAEL_INTRO);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA && !u->HasAura(SPELL_BURNING_ADRENALINE) && u != me->GetVictim(); })) nefarius->SetStandState(UNIT_STAND_STATE_STAND);
{
me->CastSpell(target, SPELL_BURNING_ADRENALINE, true);
}
_burningAdrenalineCast++;
} }
else _eventsIntro.ScheduleEvent(EVENT_SPEECH_3, 18s);
{ break;
me->CastSpell(me->GetVictim(), SPELL_BURNING_ADRENALINE, true); case EVENT_SPEECH_3:
_burningAdrenalineCast = 0; if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid))
} nefarius->CastSpell(me, SPELL_RED_LIGHTNING, TRIGGERED_NONE);
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s); _eventsIntro.ScheduleEvent(EVENT_SPEECH_4, 2s);
break;
case EVENT_SPEECH_4:
Talk(SAY_LINE1);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_5, 12s);
break;
case EVENT_SPEECH_5:
Talk(SAY_LINE2);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_6, 12s);
break;
case EVENT_SPEECH_6:
Talk(SAY_LINE3);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
_eventsIntro.ScheduleEvent(EVENT_SPEECH_7, 17s);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
break;
case EVENT_SPEECH_7:
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
if (PlayerGUID && ObjectAccessor::GetUnit(*me, PlayerGUID))
AttackStart(ObjectAccessor::GetUnit(*me, PlayerGUID));
me->SetReactState(REACT_AGGRESSIVE);
_introDone = true;
break; break;
}
} }
} }
// Yell if hp lower than 15%
if (HealthBelowPct(15) && !HasYelled)
{
Talk(SAY_HALFLIFE);
HasYelled = true;
}
DoMeleeAttackIfReady();
} }
void JustSummoned(Creature* summoned) override if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
if (summoned->GetEntry() == NPC_VICTOR_NEFARIUS) switch (eventId)
{ {
// Set not selectable, so players won't interact with it case EVENT_CLEAVE:
summoned->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); events.ScheduleEvent(EVENT_CLEAVE, 15s);
m_nefariusGuid = summoned->GetGUID(); DoCastVictim(SPELL_CLEAVE);
break;
case EVENT_FLAME_BREATH:
DoCastVictim(SPELL_FLAME_BREATH);
events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 14s);
break;
case EVENT_FIRE_NOVA:
DoCastVictim(SPELL_FIRE_NOVA);
events.ScheduleEvent(EVENT_FIRE_NOVA, 3s, 5s);
break;
case EVENT_TAIL_SWEEP:
DoCastAOE(SPELL_TAIL_SWEEP);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 15s);
break;
case EVENT_BURNING_ADRENALINE:
{
if (_burningAdrenalineCast < 2) // It's better to use TaskScheduler for this, but zzz
{
//selects a random target that isn't the current victim and is a mana user (selects mana users) but not pets
//it also ignores targets who have the aura. We don't want to place the debuff on the same target twice.
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA && !u->HasAura(SPELL_BURNING_ADRENALINE) && u != me->GetVictim(); }))
me->CastSpell(target, SPELL_BURNING_ADRENALINE, true);
_burningAdrenalineCast++;
}
else
{
me->CastSpell(me->GetVictim(), SPELL_BURNING_ADRENALINE, true);
_burningAdrenalineCast = 0;
}
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s);
break;
}
} }
} }
void sGossipSelect(Player* player, uint32 sender, uint32 action) override // Yell if hp lower than 15%
if (HealthBelowPct(15) && !HasYelled)
{ {
if (sender == GOSSIP_ID && action == 0) Talk(SAY_HALFLIFE);
{ HasYelled = true;
CloseGossipMenuFor(player);
BeginSpeech(player);
}
} }
private: DoMeleeAttackIfReady();
ObjectGuid PlayerGUID;
ObjectGuid m_nefariusGuid;
bool HasYelled;
bool _introDone;
EventMap _eventsIntro;
uint8 _burningAdrenalineCast;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_vaelAI>(creature);
} }
void JustSummoned(Creature* summoned) override
{
if (summoned->GetEntry() == NPC_VICTOR_NEFARIUS)
{
// Set not selectable, so players won't interact with it
summoned->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
m_nefariusGuid = summoned->GetGUID();
}
}
void sGossipSelect(Player* player, uint32 sender, uint32 action) override
{
if (sender == GOSSIP_ID && action == 0)
{
CloseGossipMenuFor(player);
BeginSpeech(player);
}
}
private:
ObjectGuid PlayerGUID;
ObjectGuid m_nefariusGuid;
bool HasYelled;
bool _introDone;
EventMap _eventsIntro;
uint8 _burningAdrenalineCast;
}; };
// 18173 - Burning Adrenaline // 18173 - Burning Adrenaline
@@ -308,9 +295,7 @@ class spell_vael_burning_adrenaline : public AuraScript
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
if (!GetTarget()) if (!GetTarget())
{
return; return;
}
// Do the explosion, then kill the target. // Do the explosion, then kill the target.
GetTarget()->CastSpell(GetTarget(), SPELL_BURNING_ADRENALINE_EXPLOSION, true); GetTarget()->CastSpell(GetTarget(), SPELL_BURNING_ADRENALINE_EXPLOSION, true);
@@ -325,6 +310,6 @@ class spell_vael_burning_adrenaline : public AuraScript
void AddSC_boss_vaelastrasz() void AddSC_boss_vaelastrasz()
{ {
new boss_vaelastrasz(); RegisterBlackwingLairCreatureAI(boss_vaelastrasz);
RegisterSpellScript(spell_vael_burning_adrenaline); RegisterSpellScript(spell_vael_burning_adrenaline);
} }

View File

@@ -72,404 +72,355 @@ Position const SummonPosition[8] =
uint32 const Entry[3] = { 12422, 12416, 12420 }; uint32 const Entry[3] = { 12422, 12416, 12420 };
class instance_blackwing_lair : public InstanceMapScript struct instance_blackwing_lair : public InstanceScript
{ {
public: instance_blackwing_lair(Map* map) : InstanceScript(map)
instance_blackwing_lair() : InstanceMapScript(BWLScriptName, MAP_BLACKWING_LAIR) { }
struct instance_blackwing_lair_InstanceMapScript : public InstanceScript
{ {
instance_blackwing_lair_InstanceMapScript(Map* map) : InstanceScript(map) SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
LoadObjectData(creatureData, objectData);
}
void Initialize() override
{
// Razorgore
EggCount = 0;
EggEvent = 0;
NefarianLeftTunnel = 0;
NefarianRightTunnel = 0;
addsCount.fill(0);
}
void OnCreatureCreate(Creature* creature) override
{
// This is required because the tempspawn at Vael overwrites his GUID.
if (creature->GetEntry() == NPC_VICTOR_NEFARIUS && creature->ToTempSummon())
return;
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry())
{ {
SetHeaders(DataHeader); case NPC_RAZORGORE:
SetBossNumber(EncounterCount); razorgoreGUID = creature->GetGUID();
LoadDoorData(doorData); break;
LoadObjectData(creatureData, objectData); case NPC_BLACKWING_DRAGON:
++addsCount[0];
if (Creature* razor = instance->GetCreature(razorgoreGUID))
if (CreatureAI* razorAI = razor->AI())
razorAI->JustSummoned(creature);
break;
case NPC_BLACKWING_LEGIONAIRE:
case NPC_BLACKWING_MAGE:
++addsCount[1];
if (Creature* razor = instance->GetCreature(razorgoreGUID))
if (CreatureAI* razorAI = razor->AI())
razorAI->JustSummoned(creature);
break;
case NPC_BLACKWING_GUARDSMAN:
guardList.push_back(creature->GetGUID());
break;
case NPC_NEFARIAN:
nefarianGUID = creature->GetGUID();
break;
case NPC_BLACK_DRAKONID:
case NPC_BLUE_DRAKONID:
case NPC_BRONZE_DRAKONID:
case NPC_CHROMATIC_DRAKONID:
case NPC_GREEN_DRAKONID:
case NPC_RED_DRAKONID:
if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS))
if (CreatureAI* nefariusAI = nefarius->AI())
nefariusAI->JustSummoned(creature);
break;
default:
break;
}
}
void OnGameObjectCreate(GameObject* go) override
{
InstanceScript::OnGameObjectCreate(go);
switch (go->GetEntry())
{
case GO_BLACK_DRAGON_EGG:
if (GetBossState(DATA_FIREMAW) == DONE)
go->SetPhaseMask(2, true);
else
EggList.push_back(go->GetGUID());
break;
default:
break;
}
}
void OnGameObjectRemove(GameObject* go) override
{
InstanceScript::OnGameObjectRemove(go);
if (go->GetEntry() == GO_BLACK_DRAGON_EGG)
EggList.remove(go->GetGUID());
}
uint32 GetData(uint32 data) const override
{
switch (data)
{
case DATA_NEFARIAN_LEFT_TUNNEL:
return NefarianLeftTunnel;
case DATA_NEFARIAN_RIGHT_TUNNEL:
return NefarianRightTunnel;
case DATA_EGG_EVENT:
return EggEvent;
default:
break;
} }
void Initialize() override return 0;
}
bool CheckRequiredBosses(uint32 bossId, Player const* /* player */) const override
{
switch (bossId)
{ {
// Razorgore case DATA_BROODLORD_LASHLAYER:
EggCount = 0; if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE)
EggEvent = 0; return false;
NefarianLeftTunnel = 0; break;
NefarianRightTunnel = 0; default:
addsCount.fill(0); break;
} }
void OnCreatureCreate(Creature* creature) override return true;
}
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
return false;
switch (type)
{ {
// This is required because the tempspawn at Vael overwrites his GUID. case DATA_RAZORGORE_THE_UNTAMED:
if (creature->GetEntry() == NPC_VICTOR_NEFARIUS && creature->ToTempSummon()) if (state == DONE)
{ {
return; for (ObjectGuid const& guid : EggList)
}
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry())
{
case NPC_RAZORGORE:
razorgoreGUID = creature->GetGUID();
break;
case NPC_BLACKWING_DRAGON:
++addsCount[0];
if (Creature* razor = instance->GetCreature(razorgoreGUID))
{ {
if (CreatureAI* razorAI = razor->AI()) // Eggs should be destroyed instead
{ /// @todo: after dynamic spawns
razorAI->JustSummoned(creature); if (GameObject* egg = instance->GetGameObject(guid))
} egg->SetPhaseMask(2, true);
} }
break; }
case NPC_BLACKWING_LEGIONAIRE: break;
case NPC_BLACKWING_MAGE: case DATA_NEFARIAN:
++addsCount[1]; switch (state)
if (Creature* razor = instance->GetCreature(razorgoreGUID)) {
{ case FAIL:
if (CreatureAI* razorAI = razor->AI()) _events.ScheduleEvent(EVENT_RESPAWN_NEFARIUS, 15min);
{ [[fallthrough]];
razorAI->JustSummoned(creature); case NOT_STARTED:
} if (Creature* nefarian = instance->GetCreature(nefarianGUID))
} nefarian->DespawnOrUnsummon();
break; break;
case NPC_BLACKWING_GUARDSMAN: default:
guardList.push_back(creature->GetGUID()); break;
break; }
case NPC_NEFARIAN: break;
nefarianGUID = creature->GetGUID();
break;
case NPC_BLACK_DRAKONID:
case NPC_BLUE_DRAKONID:
case NPC_BRONZE_DRAKONID:
case NPC_CHROMATIC_DRAKONID:
case NPC_GREEN_DRAKONID:
case NPC_RED_DRAKONID:
if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS))
{
if (CreatureAI* nefariusAI = nefarius->AI())
{
nefariusAI->JustSummoned(creature);
}
}
break;
default:
break;
}
} }
return true;
}
void OnGameObjectCreate(GameObject* go) override void SetData(uint32 type, uint32 data) override
{ {
InstanceScript::OnGameObjectCreate(go); if (type == DATA_EGG_EVENT)
switch (go->GetEntry())
{
case GO_BLACK_DRAGON_EGG:
if (GetBossState(DATA_FIREMAW) == DONE)
{
go->SetPhaseMask(2, true);
}
else
{
EggList.push_back(go->GetGUID());
}
break;
default:
break;
}
}
void OnGameObjectRemove(GameObject* go) override
{
InstanceScript::OnGameObjectRemove(go);
if (go->GetEntry() == GO_BLACK_DRAGON_EGG)
EggList.remove(go->GetGUID());
}
uint32 GetData(uint32 data) const override
{ {
switch (data) switch (data)
{ {
case DATA_NEFARIAN_LEFT_TUNNEL: case DONE:
return NefarianLeftTunnel; EggEvent = data;
case DATA_NEFARIAN_RIGHT_TUNNEL:
return NefarianRightTunnel;
case DATA_EGG_EVENT:
return EggEvent;
default:
break; break;
} case FAIL:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
return 0;
}
bool CheckRequiredBosses(uint32 bossId, Player const* /* player */) const override
{
switch (bossId)
{
case DATA_BROODLORD_LASHLAYER:
if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE)
return false;
break; break;
default: case IN_PROGRESS:
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45s);
EggEvent = data;
EggCount = 0;
addsCount.fill(0);
break; break;
} case NOT_STARTED:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
EggEvent = data;
EggCount = 0;
addsCount.fill(0);
return true; for (ObjectGuid const& guid : EggList)
} DoRespawnGameObject(guid, 0);
bool SetBossState(uint32 type, EncounterState state) override DoRespawnCreature(DATA_GRETHOK);
{
if (!InstanceScript::SetBossState(type, state))
return false;
switch (type) for (ObjectGuid const& guid : guardList)
{ DoRespawnCreature(guid);
case DATA_RAZORGORE_THE_UNTAMED:
if (state == DONE) break;
case SPECIAL:
if (EggEvent == NOT_STARTED)
SetData(DATA_EGG_EVENT, IN_PROGRESS);
if (++EggCount >= EggList.size())
{ {
for (ObjectGuid const& guid : EggList) if (Creature* razor = instance->GetCreature(razorgoreGUID))
{ {
// Eggs should be destroyed instead SetData(DATA_EGG_EVENT, DONE);
/// @todo: after dynamic spawns razor->RemoveAurasDueToSpell(19832); // MindControl
if (GameObject* egg = instance->GetGameObject(guid)) DoRemoveAurasDueToSpellOnPlayers(19832);
{
egg->SetPhaseMask(2, true);
}
} }
} _events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1s);
break;
case DATA_NEFARIAN:
switch (state)
{
case FAIL:
_events.ScheduleEvent(EVENT_RESPAWN_NEFARIUS, 15min);
[[fallthrough]];
case NOT_STARTED:
if (Creature* nefarian = instance->GetCreature(nefarianGUID))
{
nefarian->DespawnOrUnsummon();
}
break;
default:
break;
}
break;
}
return true;
}
void SetData(uint32 type, uint32 data) override
{
if (type == DATA_EGG_EVENT)
{
switch (data)
{
case DONE:
EggEvent = data;
break;
case FAIL:
_events.CancelEvent(EVENT_RAZOR_SPAWN); _events.CancelEvent(EVENT_RAZOR_SPAWN);
break;
case IN_PROGRESS:
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45s);
EggEvent = data;
EggCount = 0;
addsCount.fill(0);
break;
case NOT_STARTED:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
EggEvent = data;
EggCount = 0;
addsCount.fill(0);
for (ObjectGuid const& guid : EggList)
{
DoRespawnGameObject(guid, 0);
}
DoRespawnCreature(DATA_GRETHOK);
for (ObjectGuid const& guid : guardList)
{
DoRespawnCreature(guid);
}
break;
case SPECIAL:
if (EggEvent == NOT_STARTED)
SetData(DATA_EGG_EVENT, IN_PROGRESS);
if (++EggCount >= EggList.size())
{
if (Creature* razor = instance->GetCreature(razorgoreGUID))
{
SetData(DATA_EGG_EVENT, DONE);
razor->RemoveAurasDueToSpell(19832); // MindControl
DoRemoveAurasDueToSpellOnPlayers(19832);
}
_events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1s);
_events.CancelEvent(EVENT_RAZOR_SPAWN);
}
break;
}
}
if (type == DATA_NEFARIAN_LEFT_TUNNEL)
{
NefarianLeftTunnel = data;
}
if (type == DATA_NEFARIAN_RIGHT_TUNNEL)
{
NefarianRightTunnel = data;
}
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_RAZORGORE_THE_UNTAMED:
return razorgoreGUID;
default:
break;
}
return ObjectGuid::Empty;
}
void OnUnitDeath(Unit* unit) override
{
switch (unit->GetEntry())
{
case NPC_BLACKWING_DRAGON:
--addsCount[0];
if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN))
{
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s);
} }
break; break;
case NPC_BLACKWING_LEGIONAIRE:
case NPC_BLACKWING_MAGE:
--addsCount[1];
if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN))
{
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s);
}
break;
default:
break;
} }
} }
void Update(uint32 diff) override if (type == DATA_NEFARIAN_LEFT_TUNNEL)
NefarianLeftTunnel = data;
if (type == DATA_NEFARIAN_RIGHT_TUNNEL)
NefarianRightTunnel = data;
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{ {
if (_events.Empty()) case DATA_RAZORGORE_THE_UNTAMED:
return; return razorgoreGUID;
default:
break;
}
_events.Update(diff); return ObjectGuid::Empty;
}
while (uint32 eventId = _events.ExecuteEvent()) void OnUnitDeath(Unit* unit) override
{
switch (unit->GetEntry())
{
case NPC_BLACKWING_DRAGON:
--addsCount[0];
if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN))
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s);
break;
case NPC_BLACKWING_LEGIONAIRE:
case NPC_BLACKWING_MAGE:
--addsCount[1];
if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN))
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s);
break;
default:
break;
}
}
void Update(uint32 diff) override
{
if (_events.Empty())
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{ {
switch (eventId) case EVENT_RAZOR_SPAWN:
{ if (EggEvent == IN_PROGRESS)
case EVENT_RAZOR_SPAWN: {
if (EggEvent == IN_PROGRESS) bool spawnMoreAdds = true;
for (uint8 i = urand(2, 5); i > 0; --i)
{ {
bool spawnMoreAdds = true; uint32 mobEntry = Entry[urand(0, 2)];
for (uint8 i = urand(2, 5); i > 0; --i) uint32 dragonkinsCount = addsCount[0];
{ uint32 orcsCount = addsCount[1];
uint32 mobEntry = Entry[urand(0, 2)];
uint32 dragonkinsCount = addsCount[0];
uint32 orcsCount = addsCount[1];
// If more than 12 dragonkins... // If more than 12 dragonkins...
if (dragonkinsCount >= 12) if (dragonkinsCount >= 12)
{
//... and more than 40 orcs - stop spawning more adds.
if (orcsCount >= 40)
{ {
//... and more than 40 orcs - stop spawning more adds. spawnMoreAdds = false;
if (orcsCount >= 40) break;
{
spawnMoreAdds = false;
break;
}
//... - stop spawning them.
else if (mobEntry == NPC_BLACKWING_DRAGON)
{
continue;
}
} }
// If more than 40 orcs - stop spawning them. //... - stop spawning them.
else if (orcsCount >= 40 && mobEntry != NPC_BLACKWING_DRAGON) else if (mobEntry == NPC_BLACKWING_DRAGON)
{ {
continue; continue;
} }
if (Creature* summon = instance->SummonCreature(mobEntry, SummonPosition[urand(0, 7)]))
{
summon->AI()->DoZoneInCombat();
}
} }
// If more than 40 orcs - stop spawning them.
if (spawnMoreAdds) else if (orcsCount >= 40 && mobEntry != NPC_BLACKWING_DRAGON)
{ {
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15s); continue;
} }
if (Creature* summon = instance->SummonCreature(mobEntry, SummonPosition[urand(0, 7)]))
summon->AI()->DoZoneInCombat();
} }
break;
case EVENT_RAZOR_PHASE_TWO: if (spawnMoreAdds)
_events.CancelEvent(EVENT_RAZOR_SPAWN); _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15s);
if (Creature* razor = instance->GetCreature(razorgoreGUID)) }
razor->AI()->DoAction(ACTION_PHASE_TWO); break;
break; case EVENT_RAZOR_PHASE_TWO:
case EVENT_RESPAWN_NEFARIUS: _events.CancelEvent(EVENT_RAZOR_SPAWN);
if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS)) if (Creature* razor = instance->GetCreature(razorgoreGUID))
{ razor->AI()->DoAction(ACTION_PHASE_TWO);
nefarius->SetPhaseMask(1, true); break;
nefarius->setActive(true); case EVENT_RESPAWN_NEFARIUS:
nefarius->Respawn(); if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS))
nefarius->GetMotionMaster()->MoveTargetedHome(); {
} nefarius->SetPhaseMask(1, true);
break; nefarius->setActive(true);
} nefarius->Respawn();
nefarius->GetMotionMaster()->MoveTargetedHome();
}
break;
} }
} }
void ReadSaveDataMore(std::istringstream& data) override
{
data >> NefarianLeftTunnel;
data >> NefarianRightTunnel;
}
void WriteSaveDataMore(std::ostringstream& data) override
{
data << NefarianLeftTunnel << ' ' << NefarianRightTunnel;
}
protected:
ObjectGuid razorgoreGUID;
ObjectGuid nefarianGUID;
ObjectGuid nefarianDoorGUID;
// Razorgore
uint8 EggCount;
uint32 EggEvent;
GuidList EggList;
GuidList guardList;
std::array<uint32, 2> addsCount;
// Nefarian
uint32 NefarianLeftTunnel;
uint32 NefarianRightTunnel;
// Misc
EventMap _events;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_blackwing_lair_InstanceMapScript(map);
} }
void ReadSaveDataMore(std::istringstream& data) override
{
data >> NefarianLeftTunnel;
data >> NefarianRightTunnel;
}
void WriteSaveDataMore(std::ostringstream& data) override
{
data << NefarianLeftTunnel << ' ' << NefarianRightTunnel;
}
protected:
ObjectGuid razorgoreGUID;
ObjectGuid nefarianGUID;
ObjectGuid nefarianDoorGUID;
// Razorgore
uint8 EggCount;
uint32 EggEvent;
GuidList EggList;
GuidList guardList;
std::array<uint32, 2> addsCount;
// Nefarian
uint32 NefarianLeftTunnel;
uint32 NefarianRightTunnel;
// Misc
EventMap _events;
}; };
enum ShadowFlame enum ShadowFlame
@@ -527,7 +478,7 @@ public:
void AddSC_instance_blackwing_lair() void AddSC_instance_blackwing_lair()
{ {
new instance_blackwing_lair(); RegisterInstanceScript(instance_blackwing_lair, MAP_BLACKWING_LAIR);
RegisterSpellScript(spell_bwl_shadowflame); RegisterSpellScript(spell_bwl_shadowflame);
new at_orb_of_command(); new at_orb_of_command();
} }

View File

@@ -43,88 +43,73 @@ enum Events
EVENT_LIVING_BOMB, EVENT_LIVING_BOMB,
}; };
class boss_baron_geddon : public CreatureScript struct boss_baron_geddon : public BossAI
{ {
public: boss_baron_geddon(Creature* creature) : BossAI(creature, DATA_GEDDON),
boss_baron_geddon() : CreatureScript("boss_baron_geddon") { } armageddonCasted(false)
struct boss_baron_geddonAI : public BossAI
{ {
boss_baron_geddonAI(Creature* creature) : BossAI(creature, DATA_GEDDON),
armageddonCasted(false)
{
}
void Reset() override
{
_Reset();
armageddonCasted = false;
}
void JustEngagedWith(Unit* /*attacker*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_INFERNO, 13s, 15s);
events.ScheduleEvent(EVENT_IGNITE_MANA, 7s, 19s);
events.ScheduleEvent(EVENT_LIVING_BOMB, 11s, 16s);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
// If boss is below 2% hp - cast Armageddon
if (!armageddonCasted && damage < me->GetHealth() && me->HealthBelowPctDamaged(2, damage))
{
me->RemoveAurasDueToSpell(SPELL_INFERNO);
me->StopMoving();
if (me->CastSpell(me, SPELL_ARMAGEDDON, TRIGGERED_FULL_MASK) == SPELL_CAST_OK)
{
Talk(EMOTE_SERVICE);
armageddonCasted = true;
}
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_INFERNO:
{
DoCastAOE(SPELL_INFERNO);
events.Repeat(21s, 26s);
break;
}
case EVENT_IGNITE_MANA:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IGNITE_MANA))
{
DoCast(target, SPELL_IGNITE_MANA);
}
events.Repeat(27s, 32s);
break;
}
case EVENT_LIVING_BOMB:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
DoCast(target, SPELL_LIVING_BOMB);
}
events.Repeat(11s, 16s);
break;
}
}
}
private:
bool armageddonCasted;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_baron_geddonAI>(creature);
} }
void Reset() override
{
_Reset();
armageddonCasted = false;
}
void JustEngagedWith(Unit* /*attacker*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_INFERNO, 13s, 15s);
events.ScheduleEvent(EVENT_IGNITE_MANA, 7s, 19s);
events.ScheduleEvent(EVENT_LIVING_BOMB, 11s, 16s);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
// If boss is below 2% hp - cast Armageddon
if (!armageddonCasted && damage < me->GetHealth() && me->HealthBelowPctDamaged(2, damage))
{
me->RemoveAurasDueToSpell(SPELL_INFERNO);
me->StopMoving();
if (me->CastSpell(me, SPELL_ARMAGEDDON, TRIGGERED_FULL_MASK) == SPELL_CAST_OK)
{
Talk(EMOTE_SERVICE);
armageddonCasted = true;
}
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_INFERNO:
{
DoCastAOE(SPELL_INFERNO);
events.Repeat(21s, 26s);
break;
}
case EVENT_IGNITE_MANA:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IGNITE_MANA))
DoCast(target, SPELL_IGNITE_MANA);
events.Repeat(27s, 32s);
break;
}
case EVENT_LIVING_BOMB:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
DoCast(target, SPELL_LIVING_BOMB);
events.Repeat(11s, 16s);
break;
}
}
}
private:
bool armageddonCasted;
}; };
// 19695 Inferno // 19695 Inferno
@@ -149,9 +134,7 @@ class spell_geddon_inferno_aura : public AuraScript
void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
if (Creature* pCreatureTarget = GetTarget()->ToCreature()) if (Creature* pCreatureTarget = GetTarget()->ToCreature())
{
pCreatureTarget->SetReactState(REACT_AGGRESSIVE); pCreatureTarget->SetReactState(REACT_AGGRESSIVE);
}
} }
void PeriodicTick(AuraEffect const* aurEff) void PeriodicTick(AuraEffect const* aurEff)
@@ -209,9 +192,7 @@ class spell_geddon_armageddon_aura : public AuraScript
void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
if (Creature* pCreatureTarget = GetTarget()->ToCreature()) if (Creature* pCreatureTarget = GetTarget()->ToCreature())
{
pCreatureTarget->SetReactState(REACT_AGGRESSIVE); pCreatureTarget->SetReactState(REACT_AGGRESSIVE);
}
} }
void Register() override void Register() override
@@ -223,7 +204,7 @@ class spell_geddon_armageddon_aura : public AuraScript
void AddSC_boss_baron_geddon() void AddSC_boss_baron_geddon()
{ {
new boss_baron_geddon(); RegisterMoltenCoreCreatureAI(boss_baron_geddon);
// Spells // Spells
RegisterSpellScript(spell_geddon_inferno_aura); RegisterSpellScript(spell_geddon_inferno_aura);

View File

@@ -51,123 +51,93 @@ enum Events
EVENT_MAGMA_SHACKLES, EVENT_MAGMA_SHACKLES,
}; };
class boss_garr : public CreatureScript struct boss_garr : public BossAI
{ {
public: boss_garr(Creature* creature) : BossAI(creature, DATA_GARR),
boss_garr() : CreatureScript("boss_garr") {} massEruptionTimer(600000) // 10 mins
struct boss_garrAI : public BossAI
{ {
boss_garrAI(Creature* creature) : BossAI(creature, DATA_GARR), }
massEruptionTimer(600000) // 10 mins
void Reset() override
{
_Reset();
massEruptionTimer = 600000;
}
void JustEngagedWith(Unit* /*attacker*/) override
{
_JustEngagedWith();
DoCastSelf(SPELL_SEPARATION_ANXIETY, true);
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 15s);
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 10s);
massEruptionTimer = 600000; // 10 mins
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
// This should always process
if (massEruptionTimer <= diff)
{ {
Talk(EMOTE_MASS_ERRUPTION, me);
DoCastAOE(SPELL_ERUPTION_TRIGGER, true);
massEruptionTimer = 20000;
}
else
{
massEruptionTimer -= diff;
} }
void Reset() override events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 const eventId = events.ExecuteEvent())
{ {
_Reset(); switch (eventId)
massEruptionTimer = 600000;
}
void JustEngagedWith(Unit* /*attacker*/) override
{
_JustEngagedWith();
DoCastSelf(SPELL_SEPARATION_ANXIETY, true);
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 15s);
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 10s);
massEruptionTimer = 600000; // 10 mins
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{ {
return; case EVENT_ANTIMAGIC_PULSE:
{
DoCastSelf(SPELL_ANTIMAGIC_PULSE);
events.Repeat(20s);
break;
}
case EVENT_MAGMA_SHACKLES:
{
DoCastSelf(SPELL_MAGMA_SHACKLES);
events.Repeat(15s);
break;
}
} }
// This should always process
if (massEruptionTimer <= diff)
{
Talk(EMOTE_MASS_ERRUPTION, me);
DoCastAOE(SPELL_ERUPTION_TRIGGER, true);
massEruptionTimer = 20000;
}
else
{
massEruptionTimer -= diff;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ANTIMAGIC_PULSE:
{
DoCastSelf(SPELL_ANTIMAGIC_PULSE);
events.Repeat(20s);
break;
}
case EVENT_MAGMA_SHACKLES:
{
DoCastSelf(SPELL_MAGMA_SHACKLES);
events.Repeat(15s);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
} }
private: DoMeleeAttackIfReady();
uint32 massEruptionTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_garrAI>(creature);
} }
private:
uint32 massEruptionTimer;
}; };
class npc_garr_firesworn : public CreatureScript struct npc_garr_firesworn : public ScriptedAI
{ {
public: npc_garr_firesworn(Creature* creature) : ScriptedAI(creature) {}
npc_garr_firesworn() : CreatureScript("npc_garr_firesworn") {}
struct npc_garr_fireswornAI : public ScriptedAI void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override
{ {
npc_garr_fireswornAI(Creature* creature) : ScriptedAI(creature) {} if (damage >= me->GetHealth())
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override
{ {
if (damage >= me->GetHealth()) // Prevent double damage because Firesworn can kill himself with Massive Eruption
{ if (me != attacker)
// Prevent double damage because Firesworn can kill himself with Massive Erruption DoCastSelf(SPELL_ERUPTION, true);
if (me != attacker)
{
DoCastSelf(SPELL_ERUPTION, true);
}
DoCastAOE(SPELL_ENRAGE_TRIGGER); DoCastAOE(SPELL_ENRAGE_TRIGGER);
}
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_garr_fireswornAI>(creature);
} }
}; };
@@ -210,9 +180,7 @@ class spell_garr_frenzy : public SpellScript
void HandleHit(SpellEffIndex /*effIndex*/) void HandleHit(SpellEffIndex /*effIndex*/)
{ {
if (Unit* target = GetHitUnit()) if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_FRENZY); target->CastSpell(target, SPELL_FRENZY);
}
} }
void Register() override void Register() override
@@ -223,8 +191,8 @@ class spell_garr_frenzy : public SpellScript
void AddSC_boss_garr() void AddSC_boss_garr()
{ {
new boss_garr(); RegisterMoltenCoreCreatureAI(boss_garr);
new npc_garr_firesworn(); RegisterMoltenCoreCreatureAI(npc_garr_firesworn);
// Spells // Spells
RegisterSpellScript(spell_garr_separation_anxiety_aura); RegisterSpellScript(spell_garr_separation_anxiety_aura);

View File

@@ -34,74 +34,57 @@ enum Events
EVENT_SHADOW_BOLT, EVENT_SHADOW_BOLT,
}; };
class boss_gehennas : public CreatureScript struct boss_gehennas : public BossAI
{ {
public: boss_gehennas(Creature* creature) : BossAI(creature, DATA_GEHENNAS) {}
boss_gehennas() : CreatureScript("boss_gehennas") { }
struct boss_gehennasAI : public BossAI void JustEngagedWith(Unit* /*attacker*/) override
{ {
boss_gehennasAI(Creature* creature) : BossAI(creature, DATA_GEHENNAS) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_GEHENNAS_CURSE, 6s, 9s);
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 10s);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s, 5s);
}
void JustEngagedWith(Unit* /*attacker*/) override void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
_JustEngagedWith(); case EVENT_GEHENNAS_CURSE:
events.ScheduleEvent(EVENT_GEHENNAS_CURSE, 6s, 9s);
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 10s);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s, 5s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
case EVENT_GEHENNAS_CURSE: DoCastVictim(SPELL_GEHENNAS_CURSE);
events.Repeat(25s, 30s);
break;
}
case EVENT_RAIN_OF_FIRE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
DoCast(target, SPELL_RAIN_OF_FIRE, true);
events.Repeat(6s);
break;
}
case EVENT_SHADOW_BOLT:
{
if (urand(0, 1))
{ {
DoCastVictim(SPELL_GEHENNAS_CURSE); if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
events.Repeat(25s, 30s); DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
break;
}
case EVENT_RAIN_OF_FIRE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
DoCast(target, SPELL_RAIN_OF_FIRE, true);
}
events.Repeat(6s);
break;
}
case EVENT_SHADOW_BOLT:
{
if (urand(0, 1))
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
{
DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
}
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
}
else else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM); DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
events.Repeat(5s);
break;
} }
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
events.Repeat(5s);
break;
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_gehennasAI>(creature);
} }
}; };
void AddSC_boss_gehennas() void AddSC_boss_gehennas()
{ {
new boss_gehennas(); RegisterMoltenCoreCreatureAI(boss_gehennas);
} }

View File

@@ -40,191 +40,157 @@ enum Spells
SPELL_FULL_HEAL = 17683, SPELL_FULL_HEAL = 17683,
}; };
class boss_golemagg : public CreatureScript struct boss_golemagg : public BossAI
{ {
public: boss_golemagg(Creature* creature) : BossAI(creature, DATA_GOLEMAGG),
boss_golemagg() : CreatureScript("boss_golemagg") { } earthquakeTimer(0),
pyroblastTimer(0),
enraged(false)
{}
struct boss_golemaggAI : public BossAI void Reset() override
{ {
boss_golemaggAI(Creature* creature) : BossAI(creature, DATA_GOLEMAGG), _Reset();
earthquakeTimer(0), earthquakeTimer = 0;
pyroblastTimer(0), pyroblastTimer = urand(3000, 7000);
enraged(false) enraged = false;
{} DoCastSelf(SPELL_MAGMASPLASH);
DoCastSelf(SPELL_GOLEMAGG_TRUST_AURA);
DoCastSelf(SPELL_DOUBLE_ATTACK);
}
void Reset() override void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!enraged && me->HealthBelowPctDamaged(10, damage))
{ {
_Reset(); DoCastSelf(SPELL_ATTRACK_RAGER, true);
earthquakeTimer = 0; DoCastAOE(SPELL_EARTHQUAKE, true);
pyroblastTimer = urand(3000, 7000); earthquakeTimer = 5000;
enraged = false; enraged = true;
DoCastSelf(SPELL_MAGMASPLASH);
DoCastSelf(SPELL_GOLEMAGG_TRUST_AURA);
DoCastSelf(SPELL_DOUBLE_ATTACK);
} }
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
// Should not get impact by cast state (cast should always happen)
if (earthquakeTimer)
{ {
if (!enraged && me->HealthBelowPctDamaged(10, damage)) if (earthquakeTimer <= diff)
{ {
DoCastSelf(SPELL_ATTRACK_RAGER, true); DoCastSelf(SPELL_EARTHQUAKE, true);
DoCastAOE(SPELL_EARTHQUAKE, true);
earthquakeTimer = 5000; earthquakeTimer = 5000;
enraged = true;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
// Should not get impact by cast state (cast should always happen)
if (earthquakeTimer)
{
if (earthquakeTimer <= diff)
{
DoCastSelf(SPELL_EARTHQUAKE, true);
earthquakeTimer = 5000;
}
else
{
earthquakeTimer -= diff;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
if (pyroblastTimer <= diff)
{
DoCastRandomTarget(SPELL_PYROBLAST);
pyroblastTimer = 7000;
} }
else else
{ {
pyroblastTimer -= diff; earthquakeTimer -= diff;
} }
DoMeleeAttackIfReady();
} }
private: if (me->HasUnitState(UNIT_STATE_CASTING))
uint32 earthquakeTimer; return;
uint32 pyroblastTimer;
bool enraged;
};
CreatureAI* GetAI(Creature* creature) const override if (pyroblastTimer <= diff)
{ {
return GetMoltenCoreAI<boss_golemaggAI>(creature); DoCastRandomTarget(SPELL_PYROBLAST);
pyroblastTimer = 7000;
}
else
{
pyroblastTimer -= diff;
}
DoMeleeAttackIfReady();
} }
private:
uint32 earthquakeTimer;
uint32 pyroblastTimer;
bool enraged;
}; };
class npc_core_rager : public CreatureScript struct npc_core_rager : public ScriptedAI
{ {
public: npc_core_rager(Creature* creature) : ScriptedAI(creature),
npc_core_rager() : CreatureScript("npc_core_rager") { } instance(creature->GetInstanceScript()),
mangleTimer(7000),
struct npc_core_ragerAI : public ScriptedAI rangeCheckTimer(1000)
{ {
npc_core_ragerAI(Creature* creature) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
mangleTimer(7000),
rangeCheckTimer(1000)
{
}
void Reset() override
{
mangleTimer = 7000; // These times are probably wrong
rangeCheckTimer = 1000;
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
{
DoCastSelf(SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
// Just in case if something will go bad, let players to kill this creature
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
{
return;
}
if (me->HealthBelowPctDamaged(50, damage))
{
damage = 0;
DoCastSelf(SPELL_FULL_HEAL, true);
Talk(EMOTE_LOWHP);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
// Should have no impact from unit state
if (rangeCheckTimer <= diff)
{
Creature const* golemagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOLEMAGG));
if (golemagg && me->GetDistance(golemagg) > 100.0f)
{
instance->DoAction(ACTION_RESET_GOLEMAGG_ENCOUNTER);
return;
}
rangeCheckTimer = 1000;
}
else
{
rangeCheckTimer -= diff;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
// Mangle
if (mangleTimer <= diff)
{
DoCastVictim(SPELL_MANGLE);
mangleTimer = 10000;
}
else
{
mangleTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 mangleTimer;
uint32 rangeCheckTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_core_ragerAI>(creature);
} }
void Reset() override
{
mangleTimer = 7000; // These times are probably wrong
rangeCheckTimer = 1000;
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
DoCastSelf(SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
// Just in case if something will go bad, let players to kill this creature
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
return;
if (me->HealthBelowPctDamaged(50, damage))
{
damage = 0;
DoCastSelf(SPELL_FULL_HEAL, true);
Talk(EMOTE_LOWHP);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
// Should have no impact from unit state
if (rangeCheckTimer <= diff)
{
Creature const* golemagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOLEMAGG));
if (golemagg && me->GetDistance(golemagg) > 100.0f)
{
instance->DoAction(ACTION_RESET_GOLEMAGG_ENCOUNTER);
return;
}
rangeCheckTimer = 1000;
}
else
{
rangeCheckTimer -= diff;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
// Mangle
if (mangleTimer <= diff)
{
DoCastVictim(SPELL_MANGLE);
mangleTimer = 10000;
}
else
{
mangleTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 mangleTimer;
uint32 rangeCheckTimer;
}; };
void AddSC_boss_golemagg() void AddSC_boss_golemagg()
{ {
new boss_golemagg(); RegisterMoltenCoreCreatureAI(boss_golemagg);
new npc_core_rager(); RegisterMoltenCoreCreatureAI(npc_core_rager);
} }

View File

@@ -33,56 +33,45 @@ enum Events
EVENT_SHADOW_SHOCK = 3, EVENT_SHADOW_SHOCK = 3,
}; };
class boss_lucifron : public CreatureScript struct boss_lucifron : public BossAI
{ {
public: boss_lucifron(Creature* creature) : BossAI(creature, DATA_LUCIFRON) {}
boss_lucifron() : CreatureScript("boss_lucifron") { }
struct boss_lucifronAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_lucifronAI(Creature* creature) : BossAI(creature, DATA_LUCIFRON) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_IMPENDING_DOOM, 6s, 11s);
events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 11s, 14s);
events.ScheduleEvent(EVENT_SHADOW_SHOCK, 5s);
}
void JustEngagedWith(Unit* /*who*/) override void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
_JustEngagedWith(); case EVENT_IMPENDING_DOOM:
events.ScheduleEvent(EVENT_IMPENDING_DOOM, 6s, 11s);
events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 11s, 14s);
events.ScheduleEvent(EVENT_SHADOW_SHOCK, 5s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
case EVENT_IMPENDING_DOOM: DoCastVictim(SPELL_IMPENDING_DOOM);
{ events.Repeat(20s);
DoCastVictim(SPELL_IMPENDING_DOOM); break;
events.Repeat(20s); }
break; case EVENT_LUCIFRON_CURSE:
} {
case EVENT_LUCIFRON_CURSE: DoCastVictim(SPELL_LUCIFRON_CURSE);
{ events.Repeat(20s);
DoCastVictim(SPELL_LUCIFRON_CURSE); break;
events.Repeat(20s); }
break; case EVENT_SHADOW_SHOCK:
} {
case EVENT_SHADOW_SHOCK: DoCastVictim(SPELL_SHADOW_SHOCK);
{ events.Repeat(5s);
DoCastVictim(SPELL_SHADOW_SHOCK); break;
events.Repeat(5s);
break;
}
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_lucifronAI>(creature);
} }
}; };
void AddSC_boss_lucifron() void AddSC_boss_lucifron()
{ {
new boss_lucifron(); RegisterMoltenCoreCreatureAI(boss_lucifron);
} }

View File

@@ -47,73 +47,58 @@ enum Events
constexpr float MELEE_TARGET_LOOKUP_DIST = 10.0f; constexpr float MELEE_TARGET_LOOKUP_DIST = 10.0f;
class boss_magmadar : public CreatureScript struct boss_magmadar : public BossAI
{ {
public: boss_magmadar(Creature* creature) : BossAI(creature, DATA_MAGMADAR) {}
boss_magmadar() : CreatureScript("boss_magmadar") {}
struct boss_magmadarAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_magmadarAI(Creature* creature) : BossAI(creature, DATA_MAGMADAR) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_FRENZY, 8500ms);
events.ScheduleEvent(EVENT_PANIC, 9500ms);
events.ScheduleEvent(EVENT_LAVA_BOMB, 12s);
events.ScheduleEvent(EVENT_LAVA_BOMB_RANGED, 15s);
}
void JustEngagedWith(Unit* /*who*/) override void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
_JustEngagedWith(); case EVENT_FRENZY:
events.ScheduleEvent(EVENT_FRENZY, 8500ms);
events.ScheduleEvent(EVENT_PANIC, 9500ms);
events.ScheduleEvent(EVENT_LAVA_BOMB, 12s);
events.ScheduleEvent(EVENT_LAVA_BOMB_RANGED, 15s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
case EVENT_FRENZY: Talk(EMOTE_FRENZY);
{ DoCastSelf(SPELL_FRENZY);
Talk(EMOTE_FRENZY); events.Repeat(15s, 20s);
DoCastSelf(SPELL_FRENZY); break;
events.Repeat(15s, 20s); }
break; case EVENT_PANIC:
} {
case EVENT_PANIC: DoCastVictim(SPELL_PANIC);
{ events.Repeat(31s, 38s);
DoCastVictim(SPELL_PANIC); break;
events.Repeat(31s, 38s); }
break; case EVENT_LAVA_BOMB:
} {
case EVENT_LAVA_BOMB: if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true))
{ DoCast(target, SPELL_LAVA_BOMB);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true))
{
DoCast(target, SPELL_LAVA_BOMB);
}
events.Repeat(12s, 15s); events.Repeat(12s, 15s);
break; break;
} }
case EVENT_LAVA_BOMB_RANGED: case EVENT_LAVA_BOMB_RANGED:
{
std::list<Unit*> targets;
SelectTargetList(targets, 1, SelectTargetMethod::Random, 1, [this](Unit* target)
{ {
std::list<Unit*> targets; return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f;
SelectTargetList(targets, 1, SelectTargetMethod::Random, 1, [this](Unit* target) });
{
return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f;
});
if (!targets.empty()) if (!targets.empty())
{ DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED);
DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED); events.Repeat(12s, 15s);
} break;
events.Repeat(12s, 15s);
break;
}
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_magmadarAI>(creature);
} }
}; };
@@ -162,7 +147,7 @@ class spell_magmadar_lava_bomb : public SpellScript
void AddSC_boss_magmadar() void AddSC_boss_magmadar()
{ {
new boss_magmadar(); RegisterMoltenCoreCreatureAI(boss_magmadar);
// Spells // Spells
RegisterSpellScript(spell_magmadar_lava_bomb); RegisterSpellScript(spell_magmadar_lava_bomb);

View File

@@ -131,412 +131,389 @@ struct MajordomoAddData
MajordomoAddData(ObjectGuid _guid, uint32 _creatureEntry, Position _spawnPos) : guid(_guid), creatureEntry(_creatureEntry), spawnPos(_spawnPos) { } MajordomoAddData(ObjectGuid _guid, uint32 _creatureEntry, Position _spawnPos) : guid(_guid), creatureEntry(_creatureEntry), spawnPos(_spawnPos) { }
}; };
class boss_majordomo : public CreatureScript struct boss_majordomo : public BossAI
{ {
public: boss_majordomo(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {}
boss_majordomo() : CreatureScript("boss_majordomo") {}
struct boss_majordomoAI : public BossAI void JustDied(Unit* /*killer*/) override
{ {
boss_majordomoAI(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {} Talk(SAY_DEATH);
me->DespawnOrUnsummon(10s, 0s);
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
me->DespawnOrUnsummon(10s, 0s);
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_RAGNAROS)
{
summon->CastSpell(summon, SPELL_RAGNAROS_FADE);
summon->CastSpell(summon, SPELL_RAGNAROS_SUBMERGE_EFFECT, true);
summon->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
summon->SetImmuneToAll(true);
summon->SetReactState(REACT_PASSIVE);
}
}
void InitializeAI() override
{
BossAI::InitializeAI();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
std::list<TempSummon*> p_summons;
me->SummonCreatureGroup(SUMMON_GROUP_ADDS, &p_summons);
if (!p_summons.empty())
{
for (TempSummon const* summon : p_summons)
{
if (summon)
{
static_minionsGUIDS.insert(summon->GetGUID());
majordomoSummonsData[summon->GetGUID().GetCounter()] = MajordomoAddData(summon->GetGUID(), summon->GetEntry(), summon->GetPosition());
}
}
}
}
else
{
events.SetPhase(PHASE_NONE);
me->SetImmuneToAll(true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
}
}
void Reset() override
{
me->ResetLootMode();
events.Reset();
aliveMinionsGUIDS.clear();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, NOT_STARTED);
for (auto const& summon : majordomoSummonsData)
{
if (ObjectAccessor::GetCreature(*me, summon.second.guid))
{
continue;
}
if (Creature* spawn = me->SummonCreature(summon.second.creatureEntry, summon.second.spawnPos))
{
static_minionsGUIDS.erase(summon.second.guid); // Erase the guid from the previous, no longer existing, spawn.
static_minionsGUIDS.insert(spawn->GetGUID());
majordomoSummonsData.erase(summon.second.guid.GetCounter());
majordomoSummonsData[spawn->GetGUID().GetCounter()] = MajordomoAddData(spawn->GetGUID(), spawn->GetEntry(), spawn->GetPosition());
}
}
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
else
{
static_minionsGUIDS.clear();
majordomoSummonsData.clear();
summons.DespawnAll();
}
}
bool CanAIAttack(Unit const* /*target*/) const override
{
return instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE;
}
void KilledUnit(Unit* victim) override
{
if (roll_chance_i(25) && victim->IsPlayer())
{
Talk(SAY_SLAY);
}
}
void JustEngagedWith(Unit* /*attacker*/) override
{
if (!events.IsInPhase(PHASE_COMBAT))
{
return;
}
_JustEngagedWith();
DoCastAOE(SPELL_SEPARATION_ANXIETY);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_AEGIS_OF_RAGNAROS, true);
events.ScheduleEvent(EVENT_SHIELD_REFLECTION, 30s, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_RANDOM, 25s, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_TARGET, 15s, PHASE_COMBAT, PHASE_COMBAT);
aliveMinionsGUIDS.clear();
aliveMinionsGUIDS = static_minionsGUIDS;
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
aliveMinionsGUIDS.erase(summon->GetGUID());
if (summon->GetEntry() == NPC_FLAMEWAKER_HEALER || summon->GetEntry() == NPC_FLAMEWAKER_ELITE)
{
uint32 const remainingAdds = std::count_if(aliveMinionsGUIDS.begin(), aliveMinionsGUIDS.end(), [](ObjectGuid const& summonGuid)
{
return summonGuid.GetEntry() == NPC_FLAMEWAKER_HEALER || summonGuid.GetEntry() == NPC_FLAMEWAKER_ELITE;
});
// Last remaining add
if (remainingAdds == 1)
{
Talk(SAY_LAST_ADD);
DoCastAOE(SPELL_CHAMPION);
}
// 50% of adds
else if (remainingAdds == 4)
{
DoCastAOE(SPELL_IMMUNE_POLY);
}
else if (!remainingAdds)
{
static_minionsGUIDS.clear();
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, DONE);
events.CancelEventGroup(PHASE_COMBAT);
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
me->SetImmuneToAll(true);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
EnterEvadeMode();
Talk(SAY_DEFEAT);
return;
}
DoCastAOE(SPELL_ENCOURAGEMENT);
}
}
void JustReachedHome() override
{
_JustReachedHome();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) == DONE)
{
events.Reset();
events.SetPhase(PHASE_DEFEAT_OUTRO);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_1, 7500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
if (events.IsInPhase(PHASE_COMBAT) && me->GetHealth() <= damage)
{
damage = 0;
}
}
void UpdateAI(uint32 diff) override
{
switch (events.GetPhaseMask())
{
case (1 << (PHASE_COMBAT - 1)):
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHIELD_REFLECTION:
{
if (rand_chance() <= 50.f)
{
DoCastSelf(SPELL_MAGIC_REFLECTION);
}
else
{
DoCastSelf(SPELL_DAMAGE_REFLECTION);
}
events.Repeat(30s);
break;
}
case EVENT_TELEPORT_RANDOM:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCast(target, SPELL_TELEPORT_RANDOM);
}
events.Repeat(30s);
break;
}
case EVENT_TELEPORT_TARGET:
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCastAOE(SPELL_TELEPORT_TARGET);
events.Repeat(30s);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
break;
}
case (1 << (PHASE_DEFEAT_OUTRO - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DEFEAT_OUTRO_1:
{
Talk(SAY_DEFEAT_2);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_2, 8s, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_2:
{
Talk(SAY_DEFEAT_3);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_3, 21500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_3:
{
DoCastSelf(SPELL_TELEPORT_SELF);
break;
}
}
}
break;
}
case (1 << (PHASE_RAGNAROS_SUMMONING - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RAGNAROS_SUMMON_1:
{
if (GameObject* lavaSplash = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_SPLASH)))
{
lavaSplash->SetRespawnTime(900);
lavaSplash->Refresh();
}
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
lavaSteam->SetRespawnTime(900);
lavaSteam->Refresh();
}
Talk(SAY_RAG_SUM_2);
// Next event will get triggered in MovementInform
me->SetWalk(true);
me->GetMotionMaster()->MovePoint(POINT_RAGNAROS_SUMMON, MajordomoMoveRagPos, FORCED_MOVEMENT_NONE, 0.f, true, false);
break;
}
case EVENT_RAGNAROS_SUMMON_2:
{
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
me->SetFacingToObject(lavaSteam);
}
Talk(SAY_SUMMON_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_3, 16700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_EMERGE, 15s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_3:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL1_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_4, 11700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_4:
{
Talk(SAY_ARRIVAL2_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_5, 8700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_5:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL3_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_6, 16500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_6:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->CastSpell(me, SPELL_ELEMENTAL_FIRE, true);
ragnaros->AI()->DoAction(ACTION_FINISH_RAGNAROS_INTRO);
}
break;
}
// Additional events
case EVENT_RAGNAROS_EMERGE:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->RemoveAurasDueToSpell(SPELL_RAGNAROS_FADE);
ragnaros->CastSpell(ragnaros, SPELL_RAGNA_EMERGE);
}
}break;
}
}
break;
}
}
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type == POINT_MOTION_TYPE && pointId == POINT_RAGNAROS_SUMMON)
{
DoCastAOE(SPELL_SUMMON_RAGNAROS);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_2, 11500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (events.IsInPhase(PHASE_DEFEAT_OUTRO) && spellInfo->Id == SPELL_TELEPORT_SELF)
{
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetHomePosition(MajordomoRagnaros);
me->NearTeleportTo(MajordomoRagnaros.GetPositionX(), MajordomoRagnaros.GetPositionY(), MajordomoRagnaros.GetPositionZ(), MajordomoRagnaros.GetOrientation());
events.SetPhase(PHASE_NONE);
}
}
void DoAction(int32 action) override
{
if (action == ACTION_START_RAGNAROS_INTRO && !events.IsInPhase(PHASE_RAGNAROS_SUMMONING))
{
events.SetPhase(PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_1, 5s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
private:
GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion
GuidSet aliveMinionsGUIDS; // used for calculations
std::unordered_map<uint32, MajordomoAddData> majordomoSummonsData;
};
bool OnGossipHello(Player* player, Creature* creature) override
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, TEXT_ID_SUMMON_1, creature->GetGUID());
return true;
} }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_RAGNAROS)
{
summon->CastSpell(summon, SPELL_RAGNAROS_FADE);
summon->CastSpell(summon, SPELL_RAGNAROS_SUBMERGE_EFFECT, true);
summon->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
summon->SetImmuneToAll(true);
summon->SetReactState(REACT_PASSIVE);
}
}
void InitializeAI() override
{
BossAI::InitializeAI();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
std::list<TempSummon*> p_summons;
me->SummonCreatureGroup(SUMMON_GROUP_ADDS, &p_summons);
if (!p_summons.empty())
{
for (TempSummon const* summon : p_summons)
{
if (summon)
{
static_minionsGUIDS.insert(summon->GetGUID());
majordomoSummonsData[summon->GetGUID().GetCounter()] = MajordomoAddData(summon->GetGUID(), summon->GetEntry(), summon->GetPosition());
}
}
}
}
else
{
events.SetPhase(PHASE_NONE);
me->SetImmuneToAll(true);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
}
}
void Reset() override
{
me->ResetLootMode();
events.Reset();
aliveMinionsGUIDS.clear();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, NOT_STARTED);
for (auto const& summon : majordomoSummonsData)
{
if (ObjectAccessor::GetCreature(*me, summon.second.guid))
continue;
if (Creature* spawn = me->SummonCreature(summon.second.creatureEntry, summon.second.spawnPos))
{
static_minionsGUIDS.erase(summon.second.guid); // Erase the guid from the previous, no longer existing, spawn.
static_minionsGUIDS.insert(spawn->GetGUID());
majordomoSummonsData.erase(summon.second.guid.GetCounter());
majordomoSummonsData[spawn->GetGUID().GetCounter()] = MajordomoAddData(spawn->GetGUID(), spawn->GetEntry(), spawn->GetPosition());
}
}
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
else
{
static_minionsGUIDS.clear();
majordomoSummonsData.clear();
summons.DespawnAll();
}
}
bool CanAIAttack(Unit const* /*target*/) const override
{
return instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE;
}
void KilledUnit(Unit* victim) override
{
if (roll_chance_i(25) && victim->IsPlayer())
Talk(SAY_SLAY);
}
void JustEngagedWith(Unit* /*attacker*/) override
{
if (!events.IsInPhase(PHASE_COMBAT))
return;
_JustEngagedWith();
DoCastAOE(SPELL_SEPARATION_ANXIETY);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_AEGIS_OF_RAGNAROS, true);
events.ScheduleEvent(EVENT_SHIELD_REFLECTION, 30s, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_RANDOM, 25s, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_TARGET, 15s, PHASE_COMBAT, PHASE_COMBAT);
aliveMinionsGUIDS.clear();
aliveMinionsGUIDS = static_minionsGUIDS;
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
aliveMinionsGUIDS.erase(summon->GetGUID());
if (summon->GetEntry() == NPC_FLAMEWAKER_HEALER || summon->GetEntry() == NPC_FLAMEWAKER_ELITE)
{
uint32 const remainingAdds = std::count_if(aliveMinionsGUIDS.begin(), aliveMinionsGUIDS.end(), [](ObjectGuid const& summonGuid)
{
return summonGuid.GetEntry() == NPC_FLAMEWAKER_HEALER || summonGuid.GetEntry() == NPC_FLAMEWAKER_ELITE;
});
// Last remaining add
if (remainingAdds == 1)
{
Talk(SAY_LAST_ADD);
DoCastAOE(SPELL_CHAMPION);
}
// 50% of adds
else if (remainingAdds == 4)
{
DoCastAOE(SPELL_IMMUNE_POLY);
}
else if (!remainingAdds)
{
static_minionsGUIDS.clear();
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, DONE);
events.CancelEventGroup(PHASE_COMBAT);
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
me->SetImmuneToAll(true);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
EnterEvadeMode();
Talk(SAY_DEFEAT);
return;
}
DoCastAOE(SPELL_ENCOURAGEMENT);
}
}
void JustReachedHome() override
{
_JustReachedHome();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) == DONE)
{
events.Reset();
events.SetPhase(PHASE_DEFEAT_OUTRO);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_1, 7500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
if (events.IsInPhase(PHASE_COMBAT) && me->GetHealth() <= damage)
{
damage = 0;
}
}
void UpdateAI(uint32 diff) override
{
switch (events.GetPhaseMask())
{
case (1 << (PHASE_COMBAT - 1)):
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHIELD_REFLECTION:
{
if (rand_chance() <= 50.f)
{
DoCastSelf(SPELL_MAGIC_REFLECTION);
}
else
{
DoCastSelf(SPELL_DAMAGE_REFLECTION);
}
events.Repeat(30s);
break;
}
case EVENT_TELEPORT_RANDOM:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCast(target, SPELL_TELEPORT_RANDOM);
}
events.Repeat(30s);
break;
}
case EVENT_TELEPORT_TARGET:
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCastAOE(SPELL_TELEPORT_TARGET);
events.Repeat(30s);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
break;
}
case (1 << (PHASE_DEFEAT_OUTRO - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DEFEAT_OUTRO_1:
{
Talk(SAY_DEFEAT_2);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_2, 8s, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_2:
{
Talk(SAY_DEFEAT_3);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_3, 21500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_3:
{
DoCastSelf(SPELL_TELEPORT_SELF);
break;
}
}
}
break;
}
case (1 << (PHASE_RAGNAROS_SUMMONING - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RAGNAROS_SUMMON_1:
{
if (GameObject* lavaSplash = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_SPLASH)))
{
lavaSplash->SetRespawnTime(900);
lavaSplash->Refresh();
}
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
lavaSteam->SetRespawnTime(900);
lavaSteam->Refresh();
}
Talk(SAY_RAG_SUM_2);
// Next event will get triggered in MovementInform
me->SetWalk(true);
me->GetMotionMaster()->MovePoint(POINT_RAGNAROS_SUMMON, MajordomoMoveRagPos, FORCED_MOVEMENT_NONE, 0.f, true, false);
break;
}
case EVENT_RAGNAROS_SUMMON_2:
{
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
me->SetFacingToObject(lavaSteam);
}
Talk(SAY_SUMMON_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_3, 16700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_EMERGE, 15s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_3:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL1_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_4, 11700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_4:
{
Talk(SAY_ARRIVAL2_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_5, 8700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_5:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL3_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_6, 16500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_6:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->CastSpell(me, SPELL_ELEMENTAL_FIRE, true);
ragnaros->AI()->DoAction(ACTION_FINISH_RAGNAROS_INTRO);
}
break;
}
// Additional events
case EVENT_RAGNAROS_EMERGE:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->RemoveAurasDueToSpell(SPELL_RAGNAROS_FADE);
ragnaros->CastSpell(ragnaros, SPELL_RAGNA_EMERGE);
}
}break;
}
}
break;
}
}
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type == POINT_MOTION_TYPE && pointId == POINT_RAGNAROS_SUMMON)
{
DoCastAOE(SPELL_SUMMON_RAGNAROS);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_2, 11500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (events.IsInPhase(PHASE_DEFEAT_OUTRO) && spellInfo->Id == SPELL_TELEPORT_SELF)
{
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetHomePosition(MajordomoRagnaros);
me->NearTeleportTo(MajordomoRagnaros.GetPositionX(), MajordomoRagnaros.GetPositionY(), MajordomoRagnaros.GetPositionZ(), MajordomoRagnaros.GetOrientation());
events.SetPhase(PHASE_NONE);
}
}
void DoAction(int32 action) override
{
if (action == ACTION_START_RAGNAROS_INTRO && !events.IsInPhase(PHASE_RAGNAROS_SUMMONING))
{
events.SetPhase(PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_1, 5s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
void sGossipHello(Player* player) override
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, TEXT_ID_SUMMON_1, me->GetGUID());
}
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
switch (action) switch (action)
@@ -544,40 +521,39 @@ public:
case GOSSIP_ACTION_INFO_DEF: case GOSSIP_ACTION_INFO_DEF:
{ {
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID()); SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID());
break; break;
} }
case GOSSIP_ACTION_INFO_DEF+1: case GOSSIP_ACTION_INFO_DEF+1:
{ {
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID()); SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID());
break; break;
} }
case GOSSIP_ACTION_INFO_DEF+2: case GOSSIP_ACTION_INFO_DEF+2:
{ {
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
SendGossipMenuFor(player, TEXT_ID_SUMMON_3, creature->GetGUID()); SendGossipMenuFor(player, TEXT_ID_SUMMON_3, me->GetGUID());
break; break;
} }
case GOSSIP_ACTION_INFO_DEF+3: case GOSSIP_ACTION_INFO_DEF+3:
{ {
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
creature->AI()->Talk(SAY_RAG_SUM_1, player); Talk(SAY_RAG_SUM_1, player);
creature->AI()->DoAction(ACTION_START_RAGNAROS_INTRO); DoAction(ACTION_START_RAGNAROS_INTRO);
break; break;
} }
default: default:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
break; break;
} }
return true;
} }
CreatureAI* GetAI(Creature* creature) const override private:
{ GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion
return GetMoltenCoreAI<boss_majordomoAI>(creature); GuidSet aliveMinionsGUIDS; // used for calculations
} std::unordered_map<uint32, MajordomoAddData> majordomoSummonsData;
}; };
// 20538 Hate to Zero (SERVERSIDE) // 20538 Hate to Zero (SERVERSIDE)
@@ -593,12 +569,8 @@ class spell_hate_to_zero : public SpellScript
void HandleHit(SpellEffIndex /*effIndex*/) void HandleHit(SpellEffIndex /*effIndex*/)
{ {
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{
if (Creature* creatureCaster = caster->ToCreature()) if (Creature* creatureCaster = caster->ToCreature())
{
creatureCaster->GetThreatMgr().ResetAllThreat(); creatureCaster->GetThreatMgr().ResetAllThreat();
}
}
} }
void Register() override void Register() override
@@ -641,9 +613,7 @@ class spell_summon_ragnaros : public SpellScript
void HandleHit() void HandleHit()
{ {
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{
caster->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2 * HOUR * IN_MILLISECONDS); caster->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2 * HOUR * IN_MILLISECONDS);
}
} }
void Register() override void Register() override
@@ -654,7 +624,7 @@ class spell_summon_ragnaros : public SpellScript
void AddSC_boss_majordomo() void AddSC_boss_majordomo()
{ {
new boss_majordomo(); RegisterMoltenCoreCreatureAI(boss_majordomo);
// Spells // Spells
RegisterSpellScript(spell_hate_to_zero); RegisterSpellScript(spell_hate_to_zero);

View File

@@ -112,390 +112,353 @@ enum Misc
constexpr float DEATH_ORIENTATION = 4.0f; constexpr float DEATH_ORIENTATION = 4.0f;
class boss_ragnaros : public CreatureScript struct boss_ragnaros : public BossAI
{ {
public: boss_ragnaros(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
boss_ragnaros() : CreatureScript("boss_ragnaros") {} _isIntroDone(false),
_hasYelledMagmaBurst(false),
struct boss_ragnarosAI : public BossAI _processingMagmaBurst(false),
_hasSubmergedOnce(false),
_isKnockbackEmoteAllowed(true)
{ {
boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS), }
_isIntroDone(false),
_hasYelledMagmaBurst(false), void Reset() override
_processingMagmaBurst(false), {
_hasSubmergedOnce(false), _Reset();
_isKnockbackEmoteAllowed(true)
// Never reset intro events!
if (_isIntroDone && !(extraEvents.GetPhaseMask() & (1 << (PHASE_INTRO - 1))))
{ {
}
void Reset() override
{
_Reset();
// Never reset intro events!
if (_isIntroDone && !(extraEvents.GetPhaseMask() & (1 << (PHASE_INTRO - 1))))
{
extraEvents.Reset();
extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToAll(false);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
}
_hasYelledMagmaBurst = false;
_processingMagmaBurst = false;
_hasSubmergedOnce = false;
_isKnockbackEmoteAllowed = true;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->SetControlled(true, UNIT_STATE_ROOT);
_lavaBurstGUIDS.clear();
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (events.IsInPhase(PHASE_SUBMERGED) && damage >= me->GetHealth())
{
damage = 0;
}
}
void DoAction(int32 action) override
{
if (action == ACTION_FINISH_RAGNAROS_INTRO)
{
extraEvents.SetPhase(PHASE_INTRO);
extraEvents.ScheduleEvent(EVENT_INTRO_SAY, 5s, 0, PHASE_INTRO);
}
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
if (summon->GetEntry() == NPC_FLAME_OF_RAGNAROS)
{
summon->CastSpell((Unit*)nullptr, SPELL_INTENSE_HEAT, true, nullptr, nullptr, me->GetGUID());
}
else if (summon->GetEntry() == NPC_SON_OF_FLAME)
{
DoZoneInCombat(summon);
}
}
void SetGUID(ObjectGuid const& guid, int32 index) override
{
if (index == GO_LAVA_BURST)
{
if (_lavaBurstGUIDS.empty())
{
extraEvents.ScheduleEvent(EVENT_LAVA_BURST_TRIGGER, 1ms);
}
_lavaBurstGUIDS.insert(guid);
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
summons.Despawn(summon);
if (events.IsInPhase(PHASE_SUBMERGED) && !summons.HasEntry(NPC_SON_OF_FLAME))
{
HandleEmerge();
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
extraEvents.Reset(); extraEvents.Reset();
me->SetFacingTo(DEATH_ORIENTATION); extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToAll(false);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
} }
void KilledUnit(Unit* victim) override _hasYelledMagmaBurst = false;
_processingMagmaBurst = false;
_hasSubmergedOnce = false;
_isKnockbackEmoteAllowed = true;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->SetControlled(true, UNIT_STATE_ROOT);
_lavaBurstGUIDS.clear();
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (events.IsInPhase(PHASE_SUBMERGED) && damage >= me->GetHealth())
{ {
if (roll_chance_i(25) && victim->IsPlayer()) damage = 0;
}
}
void DoAction(int32 action) override
{
if (action == ACTION_FINISH_RAGNAROS_INTRO)
{
extraEvents.SetPhase(PHASE_INTRO);
extraEvents.ScheduleEvent(EVENT_INTRO_SAY, 5s, 0, PHASE_INTRO);
}
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
if (summon->GetEntry() == NPC_FLAME_OF_RAGNAROS)
summon->CastSpell((Unit*)nullptr, SPELL_INTENSE_HEAT, true, nullptr, nullptr, me->GetGUID());
else if (summon->GetEntry() == NPC_SON_OF_FLAME)
DoZoneInCombat(summon);
}
void SetGUID(ObjectGuid const& guid, int32 index) override
{
if (index == GO_LAVA_BURST)
{
if (_lavaBurstGUIDS.empty())
extraEvents.ScheduleEvent(EVENT_LAVA_BURST_TRIGGER, 1ms);
_lavaBurstGUIDS.insert(guid);
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
summons.Despawn(summon);
if (events.IsInPhase(PHASE_SUBMERGED) && !summons.HasEntry(NPC_SON_OF_FLAME))
HandleEmerge();
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
extraEvents.Reset();
me->SetFacingTo(DEATH_ORIENTATION);
}
void KilledUnit(Unit* victim) override
{
if (roll_chance_i(25) && victim->IsPlayer())
Talk(SAY_KILL);
}
void AttackStart(Unit* target) override
{
if (target && me->Attack(target, true))
DoStartNoMovement(target);
}
void EnterEvadeMode(EvadeReason why) override
{
if (!me->GetThreatMgr().IsThreatListEmpty())
{
if (!_processingMagmaBurst)
{ {
Talk(SAY_KILL); // Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED);
} }
} }
else
void AttackStart(Unit* target) override
{ {
if (target && me->Attack(target, true)) BossAI::EnterEvadeMode(why);
{
DoStartNoMovement(target);
}
} }
}
void EnterEvadeMode(EvadeReason why) override bool CanAIAttack(Unit const* victim) const override
{
// Used for Magma Blast handling to force EnterEvadeMode if there are no melee targets
return me->IsWithinMeleeRange(victim);
}
void UpdateAI(uint32 diff) override
{
if (!extraEvents.Empty())
{ {
if (!me->GetThreatMgr().IsThreatListEmpty()) extraEvents.Update(diff);
{
if (!_processingMagmaBurst)
{
// Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED);
}
}
else
{
BossAI::EnterEvadeMode(why);
}
}
bool CanAIAttack(Unit const* victim) const override while (uint32 const eventId = extraEvents.ExecuteEvent())
{
// Used for Magma Blast handling to force EnterEvadeMode if there are no melee targets
return me->IsWithinMeleeRange(victim);
}
void UpdateAI(uint32 diff) override
{
if (!extraEvents.Empty())
{
extraEvents.Update(diff);
while (uint32 const eventId = extraEvents.ExecuteEvent())
{
switch (eventId)
{
// Intro events
case EVENT_INTRO_SAY:
{
Talk(SAY_ARRIVAL5_RAG);
extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500ms, 0, PHASE_INTRO);
break;
}
case EVENT_INTRO_MAKE_ATTACKABLE:
{
_isIntroDone = true;
extraEvents.SetPhase(PHASE_EMERGED);
me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
break;
}
// Submerge events
case EVENT_EMERGE:
{
HandleEmerge();
break;
}
case EVENT_RESET_KNOCKBACK_EMOTE:
{
_isKnockbackEmoteAllowed = true;
break;
}
case EVENT_LAVA_BURST_TRIGGER:
{
if (!_lavaBurstGUIDS.empty())
{
ObjectGuid lavaBurstGUID = Acore::Containers::SelectRandomContainerElement(_lavaBurstGUIDS);
if (GameObject* go = ObjectAccessor::GetGameObject(*me, lavaBurstGUID))
{
go->CastSpell(nullptr, SPELL_LAVA_BURST_TRAP);
go->SendCustomAnim(0);
}
_lavaBurstGUIDS.erase(lavaBurstGUID);
extraEvents.Repeat(1s);
}
else
{
events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED);
}
break;
}
}
}
}
if (!UpdateVictim())
{
if (!_processingMagmaBurst)
{
return;
}
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
// Base combat events - (mainly emerge phase)
while (uint32 const eventId = events.ExecuteEvent())
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_WRATH_OF_RAGNAROS: // Intro events
case EVENT_INTRO_SAY:
{ {
DoCastVictim(SPELL_WRATH_OF_RAGNAROS); Talk(SAY_ARRIVAL5_RAG);
extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500ms, 0, PHASE_INTRO);
if (urand(0, 1))
{
Talk(SAY_WRATH);
}
events.Repeat(25s);
break; break;
} }
case EVENT_HAND_OF_RAGNAROS: case EVENT_INTRO_MAKE_ATTACKABLE:
{ {
DoCastSelf(SPELL_HAND_OF_RAGNAROS); _isIntroDone = true;
if (_isKnockbackEmoteAllowed) extraEvents.SetPhase(PHASE_EMERGED);
me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(false);
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
break;
}
// Submerge events
case EVENT_EMERGE:
{
HandleEmerge();
break;
}
case EVENT_RESET_KNOCKBACK_EMOTE:
{
_isKnockbackEmoteAllowed = true;
break;
}
case EVENT_LAVA_BURST_TRIGGER:
{
if (!_lavaBurstGUIDS.empty())
{ {
Talk(SAY_KNOCKBACK); ObjectGuid lavaBurstGUID = Acore::Containers::SelectRandomContainerElement(_lavaBurstGUIDS);
if (GameObject* go = ObjectAccessor::GetGameObject(*me, lavaBurstGUID))
{
go->CastSpell(nullptr, SPELL_LAVA_BURST_TRAP);
go->SendCustomAnim(0);
}
_lavaBurstGUIDS.erase(lavaBurstGUID);
extraEvents.Repeat(1s);
}
else
{
events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED);
}
break;
}
}
}
}
if (!UpdateVictim())
{
if (!_processingMagmaBurst)
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
// Base combat events - (mainly emerge phase)
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_WRATH_OF_RAGNAROS:
{
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
if (urand(0, 1))
Talk(SAY_WRATH);
events.Repeat(25s);
break;
}
case EVENT_HAND_OF_RAGNAROS:
{
DoCastSelf(SPELL_HAND_OF_RAGNAROS);
if (_isKnockbackEmoteAllowed)
{
Talk(SAY_KNOCKBACK);
_isKnockbackEmoteAllowed = false;
extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s);
}
events.Repeat(20s);
break;
}
case EVENT_LAVA_BURST:
{
DoCastAOE(SPELL_LAVA_BURST);
break;
}
case EVENT_MAGMA_BLAST:
{
_processingMagmaBurst = false;
if (!IsVictimWithinMeleeRange())
{
DoCastRandomTarget(SPELL_MAGMA_BLAST);
if (!_hasYelledMagmaBurst)
{
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
}
break;
}
case EVENT_MIGHT_OF_RAGNAROS:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [](Unit const* target)
{
return target->IsPlayer() && target->getPowerType() == POWER_MANA;
}))
{
if (me->CastSpell(target, SPELL_MIGHT_OF_RAGNAROS) == SPELL_CAST_OK && _isKnockbackEmoteAllowed)
{
Talk(SAY_KNOCKBACK, me);
_isKnockbackEmoteAllowed = false; _isKnockbackEmoteAllowed = false;
extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s); extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s);
} }
events.Repeat(20s);
break;
}
case EVENT_LAVA_BURST:
{
DoCastAOE(SPELL_LAVA_BURST);
break;
}
case EVENT_MAGMA_BLAST:
{
_processingMagmaBurst = false;
if (!IsVictimWithinMeleeRange())
{
DoCastRandomTarget(SPELL_MAGMA_BLAST);
if (!_hasYelledMagmaBurst)
{
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
}
break;
}
case EVENT_MIGHT_OF_RAGNAROS:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [](Unit const* target)
{
return target->IsPlayer() && target->getPowerType() == POWER_MANA;
}))
{
if (me->CastSpell(target, SPELL_MIGHT_OF_RAGNAROS) == SPELL_CAST_OK && _isKnockbackEmoteAllowed)
{
Talk(SAY_KNOCKBACK, me);
_isKnockbackEmoteAllowed = false;
extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s);
}
}
events.Repeat(11s, 30s);
break;
}
case EVENT_SUBMERGE:
{
events.CancelEventGroup(PHASE_EMERGED);
events.SetPhase(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_SUBMERGED);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(false);
me->AttackStop();
DoResetThreatList();
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true);
//me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1);
DoCastAOE(SPELL_SUMMON_SONS_FLAME);
if (!_hasSubmergedOnce)
{
_hasSubmergedOnce = true;
}
extraEvents.ScheduleEvent(EVENT_EMERGE, 90s, PHASE_SUBMERGED, PHASE_SUBMERGED);
break;
} }
events.Repeat(11s, 30s);
break;
} }
case EVENT_SUBMERGE:
if (me->HasUnitState(UNIT_STATE_CASTING))
{ {
return; events.CancelEventGroup(PHASE_EMERGED);
events.SetPhase(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_SUBMERGED);
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(false);
me->AttackStop();
DoResetThreatList();
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true);
//me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1);
DoCastAOE(SPELL_SUMMON_SONS_FLAME);
if (!_hasSubmergedOnce)
_hasSubmergedOnce = true;
extraEvents.ScheduleEvent(EVENT_EMERGE, 90s, PHASE_SUBMERGED, PHASE_SUBMERGED);
break;
} }
} }
DoMeleeAttackIfReady(); if (me->HasUnitState(UNIT_STATE_CASTING))
}
private:
EventMap extraEvents;
bool _isIntroDone;
bool _hasYelledMagmaBurst;
bool _processingMagmaBurst;
bool _hasSubmergedOnce;
bool _isKnockbackEmoteAllowed; // Prevents possible text overlap
GuidSet _lavaBurstGUIDS;
void HandleEmerge()
{
if (events.IsInPhase(PHASE_EMERGED))
{
return; return;
}
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
extraEvents.CancelEventGroup(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
me->RemoveAurasDueToSpell(SPELL_RAGNA_SUBMERGE_VISUAL);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
AttackStart(target);
}
} }
void ScheduleCombatEvents() DoMeleeAttackIfReady();
{ }
events.RescheduleEvent(EVENT_ERUPTION, 15s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_SUBMERGE, 180s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11s, PHASE_EMERGED, PHASE_EMERGED);
}
bool IsVictimWithinMeleeRange() const private:
{ EventMap extraEvents;
return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()); bool _isIntroDone;
} bool _hasYelledMagmaBurst;
}; bool _processingMagmaBurst;
bool _hasSubmergedOnce;
bool _isKnockbackEmoteAllowed; // Prevents possible text overlap
CreatureAI* GetAI(Creature* creature) const override GuidSet _lavaBurstGUIDS;
void HandleEmerge()
{ {
return GetMoltenCoreAI<boss_ragnarosAI>(creature); if (events.IsInPhase(PHASE_EMERGED))
return;
events.SetPhase(PHASE_EMERGED);
ScheduleCombatEvents();
extraEvents.CancelEventGroup(PHASE_SUBMERGED);
extraEvents.SetPhase(PHASE_EMERGED);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
me->RemoveAurasDueToSpell(SPELL_RAGNA_SUBMERGE_VISUAL);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
AttackStart(target);
}
void ScheduleCombatEvents()
{
events.RescheduleEvent(EVENT_ERUPTION, 15s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_SUBMERGE, 180s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11s, PHASE_EMERGED, PHASE_EMERGED);
}
bool IsVictimWithinMeleeRange() const
{
return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim());
} }
}; };
@@ -547,9 +510,7 @@ class spell_ragnaros_summon_sons_of_flame : public SpellScript
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{ {
for (uint32 spell : RagnarosSoFSpells) for (uint32 spell : RagnarosSoFSpells)
{
caster->CastSpell(caster, spell, true); caster->CastSpell(caster, spell, true);
}
} }
} }
@@ -561,7 +522,7 @@ class spell_ragnaros_summon_sons_of_flame : public SpellScript
void AddSC_boss_ragnaros() void AddSC_boss_ragnaros()
{ {
new boss_ragnaros(); RegisterMoltenCoreCreatureAI(boss_ragnaros);
RegisterSpellScript(spell_ragnaros_lava_burst_randomizer); RegisterSpellScript(spell_ragnaros_lava_burst_randomizer);
RegisterSpellScript(spell_ragnaros_summon_sons_of_flame); RegisterSpellScript(spell_ragnaros_summon_sons_of_flame);
} }

View File

@@ -41,70 +41,57 @@ enum Events
EVENT_SHAZZRAH_GATE, EVENT_SHAZZRAH_GATE,
}; };
class boss_shazzrah : public CreatureScript struct boss_shazzrah : public BossAI
{ {
public: boss_shazzrah(Creature* creature) : BossAI(creature, DATA_SHAZZRAH) {}
boss_shazzrah() : CreatureScript("boss_shazzrah") { }
struct boss_shazzrahAI : public BossAI void JustEngagedWith(Unit* /*target*/) override
{ {
boss_shazzrahAI(Creature* creature) : BossAI(creature, DATA_SHAZZRAH) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2s, 4s);
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 7s,11s);
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 14s, 19s);
events.ScheduleEvent(EVENT_COUNTERSPELL, 9s, 10s);
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 30s);
}
void JustEngagedWith(Unit* /*target*/) override void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
_JustEngagedWith(); case EVENT_ARCANE_EXPLOSION:
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2s, 4s);
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 7s,11s);
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 14s, 19s);
events.ScheduleEvent(EVENT_COUNTERSPELL, 9s, 10s);
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 30s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
case EVENT_ARCANE_EXPLOSION: DoCastVictim(SPELL_ARCANE_EXPLOSION);
{ events.Repeat(4s, 5s);
DoCastVictim(SPELL_ARCANE_EXPLOSION); break;
events.Repeat(4s, 5s); }
break; case EVENT_SHAZZRAH_CURSE:
} {
case EVENT_SHAZZRAH_CURSE: if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE))
{ DoCast(target, SPELL_SHAZZRAH_CURSE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE)) events.Repeat(23s, 26s);
{ break;
DoCast(target, SPELL_SHAZZRAH_CURSE); }
} case EVENT_MAGIC_GROUNDING:
events.Repeat(23s, 26s); {
break; DoCastSelf(SPELL_MAGIC_GROUNDING);
} events.Repeat(7s, 9s);
case EVENT_MAGIC_GROUNDING: break;
{ }
DoCastSelf(SPELL_MAGIC_GROUNDING); case EVENT_COUNTERSPELL:
events.Repeat(7s, 9s); {
break; DoCastAOE(SPELL_COUNTERSPELL);
} events.Repeat(15s, 18s);
case EVENT_COUNTERSPELL: break;
{ }
DoCastAOE(SPELL_COUNTERSPELL); case EVENT_SHAZZRAH_GATE:
events.Repeat(15s, 18s); {
break; DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
} events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, 3s, 6s);
case EVENT_SHAZZRAH_GATE: events.Repeat(45s);
{ break;
DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, 3s, 6s);
events.Repeat(45s);
break;
}
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_shazzrahAI>(creature);
} }
}; };
@@ -128,30 +115,22 @@ class spell_shazzrah_gate_dummy : public SpellScript
Player const* plrTarget = target->ToPlayer(); Player const* plrTarget = target->ToPlayer();
// Should not target non player targets // Should not target non player targets
if (!plrTarget) if (!plrTarget)
{
return true; return true;
}
// Should skip current victim // Should skip current victim
if (caster->GetVictim() == plrTarget) if (caster->GetVictim() == plrTarget)
{
return true; return true;
}
// Should not target enemies within melee range // Should not target enemies within melee range
if (plrTarget->IsWithinMeleeRange(caster)) if (plrTarget->IsWithinMeleeRange(caster))
{
return true; return true;
}
return false; return false;
}); });
} }
if (!targets.empty()) if (!targets.empty())
{
Acore::Containers::RandomResize(targets, 1); Acore::Containers::RandomResize(targets, 1);
}
} }
void HandleScript(SpellEffIndex /*effIndex*/) void HandleScript(SpellEffIndex /*effIndex*/)
@@ -182,7 +161,7 @@ class spell_shazzrah_gate_dummy : public SpellScript
void AddSC_boss_shazzrah() void AddSC_boss_shazzrah()
{ {
new boss_shazzrah(); RegisterMoltenCoreCreatureAI(boss_shazzrah);
// Spells // Spells
RegisterSpellScript(spell_shazzrah_gate_dummy); RegisterSpellScript(spell_shazzrah_gate_dummy);

View File

@@ -47,172 +47,138 @@ enum Events
EVENT_IMMOLATE, EVENT_IMMOLATE,
}; };
class boss_sulfuron : public CreatureScript struct boss_sulfuron : public BossAI
{ {
public: boss_sulfuron(Creature* creature) : BossAI(creature, DATA_SULFURON) {}
boss_sulfuron() : CreatureScript("boss_sulfuron") {}
struct boss_sulfuronAI : public BossAI void JustEngagedWith(Unit* /*who*/) override
{ {
boss_sulfuronAI(Creature* creature) : BossAI(creature, DATA_SULFURON) {} _JustEngagedWith();
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 6s, 20s);
events.ScheduleEvent(EVENT_INSPIRE, 7s, 10s);
events.ScheduleEvent(EVENT_KNOCKDOWN, 6s);
events.ScheduleEvent(EVENT_FLAMESPEAR, 2s);
}
void JustEngagedWith(Unit* /*who*/) override void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
_JustEngagedWith(); case EVENT_DEMORALIZING_SHOUT:
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 6s, 20s);
events.ScheduleEvent(EVENT_INSPIRE, 7s, 10s);
events.ScheduleEvent(EVENT_KNOCKDOWN, 6s);
events.ScheduleEvent(EVENT_FLAMESPEAR, 2s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
case EVENT_DEMORALIZING_SHOUT: DoCastVictim(SPELL_DEMORALIZING_SHOUT);
{ events.Repeat(12s, 18s);
DoCastVictim(SPELL_DEMORALIZING_SHOUT); break;
events.Repeat(12s, 18s); }
break; case EVENT_INSPIRE:
} {
case EVENT_INSPIRE: std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
{ if (!healers.empty())
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE); DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
if (!healers.empty())
{
DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
}
DoCastSelf(SPELL_INSPIRE); DoCastSelf(SPELL_INSPIRE);
events.Repeat(13s, 20s); events.Repeat(13s, 20s);
break; break;
} }
case EVENT_KNOCKDOWN: case EVENT_KNOCKDOWN:
{ {
DoCastVictim(SPELL_KNOCKDOWN); DoCastVictim(SPELL_KNOCKDOWN);
events.Repeat(10s, 20s); events.Repeat(10s, 20s);
break; break;
} }
case EVENT_FLAMESPEAR: case EVENT_FLAMESPEAR:
{ {
DoCastRandomTarget(SPELL_FLAMESPEAR); DoCastRandomTarget(SPELL_FLAMESPEAR);
events.Repeat(12s, 16s); events.Repeat(12s, 16s);
break; break;
}
} }
} }
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_sulfuronAI>(creature);
} }
}; };
class npc_flamewaker_priest : public CreatureScript struct npc_flamewaker_priest : public ScriptedAI
{ {
public: npc_flamewaker_priest(Creature* creature) : ScriptedAI(creature) {}
npc_flamewaker_priest() : CreatureScript("npc_flamewaker_priest") {}
struct npc_flamewaker_priestAI : public ScriptedAI void Reset() override
{ {
npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature) {} events.Reset();
}
void Reset() override void JustDied(Unit* /*killer*/) override
{ {
events.Reset(); events.Reset();
} }
void JustDied(Unit* /*killer*/) override void JustEngagedWith(Unit* /*who*/) override
{ {
events.Reset(); events.ScheduleEvent(EVENT_DARK_STRIKE, 4s, 7s);
} events.ScheduleEvent(EVENT_DARK_MENDING, 15s, 30s);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2s, 4s);
events.ScheduleEvent(EVENT_IMMOLATE, 3500ms, 6s);
}
void JustEngagedWith(Unit* /*who*/) override void UpdateAI(uint32 diff) override
{ {
events.ScheduleEvent(EVENT_DARK_STRIKE, 4s, 7s); if (!UpdateVictim())
events.ScheduleEvent(EVENT_DARK_MENDING, 15s, 30s); return;
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2s, 4s);
events.ScheduleEvent(EVENT_IMMOLATE, 3500ms, 6s);
}
void UpdateAI(uint32 diff) override events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 const eventId = events.ExecuteEvent())
{ {
if (!UpdateVictim()) switch (eventId)
{ {
return; case EVENT_DARK_STRIKE:
{
DoCastVictim(SPELL_DARK_STRIKE);
events.Repeat(4s, 7s);
break;
}
case EVENT_DARK_MENDING:
{
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1))
{
if (target->GetGUID() != me->GetGUID())
{
DoCast(target, SPELL_DARK_MENDING);
}
}
events.Repeat(15s, 20s);
break;
}
case EVENT_SHADOW_WORD_PAIN:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHADOW_WORD_PAIN))
DoCast(target, SPELL_SHADOW_WORD_PAIN);
events.Repeat(2500ms, 5s);
break;
}
case EVENT_IMMOLATE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IMMOLATE))
DoCast(target, SPELL_IMMOLATE);
events.Repeat(5s, 7s);
break;
}
} }
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DARK_STRIKE:
{
DoCastVictim(SPELL_DARK_STRIKE);
events.Repeat(4s, 7s);
break;
}
case EVENT_DARK_MENDING:
{
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1))
{
if (target->GetGUID() != me->GetGUID())
{
DoCast(target, SPELL_DARK_MENDING);
}
}
events.Repeat(15s, 20s);
break;
}
case EVENT_SHADOW_WORD_PAIN:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHADOW_WORD_PAIN))
{
DoCast(target, SPELL_SHADOW_WORD_PAIN);
}
events.Repeat(2500ms, 5s);
break;
}
case EVENT_IMMOLATE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IMMOLATE))
{
DoCast(target, SPELL_IMMOLATE);
}
events.Repeat(5s, 7s);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
} }
private: DoMeleeAttackIfReady();
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_flamewaker_priestAI>(creature);
} }
private:
EventMap events;
}; };
void AddSC_boss_sulfuron() void AddSC_boss_sulfuron()
{ {
new boss_sulfuron(); RegisterMoltenCoreCreatureAI(boss_sulfuron);
new npc_flamewaker_priest(); RegisterMoltenCoreCreatureAI(npc_flamewaker_priest);
} }

View File

@@ -53,384 +53,331 @@ MCBossObject const linkedBossObjData[MAX_MC_LINKED_BOSS_OBJ]=
constexpr uint8 SAY_SPAWN = 1; constexpr uint8 SAY_SPAWN = 1;
class instance_molten_core : public InstanceMapScript struct instance_molten_core : public InstanceScript
{ {
public: instance_molten_core(Map* map) : InstanceScript(map)
instance_molten_core() : InstanceMapScript(MCScriptName, MAP_MOLTEN_CORE) {}
struct instance_molten_core_InstanceMapScript : public InstanceScript
{ {
instance_molten_core_InstanceMapScript(Map* map) : InstanceScript(map) SetHeaders(DataHeader);
{ SetBossNumber(MAX_ENCOUNTER);
SetHeaders(DataHeader); LoadMinionData(minionData);
SetBossNumber(MAX_ENCOUNTER);
LoadMinionData(minionData);
}
void OnPlayerEnter(Player* /*player*/) override
{
if (CheckMajordomoExecutus())
{
SummonMajordomoExecutus();
}
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_GOLEMAGG_THE_INCINERATOR:
{
_golemaggGUID = creature->GetGUID();
break;
}
case NPC_CORE_RAGER:
{
_golemaggMinionsGUIDS.insert(creature->GetGUID());
break;
}
case NPC_MAJORDOMO_EXECUTUS:
{
_majordomoExecutusGUID = creature->GetGUID();
break;
}
case NPC_GARR:
{
_garrGUID = creature->GetGUID();
break;
}
case NPC_RAGNAROS:
{
_ragnarosGUID = creature->GetGUID();
break;
}
case NPC_FIRESWORN:
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
AddMinion(creature);
break;
}
}
}
void OnCreatureRemove(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_FIRESWORN:
{
RemoveMinion(creature);
break;
}
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
RemoveMinion(creature);
break;
}
}
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_CACHE_OF_THE_FIRELORD:
{
_cacheOfTheFirelordGUID = go->GetGUID();
break;
}
case GO_CIRCLE_GEDDON:
case GO_CIRCLE_GARR:
case GO_CIRCLE_GEHENNAS:
case GO_CIRCLE_GOLEMAGG:
case GO_CIRCLE_MAGMADAR:
case GO_CIRCLE_SHAZZRAH:
case GO_CIRCLE_SULFURON:
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].circleId != go->GetEntry())
{
continue;
}
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
{
go->DespawnOrUnsummon(0ms, Seconds(WEEK));
}
else
{
_circlesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
}
break;
}
case GO_RUNE_KRESS:
case GO_RUNE_MOHN:
case GO_RUNE_BLAZ:
case GO_RUNE_MAZJ:
case GO_RUNE_ZETH:
case GO_RUNE_THERI:
case GO_RUNE_KORO:
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].runeId != go->GetEntry())
{
continue;
}
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
{
go->UseDoorOrButton(WEEK * IN_MILLISECONDS);
}
else
{
_runesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
}
break;
}
case GO_LAVA_STEAM:
{
_lavaSteamGUID = go->GetGUID();
break;
}
case GO_LAVA_SPLASH:
{
_lavaSplashGUID = go->GetGUID();
break;
}
case GO_LAVA_BURST:
{
if (Creature* ragnaros = instance->GetCreature(_ragnarosGUID))
{
ragnaros->AI()->SetGUID(go->GetGUID(), GO_LAVA_BURST);
}
break;
}
}
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_GOLEMAGG:
return _golemaggGUID;
case DATA_MAJORDOMO_EXECUTUS:
return _majordomoExecutusGUID;
case DATA_GARR:
return _garrGUID;
case DATA_LAVA_STEAM:
return _lavaSteamGUID;
case DATA_LAVA_SPLASH:
return _lavaSplashGUID;
case DATA_RAGNAROS:
return _ragnarosGUID;
}
return ObjectGuid::Empty;
}
bool SetBossState(uint32 bossId, EncounterState state) override
{
if (!InstanceScript::SetBossState(bossId, state))
{
return false;
}
if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
if (GameObject* cache = instance->GetGameObject(_cacheOfTheFirelordGUID))
{
cache->SetRespawnTime(7 * DAY);
cache->SetLootRecipient(instance);
}
}
else if (bossId == DATA_GOLEMAGG)
{
switch (state)
{
case NOT_STARTED:
case FAIL:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
Creature* minion = instance->GetCreature(minionGuid);
if (minion && minion->isDead())
{
minion->Respawn();
}
}
}
break;
}
case IN_PROGRESS:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->AI()->DoZoneInCombat(nullptr, 150.0f);
}
}
}
break;
}
case DONE:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->CastSpell(minion, SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
}
_golemaggMinionsGUIDS.clear();
}
break;
}
default:
break;
}
}
// Perform needed checks for Majordomu
if (bossId < DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
if (GameObject* circle = instance->GetGameObject(_circlesGUIDs[bossId]))
{
circle->DespawnOrUnsummon(0ms, Seconds(WEEK));
_circlesGUIDs[bossId].Clear();
}
if (GameObject* rune = instance->GetGameObject(_runesGUIDs[bossId]))
{
rune->UseDoorOrButton(WEEK * IN_MILLISECONDS);
_runesGUIDs[bossId].Clear();
}
if (CheckMajordomoExecutus())
{
SummonMajordomoExecutus();
}
}
return true;
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET_GOLEMAGG_ENCOUNTER)
{
if (Creature* golemagg = instance->GetCreature(_golemaggGUID))
{
golemagg->AI()->EnterEvadeMode();
}
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->AI()->EnterEvadeMode();
}
}
}
}
}
void SummonMajordomoExecutus()
{
if (instance->GetCreature(_majordomoExecutusGUID))
{
return;
}
if (GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
if (Creature* creature = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoSummonPos))
{
creature->AI()->Talk(SAY_SPAWN);
}
}
else
{
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoRagnaros);
}
}
bool CheckMajordomoExecutus() const
{
if (GetBossState(DATA_RAGNAROS) == DONE)
{
return false;
}
for (uint8 i = 0; i < DATA_MAJORDOMO_EXECUTUS; ++i)
{
if (i == DATA_LUCIFRON)
{
continue;
}
if (GetBossState(i) != DONE)
{
return false;
}
}
// Prevent spawning if Ragnaros is present
if (instance->GetCreature(_ragnarosGUID))
{
return false;
}
return true;
}
private:
std::unordered_map<uint32/*bossid*/, ObjectGuid/*circleGUID*/> _circlesGUIDs;
std::unordered_map<uint32/*bossid*/, ObjectGuid/*runeGUID*/> _runesGUIDs;
// Golemagg encounter related
ObjectGuid _golemaggGUID;
GuidSet _golemaggMinionsGUIDS;
// Ragnaros encounter related
ObjectGuid _ragnarosGUID;
ObjectGuid _lavaSteamGUID;
ObjectGuid _lavaSplashGUID;
ObjectGuid _majordomoExecutusGUID;
ObjectGuid _cacheOfTheFirelordGUID;
ObjectGuid _garrGUID;
ObjectGuid _magmadarGUID;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_molten_core_InstanceMapScript(map);
} }
void OnPlayerEnter(Player* /*player*/) override
{
if (CheckMajordomoExecutus())
SummonMajordomoExecutus();
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_GOLEMAGG_THE_INCINERATOR:
{
_golemaggGUID = creature->GetGUID();
break;
}
case NPC_CORE_RAGER:
{
_golemaggMinionsGUIDS.insert(creature->GetGUID());
break;
}
case NPC_MAJORDOMO_EXECUTUS:
{
_majordomoExecutusGUID = creature->GetGUID();
break;
}
case NPC_GARR:
{
_garrGUID = creature->GetGUID();
break;
}
case NPC_RAGNAROS:
{
_ragnarosGUID = creature->GetGUID();
break;
}
case NPC_FIRESWORN:
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
AddMinion(creature);
break;
}
}
}
void OnCreatureRemove(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_FIRESWORN:
{
RemoveMinion(creature);
break;
}
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
RemoveMinion(creature);
break;
}
}
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_CACHE_OF_THE_FIRELORD:
{
_cacheOfTheFirelordGUID = go->GetGUID();
break;
}
case GO_CIRCLE_GEDDON:
case GO_CIRCLE_GARR:
case GO_CIRCLE_GEHENNAS:
case GO_CIRCLE_GOLEMAGG:
case GO_CIRCLE_MAGMADAR:
case GO_CIRCLE_SHAZZRAH:
case GO_CIRCLE_SULFURON:
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].circleId != go->GetEntry())
continue;
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
go->DespawnOrUnsummon(0ms, Seconds(WEEK));
else
_circlesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
break;
}
case GO_RUNE_KRESS:
case GO_RUNE_MOHN:
case GO_RUNE_BLAZ:
case GO_RUNE_MAZJ:
case GO_RUNE_ZETH:
case GO_RUNE_THERI:
case GO_RUNE_KORO:
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].runeId != go->GetEntry())
continue;
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
go->UseDoorOrButton(WEEK * IN_MILLISECONDS);
else
_runesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
break;
}
case GO_LAVA_STEAM:
{
_lavaSteamGUID = go->GetGUID();
break;
}
case GO_LAVA_SPLASH:
{
_lavaSplashGUID = go->GetGUID();
break;
}
case GO_LAVA_BURST:
{
if (Creature* ragnaros = instance->GetCreature(_ragnarosGUID))
ragnaros->AI()->SetGUID(go->GetGUID(), GO_LAVA_BURST);
break;
}
}
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_GOLEMAGG:
return _golemaggGUID;
case DATA_MAJORDOMO_EXECUTUS:
return _majordomoExecutusGUID;
case DATA_GARR:
return _garrGUID;
case DATA_LAVA_STEAM:
return _lavaSteamGUID;
case DATA_LAVA_SPLASH:
return _lavaSplashGUID;
case DATA_RAGNAROS:
return _ragnarosGUID;
}
return ObjectGuid::Empty;
}
bool SetBossState(uint32 bossId, EncounterState state) override
{
if (!InstanceScript::SetBossState(bossId, state))
return false;
if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
if (GameObject* cache = instance->GetGameObject(_cacheOfTheFirelordGUID))
{
cache->SetRespawnTime(7 * DAY);
cache->SetLootRecipient(instance);
}
}
else if (bossId == DATA_GOLEMAGG)
{
switch (state)
{
case NOT_STARTED:
case FAIL:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
Creature* minion = instance->GetCreature(minionGuid);
if (minion && minion->isDead())
minion->Respawn();
}
}
break;
}
case IN_PROGRESS:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
minion->AI()->DoZoneInCombat(nullptr, 150.0f);
}
}
break;
}
case DONE:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
minion->CastSpell(minion, SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
_golemaggMinionsGUIDS.clear();
}
break;
}
default:
break;
}
}
// Perform needed checks for Majordomu
if (bossId < DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
if (GameObject* circle = instance->GetGameObject(_circlesGUIDs[bossId]))
{
circle->DespawnOrUnsummon(0ms, Seconds(WEEK));
_circlesGUIDs[bossId].Clear();
}
if (GameObject* rune = instance->GetGameObject(_runesGUIDs[bossId]))
{
rune->UseDoorOrButton(WEEK * IN_MILLISECONDS);
_runesGUIDs[bossId].Clear();
}
if (CheckMajordomoExecutus())
SummonMajordomoExecutus();
}
return true;
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET_GOLEMAGG_ENCOUNTER)
{
if (Creature* golemagg = instance->GetCreature(_golemaggGUID))
golemagg->AI()->EnterEvadeMode();
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
minion->AI()->EnterEvadeMode();
}
}
}
}
void SummonMajordomoExecutus()
{
if (instance->GetCreature(_majordomoExecutusGUID))
return;
if (GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
if (Creature* creature = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoSummonPos))
creature->AI()->Talk(SAY_SPAWN);
}
else
{
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoRagnaros);
}
}
bool CheckMajordomoExecutus() const
{
if (GetBossState(DATA_RAGNAROS) == DONE)
return false;
for (uint8 i = 0; i < DATA_MAJORDOMO_EXECUTUS; ++i)
{
if (i == DATA_LUCIFRON)
continue;
if (GetBossState(i) != DONE)
return false;
}
// Prevent spawning if Ragnaros is present
if (instance->GetCreature(_ragnarosGUID))
return false;
return true;
}
private:
std::unordered_map<uint32/*bossid*/, ObjectGuid/*circleGUID*/> _circlesGUIDs;
std::unordered_map<uint32/*bossid*/, ObjectGuid/*runeGUID*/> _runesGUIDs;
// Golemagg encounter related
ObjectGuid _golemaggGUID;
GuidSet _golemaggMinionsGUIDS;
// Ragnaros encounter related
ObjectGuid _ragnarosGUID;
ObjectGuid _lavaSteamGUID;
ObjectGuid _lavaSplashGUID;
ObjectGuid _majordomoExecutusGUID;
ObjectGuid _cacheOfTheFirelordGUID;
ObjectGuid _garrGUID;
ObjectGuid _magmadarGUID;
}; };
void AddSC_instance_molten_core() void AddSC_instance_molten_core()
{ {
new instance_molten_core(); RegisterInstanceScript(instance_molten_core, MAP_MOLTEN_CORE);
} }

View File

@@ -46,75 +46,60 @@ enum Spells
}; };
// Serrated Bites timer may be wrong // Serrated Bites timer may be wrong
class npc_mc_core_hound : public CreatureScript struct npc_mc_core_hound : public CreatureAI
{ {
public: npc_mc_core_hound(Creature* creature) :
npc_mc_core_hound() : CreatureScript("npc_mc_core_hound") {} CreatureAI(creature),
instance(creature->GetInstanceScript()),
struct npc_mc_core_houndAI : public CreatureAI serratedBiteTimer(3000)
{ {
npc_mc_core_houndAI(Creature* creature) :
CreatureAI(creature),
instance(creature->GetInstanceScript()),
serratedBiteTimer(3000)
{
}
void Reset() override
{
serratedBiteTimer = 3000;
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Prevent receiving any extra damage if Hound is playing dead
if (me->HasAura(SPELL_PLAY_DEAD))
{
damage = 0;
return;
}
else if (me->GetHealth() <= damage)
{
damage = 0;
Talk(EMOTE_SMOLDERING);
DoCastSelf(SPELL_PLAY_DEAD);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_PLAY_DEAD))
{
return;
}
if (serratedBiteTimer <= diff)
{
DoCastVictim(SPELL_SERRATED_BITE);
serratedBiteTimer = urand(5000, 6000);
}
else
{
serratedBiteTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 serratedBiteTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_mc_core_houndAI>(creature);
} }
void Reset() override
{
serratedBiteTimer = 3000;
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Prevent receiving any extra damage if Hound is playing dead
if (me->HasAura(SPELL_PLAY_DEAD))
{
damage = 0;
return;
}
else if (me->GetHealth() <= damage)
{
damage = 0;
Talk(EMOTE_SMOLDERING);
DoCastSelf(SPELL_PLAY_DEAD);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_PLAY_DEAD))
return;
if (serratedBiteTimer <= diff)
{
DoCastVictim(SPELL_SERRATED_BITE);
serratedBiteTimer = urand(5000, 6000);
}
else
{
serratedBiteTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 serratedBiteTimer;
}; };
// 19822 Play Dead // 19822 Play Dead
@@ -136,9 +121,7 @@ class spell_mc_play_dead_aura : public AuraScript
{ {
Creature* creatureTarget = GetTarget()->ToCreature(); Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget) if (!creatureTarget)
{
return; return;
}
creatureTarget->CastSpell(creatureTarget, SPELL_PLAY_DEAD_PACIFY, true); creatureTarget->CastSpell(creatureTarget, SPELL_PLAY_DEAD_PACIFY, true);
creatureTarget->SetDynamicFlag(UNIT_DYNFLAG_DEAD); creatureTarget->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
@@ -154,9 +137,7 @@ class spell_mc_play_dead_aura : public AuraScript
{ {
Creature* creatureTarget = GetTarget()->ToCreature(); Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget) if (!creatureTarget)
{
return; return;
}
creatureTarget->RemoveAurasDueToSpell(SPELL_PLAY_DEAD_PACIFY); creatureTarget->RemoveAurasDueToSpell(SPELL_PLAY_DEAD_PACIFY);
creatureTarget->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD); creatureTarget->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD);
@@ -166,9 +147,7 @@ class spell_mc_play_dead_aura : public AuraScript
creatureTarget->SetReactState(REACT_AGGRESSIVE); creatureTarget->SetReactState(REACT_AGGRESSIVE);
if (!creatureTarget->IsInCombat()) if (!creatureTarget->IsInCombat())
{
return; return;
}
bool shouldDie = true; bool shouldDie = true;
std::list<Creature*> hounds; std::list<Creature*> hounds;
@@ -246,9 +225,7 @@ struct npc_lava_spawn : public ScriptedAI
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
_scheduler.Update(diff); _scheduler.Update(diff);
@@ -262,7 +239,7 @@ private:
void AddSC_molten_core() void AddSC_molten_core()
{ {
// Creatures // Creatures
new npc_mc_core_hound(); RegisterMoltenCoreCreatureAI(npc_mc_core_hound);
RegisterCreatureAI(npc_lava_spawn); RegisterCreatureAI(npc_lava_spawn);
// Spells // Spells

View File

@@ -127,4 +127,7 @@ inline AI* GetMoltenCoreAI(T* obj)
return GetInstanceAI<AI>(obj, MCScriptName); return GetInstanceAI<AI>(obj, MCScriptName);
} }
#define RegisterMoltenCoreCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMoltenCoreAI)
#define RegisterMoltenCoreGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetMoltenCoreAI)
#endif #endif