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
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 6659 additions and 7938 deletions

View file

@ -18,6 +18,7 @@
#include "blackrock_depths.h"
#include "AreaTriggerScript.h"
#include "CreatureScript.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h"
#include "GameTime.h"
#include "Player.h"
@ -34,93 +35,76 @@ enum IronhandData
constexpr Milliseconds IRONHAND_FLAMES_TIMER = 16s;
constexpr Milliseconds IRONHAND_FLAMES_TIMER_RAND = 3s;
class go_shadowforge_brazier : public GameObjectScript
struct go_shadowforge_brazier : public GameObjectAI
{
public:
go_shadowforge_brazier() : GameObjectScript("go_shadowforge_brazier") {}
go_shadowforge_brazier(GameObject* go) : GameObjectAI(go) {}
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* southBrazier = ObjectAccessor::GetGameObject(*go, instance->GetGuidData(DATA_SF_BRAZIER_S));
GameObject* northBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_N));
GameObject* southBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_S));
if (!northBrazier || !southBrazier)
{
return false;
}
// should only happen on first brazier
if (instance->GetData(TYPE_LYCEUM) == NOT_STARTED)
{
instance->SetData(TYPE_LYCEUM, IN_PROGRESS);
}
// Check if the opposite brazier is lit - if it is, open the gates.
if ((go->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (go->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE))
if ((me->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (me->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE))
{
instance->SetData(TYPE_LYCEUM, DONE);
}
return false;
}
return false;
};
}
};
class ironhand_guardian : public CreatureScript
struct brd_ironhand_guardian : public CreatureAI
{
public:
ironhand_guardian() : CreatureScript("brd_ironhand_guardian") {}
brd_ironhand_guardian(Creature* creature) : CreatureAI(creature) {}
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) {}
bool flames_enabled = false;
events.Update(diff);
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);
events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS);
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;
}
}
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
if (flames_enabled)
{
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_GOUT_OF_FLAMES:
DoCast(SPELL_GOUT_OF_FLAMES);
events.RescheduleEvent(SPELL_GOUT_OF_FLAMES, IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND);
break;
default:
break;
}
}
}
}
EventMap events;
};
private:
bool _flamesEnabled = false;
EventMap events;
};
struct WaveCreature
@ -159,13 +143,10 @@ public:
{
time_t now = GameTime::GetGameTime().count();
if (instance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || instance->GetData(TYPE_RING_OF_LAW) == DONE)
{
return false;
}
if (now - instance->GetData(DATA_TIME_RING_FAIL) < 2 * 60) // in case of wipe, so people can rez.
{
return false;
}
instance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS);
return true;
@ -185,249 +166,232 @@ enum GrimstoneTexts
SAY_TEXT6 = 5
};
class npc_grimstone : public CreatureScript
struct npc_grimstone : public npc_escortAI
{
public:
npc_grimstone() : CreatureScript("npc_grimstone") { }
CreatureAI* GetAI(Creature* creature) const override
npc_grimstone(Creature* creature) : npc_escortAI(creature), summons(me)
{
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;
theldrenEvent = false;
summons.DespawnAll();
eventTimer = 5000;
}
}
InstanceScript* instance;
SummonList summons;
uint8 eventPhase;
uint32 eventTimer;
uint32 resetTimer;
uint8 MobSpawnId;
uint8 BossSpawnId;
bool theldrenEvent;
void Reset() override
void WaypointReached(uint32 waypointId) override
{
switch (waypointId)
{
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())
{
resetTimer = 0;
case 0:
Talk(SAY_TEXT1);
SetEscortPaused(true);
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:
Talk(SAY_TEXT1);
SetEscortPaused(true);
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)
if (Creature* creature = ObjectAccessor::GetCreature(*me, sum))
{
if (creature->IsAlive() && creature->GetVictim())
{
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me);
instance->SetData(TYPE_RING_OF_LAW, DONE);
resetTimer = 30000;
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);
}
void SummonBoss()
{
if (me->FindNearestGameObject(GO_BANNER_OF_PROVOCATION, 100.0f))
if (eventTimer <= diff)
{
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);
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
me->SummonCreature(RingBoss[BossSpawnId], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0);
resetTimer = 30000;
eventTimer -= diff;
}
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
@ -438,67 +402,53 @@ enum PhalanxSpells
SPELL_MIGHTYBLOW = 14099
};
class npc_phalanx : public CreatureScript
struct npc_phalanx : public ScriptedAI
{
public:
npc_phalanx() : CreatureScript("npc_phalanx") { }
npc_phalanx(Creature* creature) : ScriptedAI(creature) { }
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;
uint32 FireballVolley_Timer;
uint32 MightyBlow_Timer;
void Reset() override
if (_thunderClapTimer <= diff)
{
ThunderClap_Timer = 12000;
FireballVolley_Timer = 0;
MightyBlow_Timer = 15000;
DoCastVictim(SPELL_THUNDERCLAP);
_thunderClapTimer = 10000;
}
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
if (!UpdateVictim())
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();
DoCastVictim(SPELL_MIGHTYBLOW);
_mightyBlowTimer = 10000;
}
};
else _mightyBlowTimer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 _thunderClapTimer;
uint32 _fireballVolleyTimer;
uint32 _mightyBlowTimer;
};
// npc_lokhtos_darkbargainer
@ -518,12 +468,11 @@ enum LokhtosSpells
SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059
};
class npc_lokhtos_darkbargainer : public CreatureScript
struct npc_lokhtos_darkbargainer : public ScriptedAI
{
public:
npc_lokhtos_darkbargainer() : CreatureScript("npc_lokhtos_darkbargainer") { }
npc_lokhtos_darkbargainer(Creature* creature) : ScriptedAI(creature) { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
@ -532,32 +481,26 @@ public:
player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false);
}
if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(creature->GetGUID());
return true;
player->GetSession()->SendListInventory(me->GetGUID());
}
bool OnGossipHello(Player* player, Creature* creature) override
void sGossipHello(Player* player) override
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
if (me->IsQuestGiver())
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);
if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 &&
!player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) &&
player->HasItemCount(ITEM_SULFURON_INGOT))
{
AddGossipItemFor(player, 4781, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
if (player->GetReputationRank(59) < REP_FRIENDLY)
SendGossipMenuFor(player, 3673, creature->GetGUID());
SendGossipMenuFor(player, 3673, me->GetGUID());
else
SendGossipMenuFor(player, 3677, creature->GetGUID());
return true;
SendGossipMenuFor(player, 3677, me->GetGUID());
}
};
@ -577,19 +520,29 @@ enum RocknotQuests
QUEST_ALE = 4295
};
class npc_rocknot : public CreatureScript
struct npc_rocknot : public npc_escortAI
{
public:
npc_rocknot() : CreatureScript("npc_rocknot") { }
bool OnQuestReward(Player* /*player*/, Creature* creature, Quest const* quest, uint32 /*item*/) override
npc_rocknot(Creature* creature) : npc_escortAI(creature)
{
instance = creature->GetInstanceScript();
}
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)
return true;
return;
if (instance->GetData(TYPE_BAR) == DONE || instance->GetData(TYPE_BAR) == SPECIAL)
return true;
return;
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
if (instance->GetData(TYPE_BAR) == SPECIAL)
{
creature->AI()->Talk(SAY_GOT_BEER);
creature->CastSpell(creature, SPELL_DRUNKEN_RAGE, false);
if (npc_escortAI* escortAI = CAST_AI(npc_rocknot::npc_rocknotAI, creature->AI()))
{
creature->SetWalk(true);
escortAI->Start(false);
}
Talk(SAY_GOT_BEER);
me->CastSpell(me, SPELL_DRUNKEN_RAGE, false);
me->SetWalk(true);
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;
uint32 BreakKeg_Timer;
uint32 BreakDoor_Timer;
void Reset() override
void UpdateAI(uint32 diff) override
{
if (_breakKegTimer)
{
if (HasEscortState(STATE_ESCORT_ESCORTING))
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)
if (_breakKegTimer <= diff)
{
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);
BreakKeg_Timer = 2000;
break;
DoGo(DATA_GO_BAR_KEG, 0);
_breakKegTimer = 0;
_breakDoorTimer = 1000;
}
else _breakKegTimer -= diff;
}
void UpdateAI(uint32 diff) override
if (_breakDoorTimer)
{
if (BreakKeg_Timer)
if (_breakDoorTimer <= diff)
{
if (BreakKeg_Timer <= diff)
{
DoGo(DATA_GO_BAR_KEG, 0);
BreakKeg_Timer = 0;
BreakDoor_Timer = 1000;
}
else 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
//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);
_breakDoorTimer = 0;
}
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);
else _breakDoorTimer -= diff;
}
};
npc_escortAI::UpdateAI(diff);
}
private:
InstanceScript* instance;
uint32 _breakKegTimer;
uint32 _breakDoorTimer;
};
void AddSC_blackrock_depths()
{
new go_shadowforge_brazier();
RegisterBlackrockDepthsGameObjectAI(go_shadowforge_brazier);
new at_ring_of_law();
new npc_grimstone();
new npc_phalanx();
new npc_lokhtos_darkbargainer();
new npc_rocknot();
new ironhand_guardian();
RegisterBlackrockDepthsCreatureAI(npc_grimstone);
RegisterBlackrockDepthsCreatureAI(npc_phalanx);
RegisterBlackrockDepthsCreatureAI(npc_lokhtos_darkbargainer);
RegisterBlackrockDepthsCreatureAI(npc_rocknot);
RegisterBlackrockDepthsCreatureAI(brd_ironhand_guardian);
}

View file

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

View file

@ -50,219 +50,184 @@ const Position SummonPositions[7] =
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() : CreatureScript("boss_ambassador_flamelash") { }
boss_ambassador_flamelash(Creature* creature) : BossAI(creature, 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
SummonList summons;
for (int RuneEntry : gobjectDwarfRunesEntry)
if (GameObject* dwarfRune = me->FindNearestGameObject(RuneEntry, 200.0f))
dwarfRune->SetGoState(state);
}
// This will allow to find a valid position to spawn them
std::vector<int> validPosition;
bool foundValidPosition = false;
void JustEngagedWith(Unit* /*who*/) override
{
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:
_events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s);
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
for (int pos : _validPosition)
{
// Check every position inside the vector
for (int pos : validPosition)
// If the random is different, we found a temporary true,
// 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,
// until we find one that is equal, which means it has been used.
if (pos != randomPosition)
foundValidPosition = true;
else
{
foundValidPosition = false;
break;
}
_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
me->SummonCreature(NPC_FIRE_SPIRIT, SummonPositions[getValidRandomPosition()], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60 * IN_MILLISECONDS);
_events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s);
case EVENT_SPELL_FIREBLAST:
DoCastVictim(SPELL_FIREBLAST);
events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s);
break;
case EVENT_SUMMON_SPIRITS:
SummonSpirits();
break;
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
_events.Update(diff);
switch (_events.ExecuteEvent())
{
case EVENT_SPELL_FIREBLAST:
DoCastVictim(SPELL_FIREBLAST);
_events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s);
break;
case EVENT_SUMMON_SPIRITS:
SummonSpirits();
break;
}
DoMeleeAttackIfReady();
}
};
private:
// This will allow to find a valid position to spawn them
std::vector<int> _validPosition;
bool _foundValidPosition = false;
};
class npc_burning_spirit : public CreatureScript
struct npc_burning_spirit : public ScriptedAI
{
public:
npc_burning_spirit() : CreatureScript("npc_burning_spirit") { }
npc_burning_spirit(Creature* creature) : ScriptedAI(creature) {}
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
{
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);
_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:
ObjectGuid _flamelasherGUID;
};
void AddSC_boss_ambassador_flamelash()
{
new boss_ambassador_flamelash();
new npc_burning_spirit();
RegisterBlackrockDepthsCreatureAI(boss_ambassador_flamelash);
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_ENVELOPING_WEB = 16s;
class boss_anubshiah : public CreatureScript
struct boss_anubshiah : public BossAI
{
public:
boss_anubshiah() : CreatureScript("boss_anubshiah") { }
boss_anubshiah(Creature* creature) : BossAI(creature, DATA_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();
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);
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;
}
}
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();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_anubshiah()
{
new boss_anubshiah();
RegisterBlackrockDepthsCreatureAI(boss_anubshiah);
}

View file

@ -34,106 +34,87 @@ enum Spells
#define DATA_PERCENT_DEAD_SENATORS 0
class boss_emperor_dagran_thaurissan : public CreatureScript
struct boss_emperor_dagran_thaurissan : public BossAI
{
public:
boss_emperor_dagran_thaurissan() : CreatureScript("boss_emperor_dagran_thaurissan") { }
uint32 hasYelled = 0;
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;
uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database
Talk(SAY_SLAY);
}
boss_draganthaurissanAI(Creature* creature) : BossAI(creature, DATA_EMPEROR){}
void JustEngagedWith(Unit* /*who*/) override
void SetData(uint32 type, uint32 data) 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);
}
else
{
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++;
}
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();
Moira->AI()->Talk(0);
Moira->SetFaction(FACTION_FRIENDLY);
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;
}
}
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();
}
};
DoMeleeAttackIfReady();
}
};
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_SHIELD = 12s;
class boss_eviscerator : public CreatureScript
struct boss_eviscerator : public BossAI
{
public:
boss_eviscerator() : CreatureScript("boss_eviscerator") {}
boss_eviscerator(Creature* creature) : BossAI(creature, DATA_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) {}
bool SpellShieldReady = false;
void JustEngagedWith(Unit* /*who*/) override
if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady)
{
_JustEngagedWith();
events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY / 5);
events.ScheduleEvent(SPELL_REND, TIMER_REND / 5);
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD / 5);
DoCast(SPELL_SHIELD);
SpellShieldReady = false;
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD);
}
}
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);
SpellShieldReady = false;
events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD);
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;
}
}
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();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_eviscerator()
{
new boss_eviscerator();
RegisterBlackrockDepthsCreatureAI(boss_eviscerator);
}

View file

@ -26,108 +26,94 @@ enum Spells
SPELL_CLEAVE = 20691
};
class boss_general_angerforge : public CreatureScript
struct boss_general_angerforge : public ScriptedAI
{
public:
boss_general_angerforge() : CreatureScript("boss_general_angerforge") { }
boss_general_angerforge(Creature* creature) : ScriptedAI(creature) { }
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;
uint32 HamString_Timer;
uint32 Cleave_Timer;
uint32 Adds_Timer;
bool Medics;
void SummonMedics(Unit* victim)
{
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 Reset() override
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
if (_mightyBlowTimer <= diff)
{
MightyBlow_Timer = 8000;
HamString_Timer = 12000;
Cleave_Timer = 16000;
Adds_Timer = 0;
Medics = false;
DoCastVictim(SPELL_MIGHTYBLOW);
_mightyBlowTimer = 18000;
}
else _mightyBlowTimer -= diff;
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 { }
void SummonAdds(Unit* victim)
//Summon Medics
if (!_medics && HealthBelowPct(21))
{
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);
SummonMedics(me->GetVictim());
SummonMedics(me->GetVictim());
_medics = true;
}
void SummonMedics(Unit* victim)
{
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);
}
DoMeleeAttackIfReady();
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//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();
}
};
private:
uint32 _mightyBlowTimer;
uint32 _hamStringTimer;
uint32 _cleaveTimer;
uint32 _addsTimer;
bool _medics;
};
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_BLOODLUST = 30s;
class boss_gorosh_the_dervish : public CreatureScript
struct boss_gorosh_the_dervish : public BossAI
{
public:
boss_gorosh_the_dervish() : CreatureScript("boss_gorosh_the_dervish") { }
boss_gorosh_the_dervish(Creature* creature) : BossAI(creature, DATA_GOROSH) { }
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();
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())
switch (eventId)
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
case SPELL_WHIRLWIND:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
case SPELL_WHIRLWIND:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
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;
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;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
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_FRENZY = 15s;
class boss_grizzle : public CreatureScript
struct boss_grizzle : public BossAI
{
public:
boss_grizzle() : CreatureScript("boss_grizzle") { }
boss_grizzle(Creature* creature) : BossAI(creature, DATA_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();
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())
switch (eventId)
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
case SPELL_GROUNDTREMOR:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
case SPELL_GROUNDTREMOR:
if (me->GetDistance2d(me->GetVictim()) < 10.0f)
{
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;
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;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
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_WEB_EXPLOSION = 20s;
class boss_hedrum : public CreatureScript
struct boss_hedrum : public BossAI
{
public:
boss_hedrum() : CreatureScript("boss_hedrum") {}
boss_hedrum(Creature* creature) : BossAI(creature, DATA_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();
events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING / 5);
events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL / 5);
events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION / 5);
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;
}
}
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();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_hedrum()
{
new boss_hedrum();
RegisterBlackrockDepthsCreatureAI(boss_hedrum);
}

View file

@ -27,81 +27,67 @@ enum Spells
SPELL_SHADOWSHIELD = 22417
};
class boss_high_interrogator_gerstahn : public CreatureScript
struct boss_high_interrogator_gerstahn : public ScriptedAI
{
public:
boss_high_interrogator_gerstahn() : CreatureScript("boss_high_interrogator_gerstahn") { }
boss_high_interrogator_gerstahn(Creature* creature) : ScriptedAI(creature) { }
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;
uint32 ManaBurn_Timer;
uint32 PsychicScream_Timer;
uint32 ShadowShield_Timer;
void Reset() override
if (_shadowWordPainTimer <= diff)
{
ShadowWordPain_Timer = 4000;
ManaBurn_Timer = 14000;
PsychicScream_Timer = 32000;
ShadowShield_Timer = 8000;
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_SHADOWWORDPAIN);
_shadowWordPainTimer = 7000;
}
else _shadowWordPainTimer -= diff;
void JustEngagedWith(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
if (_manaBurnTimer <= diff)
{
//Return since we have no target
if (!UpdateVictim())
return;
//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();
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_MANABURN);
_manaBurnTimer = 10000;
}
};
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()
{
new boss_high_interrogator_gerstahn();
RegisterBlackrockDepthsCreatureAI(boss_high_interrogator_gerstahn);
}

View file

@ -25,66 +25,54 @@ enum Spells
SPELL_WARSTOMP = 24375
};
class boss_magmus : public CreatureScript
struct boss_magmus : public BossAI
{
public:
boss_magmus() : CreatureScript("boss_magmus") { }
boss_magmus(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {}
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
{
_Reset();
instance->SetData(TYPE_IRON_HALL, NOT_STARTED);
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
void JustEngagedWith(Unit* /*who*/) override
{
instance->SetData(TYPE_IRON_HALL, IN_PROGRESS);
_JustEngagedWith();
events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s);
events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s);
}
events.Update(diff);
void UpdateAI(uint32 diff) override
while (uint32 eventId = events.ExecuteEvent())
{
//Return since we have no target
if (!UpdateVictim())
switch (eventId)
{
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()
{
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_WORDPAIN = 12s;
struct boss_moira_bronzebeardAI : public BossAI
struct boss_moira_bronzebeard : public BossAI
{
// 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
{
_JustEngagedWith();
@ -49,15 +49,13 @@ struct boss_moira_bronzebeardAI : public BossAI
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)
@ -83,22 +81,18 @@ struct boss_moira_bronzebeardAI : public BossAI
{
Creature* emperor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EMPEROR));
if (emperor && emperor->HealthBelowPct(90))
{
DoCast(emperor, spell);
}
else if (HealthBelowPct(90))
{
DoCastSelf(spell);
}
events.ScheduleEvent(spell, timer - 2s, timer + 2s);
}
};
// high priestess should be fairly identical to Moira.
// Running away when emperor dies is handled through GUID from emperor, therefore not relevant here.
struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI
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
{
@ -110,18 +104,16 @@ struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI
events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 2);
}
void UpdateAI(uint32 diff) override
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)
@ -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()
{
new boss_moira_bronzebeard();
RegisterBlackrockDepthsCreatureAI(boss_moira_bronzebeard);
}
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_SLOW = 15s;
class boss_okthor : public CreatureScript
struct boss_okthor : public BossAI
{
public:
boss_okthor() : CreatureScript("boss_okthor") {}
boss_okthor(Creature* creature) : BossAI(creature, DATA_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();
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())
switch (eventId)
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
case SPELL_ARCANE_BOLT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
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)
{
case SPELL_ARCANE_BOLT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
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;
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;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
private:
Milliseconds _nextArcaneExplosionTime;
};
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...
};
class boss_gloomrel : public CreatureScript
struct boss_gloomrel : public ScriptedAI
{
public:
boss_gloomrel() : CreatureScript("boss_gloomrel") { }
boss_gloomrel(Creature* creature) : ScriptedAI(creature) { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_INFO_DEF+1:
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;
case GOSSIP_ACTION_INFO_DEF+11:
CloseGossipMenuFor(player);
@ -73,33 +72,29 @@ public:
break;
case GOSSIP_ACTION_INFO_DEF+2:
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;
case GOSSIP_ACTION_INFO_DEF+22:
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
instance->DoRespawnGameObject(instance->GetGuidData(DATA_GO_CHALICE), MINUTE * 5);
}
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))
{
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)
AddGossipItemFor(player, GOSSIP_GROOMREL, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID());
}
};
@ -120,145 +115,124 @@ enum DoomrelEvents
EVENT_SPELL_SUMMON_VOIDWALKERS = 5,
};
class boss_doomrel : public CreatureScript
struct boss_doomrel : public ScriptedAI
{
public:
boss_doomrel() : CreatureScript("boss_doomrel") { }
boss_doomrel(Creature* creature) : ScriptedAI(creature)
{
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);
switch (action)
{
case GOSSIP_ACTION_INFO_DEF+1:
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;
case GOSSIP_ACTION_INFO_DEF+2:
CloseGossipMenuFor(player);
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
// Start encounter
InstanceScript* instance = creature->GetInstanceScript();
if (instance)
{
instance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS);
}
creature->AI()->Talk(SAY_START_FIGHT);
Talk(SAY_START_FIGHT);
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);
SendGossipMenuFor(player, SAY_DOOMREL_HELLO, creature->GetGUID());
return true;
SendGossipMenuFor(player, SAY_DOOMREL_HELLO, me->GetGUID());
}
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;
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();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_tomb_of_seven()
{
new boss_gloomrel();
new boss_doomrel();
RegisterBlackrockDepthsCreatureAI(boss_gloomrel);
RegisterBlackrockDepthsCreatureAI(boss_doomrel);
}

View file

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

View file

@ -40,98 +40,85 @@ enum Events
EVENT_CHECK_CONFLAGRATION_TARGET
};
class boss_drakkisath : public CreatureScript
struct boss_drakkisath : public BossAI
{
public:
boss_drakkisath() : CreatureScript("boss_drakkisath") { }
struct boss_drakkisathAI : public BossAI
boss_drakkisath(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH)
{
boss_drakkisathAI(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH)
{
_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);
_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;
};
void AddSC_boss_drakkisath()
{
new boss_drakkisath();
RegisterBlackrockSpireCreatureAI(boss_drakkisath);
}

View file

@ -51,125 +51,114 @@ enum Events
EVENT_SUMMONED_2 = 6
};
class boss_gyth : public CreatureScript
struct boss_gyth : public BossAI
{
public:
boss_gyth() : CreatureScript("boss_gyth") { }
boss_gyth(Creature* creature) : BossAI(creature, DATA_GYTH) { }
struct boss_gythAI : public BossAI
void Reset() override
{
boss_gythAI(Creature* creature) : BossAI(creature, DATA_GYTH) { }
void Reset() override
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
{
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
{
instance->SetBossState(DATA_GYTH, NOT_STARTED);
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);
});
instance->SetBossState(DATA_GYTH, NOT_STARTED);
summons.DespawnAll();
me->DespawnOrUnsummon();
}
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);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CORROSIVE_ACID:
DoCast(me, SPELL_CORROSIVE_ACID);
events.ScheduleEvent(EVENT_CORROSIVE_ACID, 10s, 16s);
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_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);
case EVENT_SUMMONED_2:
me->GetMotionMaster()->MoveWaypoint(GYTH_PATH_1, false);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
return;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_gythAI>(creature);
events.Update(diff);
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()
{
new boss_gyth();
RegisterBlackrockSpireCreatureAI(boss_gyth);
RegisterSpellScript(spell_gyth_chromatic_protection);
}

View file

@ -38,70 +38,59 @@ enum Events
const Position SummonLocation = { -167.9561f, -411.7844f, 76.23057f, 1.53589f };
class boss_halycon : public CreatureScript
struct boss_halycon : public BossAI
{
public:
boss_halycon() : CreatureScript("boss_halycon") { }
boss_halycon(Creature* creature) : BossAI(creature, DATA_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();
}
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)
{
switch (eventId)
{
case EVENT_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(EVENT_REND, 8s, 10s);
break;
case EVENT_THRASH:
DoCast(me, SPELL_THRASH);
break;
default:
break;
}
case EVENT_REND:
DoCastVictim(SPELL_REND);
events.ScheduleEvent(EVENT_REND, 8s, 10s);
break;
case EVENT_THRASH:
DoCast(me, SPELL_THRASH);
break;
default:
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_halyconAI>(creature);
DoMeleeAttackIfReady();
}
};
void AddSC_boss_halycon()
{
new boss_halycon();
RegisterBlackrockSpireCreatureAI(boss_halycon);
}

View file

@ -31,69 +31,58 @@ enum Events
EVENT_KNOCK_AWAY = 2
};
class boss_highlord_omokk : public CreatureScript
struct boss_highlord_omokk : public BossAI
{
public:
boss_highlord_omokk() : CreatureScript("boss_highlord_omokk") { }
boss_highlord_omokk(Creature* creature) : BossAI(creature, DATA_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();
}
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)
{
switch (eventId)
{
case EVENT_FRENZY:
DoCastVictim(SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 60s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCK_AWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s);
break;
default:
break;
}
case EVENT_FRENZY:
DoCastVictim(SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 60s);
break;
case EVENT_KNOCK_AWAY:
DoCastVictim(SPELL_KNOCK_AWAY);
events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s);
break;
default:
break;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_highlordomokk()
{
new boss_highlord_omokk();
RegisterBlackrockSpireCreatureAI(boss_highlord_omokk);
}

View file

@ -49,145 +49,130 @@ enum EventPhase
EVENT_PHASE_FIGHT = 2
};
class boss_lord_valthalak : public CreatureScript
struct boss_lord_valthalak : public BossAI
{
public:
boss_lord_valthalak() : CreatureScript("boss_lord_valthalak") { }
boss_lord_valthalak(Creature* creature) : BossAI(creature, DATA_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
{
BossAI::Reset();
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
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);
_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;
};
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:
spell = Acore::Containers::SelectRandomContainerElement(humanSpells);
if (spell == SPELL_REJUVENATION || spell == SPELL_HEALING_TOUCH)
{
DoCastSelf(spell);
}
else
{
DoCastAOE(spell);
}
break;
case PHASE_BEAR:
spell = Acore::Containers::SelectRandomContainerElement(bearSpells);
@ -155,9 +151,7 @@ struct boss_mor_grayhoof : public BossAI
{
CastRandomSpell(PHASE_BEAR);
if (context.GetRepeatCounter() <= 3)
{
context.Repeat();
}
});
}
else if (_phase == PHASE_BEAR && me->HealthBelowPct(50.f))
@ -170,9 +164,7 @@ struct boss_mor_grayhoof : public BossAI
{
CastRandomSpell(PHASE_CAT);
if (context.GetRepeatCounter() <= 3)
{
context.Repeat();
}
});
}
else if (_phase == PHASE_CAT && me->HealthBelowPct(25.f))
@ -203,9 +195,7 @@ struct boss_mor_grayhoof : public BossAI
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
_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 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() : CreatureScript("boss_overlord_wyrmthalak") { }
boss_overlord_wyrmthalak(Creature* creature) : BossAI(creature, DATA_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();
Summoned = false;
}
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 (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
Talk(CALL_HELP);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
warlord->AI()->AttackStart(target);
if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
berserker->AI()->AttackStart(target);
Summoned = true;
}
if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS))
warlord->AI()->AttackStart(target);
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()
{
new boss_overlord_wyrmthalak();
RegisterBlackrockSpireCreatureAI(boss_overlord_wyrmthalak);
}

View file

@ -68,241 +68,226 @@ enum Events
EVENT_ENTER_COMBAT = 10
};
class boss_pyroguard_emberseer : public CreatureScript
struct boss_pyroguard_emberseer : public BossAI
{
public:
boss_pyroguard_emberseer() : CreatureScript("boss_pyroguard_emberseer") { }
boss_pyroguard_emberseer(Creature* creature) : BossAI(creature, DATA_PYROGAURD_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);
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);
// Open doors on reset
if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS)
OpenDoors(false); // Opens 2 entrance doors
case 1:
events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
break;
case 2:
// Close these two doors on Blackhand Incarcerators aggro
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 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.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s);
instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS);
break;
case 2:
// Close these two doors on Blackhand Incarcerators aggro
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;
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 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);
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_FIRENOVA:
DoCast(me, SPELL_FIRENOVA);
events.ScheduleEvent(EVENT_FIRENOVA, 6s);
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_FLAMEBUFFET:
DoCast(me, SPELL_FLAMEBUFFET);
events.ScheduleEvent(EVENT_FLAMEBUFFET, 14s);
case EVENT_PRE_ENTER_COMBAT_2:
Talk(YELL_FREE_OF_BONDS);
break;
case EVENT_PYROBLAST:
DoCastRandomTarget(SPELL_PYROBLAST, 0, 100.0f);
events.ScheduleEvent(EVENT_PYROBLAST, 15s);
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;
}
}
DoMeleeAttackIfReady();
return;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_pyroguard_emberseerAI>(creature);
events.Update(diff);
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
};
class npc_blackhand_incarcerator : public CreatureScript
struct npc_blackhand_incarcerator : public ScriptedAI
{
public:
npc_blackhand_incarcerator() : CreatureScript("npc_blackhand_incarcerator") { }
struct npc_blackhand_incarceratorAI : public ScriptedAI
npc_blackhand_incarcerator(Creature* creature) : ScriptedAI(creature)
{
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);
while (uint32 eventId = _events.ExecuteEvent())
{
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;
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;
}
}
}
DoMeleeAttackIfReady();
return;
}
private:
EventMap _events;
bool _fleedForAssistance;
};
_events.Update(diff);
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<npc_blackhand_incarceratorAI>(creature);
while (uint32 eventId = _events.ExecuteEvent())
{
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()
{
new boss_pyroguard_emberseer();
new npc_blackhand_incarcerator();
RegisterBlackrockSpireCreatureAI(boss_pyroguard_emberseer);
RegisterBlackrockSpireCreatureAI(npc_blackhand_incarcerator);
}

View file

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

View file

@ -99,346 +99,327 @@ enum Events
EVENT_MORTAL_STRIKE = 32,
};
class boss_rend_blackhand : public CreatureScript
struct boss_rend_blackhand : public BossAI
{
public:
boss_rend_blackhand() : CreatureScript("boss_rend_blackhand") { }
boss_rend_blackhand(Creature* creature) : BossAI(creature, DATA_WARCHIEF_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();
if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS)
{
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);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION);
me->SetImmuneToAll(false);
return;
}
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();
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);
}
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())
if (!_gythEvent)
{
instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL);
}
_gythEvent = true;
BossAI::SummonedCreatureDespawn(creature);
}
void SetData(uint32 type, uint32 data) override
{
if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM)
{
if (!gythEvent)
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f))
{
gythEvent = true;
if (!victor->IsAlive())
victor->Respawn(true);
if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f))
{
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);
_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);
}
}
}
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);
break;
}
case 6:
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);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_WHIRLWIND:
DoCast(SPELL_WHIRLWIND);
events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 18s);
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_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
events.ScheduleEvent(EVENT_CLEAVE, 10s, 14s);
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_MORTAL_STRIKE:
DoCastVictim(SPELL_MORTAL_STRIKE);
events.ScheduleEvent(EVENT_MORTAL_STRIKE, 14s, 18s);
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;
}
}
DoMeleeAttackIfReady();
}
void SummonWave()
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
me->SummonCreatureGroup(_currentWave);
if (GameObject* waveDoor = me->GetMap()->GetGameObject(waveDoorGUID))
switch (eventId)
{
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;
}
private:
bool gythEvent;
uint8 _currentWave;
ObjectGuid victorGUID;
ObjectGuid waveDoorGUID;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackrockSpireAI<boss_rend_blackhandAI>(creature);
DoMeleeAttackIfReady();
}
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()
{
new boss_rend_blackhand();
RegisterBlackrockSpireCreatureAI(boss_rend_blackhand);
}

View file

@ -38,211 +38,178 @@ enum Says
SAY_SUMMON = 0,
};
class npc_rookery_hatcher : public CreatureScript
struct npc_rookery_hatcher : public CreatureAI
{
public:
npc_rookery_hatcher() : CreatureScript("npc_rookery_hatcher") {}
npc_rookery_hatcher(Creature* creature) : CreatureAI(creature) {}
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;
GameObject* targetEgg;
Position targetPosition;
float tempDist = 20;
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();
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())
if (!whelp->IsInCombat())
{
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
{
BossAI::InitializeAI();
Talk(SAY_SUMMON);
DoZoneInCombat(nullptr, 100.0f);
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
events.Update(diff);
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
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case SPELL_WAR_STOMP:
DoCastVictim(SPELL_WAR_STOMP);
events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s);
break;
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;
}
}
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())
{
resetTimer -= diff;
if (resetTimer < diff)
{
instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL);
}
return;
}
resetTimer = 10000;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
ExecuteEvent(eventId);
}
DoMeleeAttackIfReady();
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);
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()
{
new boss_solakar_flamewreath();
new npc_rookery_hatcher();
RegisterBlackrockSpireCreatureAI(boss_solakar_flamewreath);
RegisterBlackrockSpireCreatureAI(npc_rookery_hatcher);
}

View file

@ -90,185 +90,152 @@ private:
// Used to make Hodir disengage whenever he leaves his room
constexpr static float FirewalPositionY = -505.f;
class boss_the_beast : public CreatureScript
struct boss_the_beast : public BossAI
{
public:
boss_the_beast() : CreatureScript("boss_the_beast") { }
boss_the_beast(Creature* creature) : BossAI(creature, DATA_THE_BEAST), _beastReached(false), _orcYelled(false) {}
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();
if (_beastReached)
case DATA_BEAST_ROOM:
{
me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true);
}
}
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 (!_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();
}
//! 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)
{
if (!yelled)
{
yelled = true;
orc->AI()->Talk(SAY_BLACKHAND_DOOMED);
}
orc->m_Events.AddEventAtOffset(new OrcMoveEvent(orc), 3s);
orc->m_Events.AddEventAtOffset(new OrcDeathEvent(orc), 9s);
yelled = true;
orc->AI()->Talk(SAY_BLACKHAND_DOOMED);
}
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)
// 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)
SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM);
}
break;
// There is a chance player logged in between areatriggers (realm crash or restart)
// 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)
SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM);
}
break;
}
}
}
void UpdateAI(uint32 diff) override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (me->GetPositionY() > FirewalPositionY)
{
if (!UpdateVictim())
{
return;
}
EnterEvadeMode();
return;
}
if (me->GetPositionY() > FirewalPositionY)
{
EnterEvadeMode();
return;
}
events.Update(diff);
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))
{
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()
{
std::list<Creature*> temp;
me->GetCreatureListWithEntryInGrid(temp, NPC_BLACKHAND_ELITE, 50.0f);
for (Creature* creature : temp)
{
if (creature->IsAlive())
{
_nearbyOrcsGUIDs.push_back(creature->GetGUID());
}
}
}
DoMeleeAttackIfReady();
}
private:
bool _beastReached;
bool _orcYelled;
GuidVector _nearbyOrcsGUIDs;
};
void FindNearbyOrcs()
{
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:
bool _beastReached;
bool _orcYelled;
GuidVector _nearbyOrcsGUIDs;
};
//! 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
{
if (player->IsGameMaster())
{
return false;
}
if (InstanceScript* instance = player->GetInstanceScript())
{
if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST)))
{
beast->AI()->SetData(DATA_BEAST_REACHED, DATA_BEAST_REACHED);
}
return true;
}
@ -306,16 +269,12 @@ public:
bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{
if (player->IsGameMaster())
{
return false;
}
if (InstanceScript* instance = player->GetInstanceScript())
{
if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST)))
{
beast->AI()->SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM);
}
return true;
}
@ -326,7 +285,7 @@ public:
void AddSC_boss_thebeast()
{
new boss_the_beast();
RegisterBlackrockSpireCreatureAI(boss_the_beast);
new at_trigger_the_beast_movement();
new at_the_beast_room();
}

View file

@ -40,82 +40,67 @@ enum Events
EVENT_INTIMIDATING_ROAR = 3
};
class boss_urok_doomhowl : public CreatureScript
struct boss_urok_doomhowl : public BossAI
{
public:
boss_urok_doomhowl() : CreatureScript("boss_urok_doomhowl") { }
boss_urok_doomhowl(Creature* creature) : BossAI(creature, DATA_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
{
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)))
challenge->Delete();
if (GameObject* challenge = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_CHALLENGE)))
{
challenge->Delete();
}
if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE)))
pile->DespawnOrUnsummon(0ms, Seconds(MONTH));
}
if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE)))
{
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
void JustEngagedWith(Unit* /*who*/) 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()
{
new boss_urok_doomhowl();
RegisterBlackrockSpireCreatureAI(boss_urok_doomhowl);
}

View file

@ -55,86 +55,75 @@ enum EventGroups
GROUP_WARMASTER
};
class boss_warmaster_voone : public CreatureScript
struct boss_warmaster_voone : public BossAI
{
public:
boss_warmaster_voone() : CreatureScript("boss_warmaster_voone") { }
boss_warmaster_voone(Creature* creature) : BossAI(creature, DATA_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
{
_JustEngagedWith();
events.SetPhase(PHASE_BRAWLER);
events.ScheduleEvent(EVENT_THRASH, 3s, GROUP_BRAWLER, PHASE_BRAWLER);
events.ScheduleEvent(EVENT_THROW_AXE, 1s, GROUP_BRAWLER, PHASE_BRAWLER);
}
events.SetPhase(PHASE_BRAWLER);
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
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) 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()
{
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 RegisterBlackwingLairGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackwingLairAI)
#endif

View file

@ -58,196 +58,157 @@ enum Actions
ACTION_DISARMED = 1
};
class boss_broodlord : public CreatureScript
struct boss_broodlord : public BossAI
{
public:
boss_broodlord() : CreatureScript("boss_broodlord") { }
boss_broodlord(Creature* creature) : BossAI(creature, DATA_BROODLORD_LASHLAYER) { }
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
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
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);
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);
}
};
class go_suppression_device : public GameObjectScript
{
public:
go_suppression_device() : GameObjectScript("go_suppression_device") { }
void JustDied(Unit* /*killer*/) override
{
_JustDied();
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
go->SetLootState(GO_READY);
[[fallthrough]];
case GO_ACTIVATED:
go->AI()->DoAction(ACTION_DISARMED);
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;
}
}
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) { }
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);
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;
};
class spell_suppression_aura : public SpellScript
@ -271,7 +232,7 @@ class spell_suppression_aura : public SpellScript
void AddSC_boss_broodlord()
{
new boss_broodlord();
new go_suppression_device();
RegisterBlackwingLairCreatureAI(boss_broodlord);
RegisterBlackwingLairGameObjectAI(go_suppression_device);
RegisterSpellScript(spell_suppression_aura);
}

View file

@ -70,203 +70,171 @@ enum Misc
Position const homePos = { -7491.1587f, -1069.718f, 476.59094, 476.59094f };
class boss_chromaggus : public CreatureScript
struct boss_chromaggus : public BossAI
{
public:
boss_chromaggus() : CreatureScript("boss_chromaggus") { }
struct boss_chromaggusAI : public BossAI
boss_chromaggus(Creature* creature) : BossAI(creature, DATA_CHROMAGGUS)
{
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();
// 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);
_playerGUID = guid;
// 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;
}
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)
switch (eventId)
{
_playerGUID = guid;
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
me->SetImmuneToAll(false);
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;
}
}
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())
{
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:
std::list<uint32> _breathSpells;
bool Enraged;
ObjectGuid _playerGUID;
};
// Enrage if not already enraged and below 20%
if (!Enraged && HealthBelowPct(20))
{
DoCast(me, SPELL_ENRAGE);
Enraged = true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_chromaggusAI>(creature);
DoMeleeAttackIfReady();
}
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() : GameObjectScript("go_chromaggus_lever") { }
go_chromaggus_lever(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { }
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()) { }
bool GossipHello(Player* player, bool reportUse) override
if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS)
{
if (reportUse)
if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS))
{
if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS)
{
if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS))
{
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);
creature->SetHomePosition(homePos);
creature->GetMotionMaster()->MoveWaypoint(creature->GetEntry() * 10, false);
creature->AI()->SetGUID(player->GetGUID(), GUID_LEVER_USER);
}
return true;
if (GameObject* go = _instance->GetGameObject(DATA_GO_CHROMAGGUS_DOOR))
_instance->HandleGameObject(ObjectGuid::Empty, true, go);
}
private:
InstanceScript* _instance;
};
GameObjectAI* GetAI(GameObject* go) const override
{
return GetBlackwingLairAI<go_chromaggus_leverAI>(go);
me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_IN_USE);
me->SetGoState(GO_STATE_ACTIVE);
}
return true;
}
private:
InstanceScript* _instance;
};
enum ElementalShieldSpells
@ -306,9 +274,7 @@ class spell_gen_elemental_shield : public SpellScript
if (Unit* caster = GetCaster())
{
for (uint32 spell = SPELL_FIRE_ELEMENTAL_SHIELD; spell <= SPELL_ARCANE_ELEMENTAL_SHIELD; ++spell)
{
caster->RemoveAurasDueToSpell(spell);
}
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())
{
for (uint32 spell = SPELL_RED_BROOD_POWER; spell <= SPELL_GREEN_BROOD_POWER; ++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);
}
@ -357,8 +321,8 @@ class spell_gen_brood_power : public SpellScript
void AddSC_boss_chromaggus()
{
new boss_chromaggus();
new go_chromaggus_lever();
RegisterBlackwingLairCreatureAI(boss_chromaggus);
RegisterBlackwingLairGameObjectAI(go_chromaggus_lever);
RegisterSpellScript(spell_gen_elemental_shield);
RegisterSpellScript(spell_gen_brood_power);
}

View file

@ -33,82 +33,69 @@ enum Events
EVENT_SHADOWOFEBONROC = 3
};
class boss_ebonroc : public CreatureScript
struct boss_ebonroc : public BossAI
{
public:
boss_ebonroc() : CreatureScript("boss_ebonroc") { }
boss_ebonroc(Creature* creature) : BossAI(creature, DATA_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))
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
{
return GetBlackwingLairAI<boss_ebonrocAI>(creature);
DoMeleeAttackIfReady();
}
};
void AddSC_boss_ebonroc()
{
new boss_ebonroc();
RegisterBlackwingLairCreatureAI(boss_ebonroc);
}

View file

@ -33,69 +33,58 @@ enum Events
EVENT_FLAMEBUFFET = 3
};
class boss_firemaw : public CreatureScript
struct boss_firemaw : public BossAI
{
public:
boss_firemaw() : CreatureScript("boss_firemaw") { }
boss_firemaw(Creature* creature) : BossAI(creature, DATA_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);
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);
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;
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
{
return GetBlackwingLairAI<boss_firemawAI>(creature);
DoMeleeAttackIfReady();
}
};
void AddSC_boss_firemaw()
{
new boss_firemaw();
RegisterBlackwingLairCreatureAI(boss_firemaw);
}

View file

@ -38,70 +38,59 @@ enum Events
EVENT_FRENZY = 3
};
class boss_flamegor : public CreatureScript
struct boss_flamegor : public BossAI
{
public:
boss_flamegor() : CreatureScript("boss_flamegor") { }
boss_flamegor(Creature* creature) : BossAI(creature, DATA_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);
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);
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;
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
{
return GetBlackwingLairAI<boss_flamegorAI>(creature);
DoMeleeAttackIfReady();
}
};
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
{
if (!_me || !target || !target->IsPlayer())
{
return false;
}
if (target->getClass() != _targetClass)
{
return false;
}
return true;
}
@ -231,304 +227,291 @@ private:
uint8 _targetClass;
};
class boss_victor_nefarius : public CreatureScript
struct boss_victor_nefarius : public BossAI
{
public:
boss_victor_nefarius() : CreatureScript("boss_victor_nefarius") { }
struct boss_victor_nefariusAI : public BossAI
boss_victor_nefarius(Creature* creature) : BossAI(creature, DATA_NEFARIAN)
{
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 = instance->GetData(DATA_NEFARIAN_RIGHT_TUNNEL);
_nefarianRightTunnel = nefarianDrakonidSpawners[0];
_nefarianLeftTunnel = nefarianDrakonidSpawners[1];
if (!_nefarianLeftTunnel || !_nefarianRightTunnel)
{
// 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);
_nefarianRightTunnel = nefarianDrakonidSpawners[0];
_nefarianLeftTunnel = nefarianDrakonidSpawners[1];
// save it to instance
instance->SetData(DATA_NEFARIAN_LEFT_TUNNEL, _nefarianLeftTunnel);
instance->SetData(DATA_NEFARIAN_RIGHT_TUNNEL, _nefarianRightTunnel);
}
// 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;
}
void Reset() override
{
Initialize();
if (me->GetMapId() == MAP_BLACKWING_LAIR)
if (Creature* nefarian = me->FindNearestCreature(NPC_NEFARIAN, 1000.0f, true))
{
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.
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();
}
nefarian->DespawnOrUnsummon();
}
else
std::list<GameObject*> drakonidBones;
me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& bones : drakonidBones)
{
_Reset();
}
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);
bones->DespawnOrUnsummon();
}
}
}
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)
else
{
me->StopMoving();
events.ScheduleEvent(EVENT_PATH_2, 9s);
_Reset();
}
if (type == 1 && data == 2)
events.ScheduleEvent(EVENT_SUCCESS_1, 5s);
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();
}
void UpdateAI(uint32 diff) override
if (action == ACTION_ADD_KILLED)
{
if (!UpdateVictim())
{
events.Update(diff);
_killedAdds++;
while (uint32 eventId = events.ExecuteEvent())
if (_killedAdds == MAX_DRAKONID_KILLED)
{
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn))
{
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;
}
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);
}
}
}
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;
}
// Only do this if we haven't spawned nefarian yet
if (UpdateVictim() && KilledAdds <= MAX_DRAKONID_KILLED)
while (uint32 eventId = events.ExecuteEvent())
{
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))
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
@ -545,12 +528,8 @@ struct boss_nefarian : public BossAI
{
_Reset();
if (Creature* victor = me->FindNearestCreature(NPC_VICTOR_NEFARIUS, 200.f, true))
{
if (victor->AI())
{
victor->AI()->DoAction(ACTION_RESET);
}
}
me->DespawnOrUnsummon();
}
@ -578,9 +557,7 @@ struct boss_nefarian : public BossAI
void KilledUnit(Unit* victim) override
{
if (rand32() % 5)
{
return;
}
Talk(SAY_SLAY, victim);
}
@ -588,14 +565,10 @@ struct boss_nefarian : public BossAI
void MovementInform(uint32 type, uint32 id) override
{
if (type != WAYPOINT_MOTION_TYPE)
{
return;
}
if (id == 4)
{
Talk(SAY_INTRO);
}
if (id == 6)
{
@ -617,9 +590,7 @@ struct boss_nefarian : public BossAI
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
if (me->GetVictim())
{
AttackStart(me->GetVictim());
}
events.ScheduleEvent(EVENT_SHADOWFLAME, 12s);
events.ScheduleEvent(EVENT_FEAR, 25s, 35s);
@ -633,16 +604,12 @@ struct boss_nefarian : public BossAI
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
@ -671,16 +638,10 @@ struct boss_nefarian : public BossAI
break;
case EVENT_CLASSCALL:
if (classesPresent.empty())
{
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* victim = ref->GetVictim())
{
if (victim->IsPlayer())
classesPresent.insert(victim->getClass());
}
}
}
uint8 targetClass = Acore::Containers::SelectRandomContainerElement(classesPresent);
@ -731,9 +692,7 @@ struct boss_nefarian : public BossAI
me->GetMap()->DoForAllPlayers([&](Player* p)
{
if (!p->IsGameMaster())
{
me->CastSpell(p, SPELL_DEATH_KNIGHT, true);
}
});
break;
default:
@ -745,9 +704,7 @@ struct boss_nefarian : public BossAI
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
@ -783,9 +740,7 @@ struct npc_corrupted_totem : public ScriptedAI
{
me->AddUnitState(UNIT_STATE_ROOT);
if (!me->HasAura(SPELL_ROOT_SELF))
{
me->AddAura(SPELL_ROOT_SELF, me);
}
me->AddAura(AURA_AVOIDANCE, me);
scheduler.CancelAll();
@ -809,9 +764,7 @@ struct npc_corrupted_totem : public ScriptedAI
}
if (!spellId)
{
return;
}
std::vector<uint32> mobsEntries =
{
@ -835,25 +788,19 @@ struct npc_corrupted_totem : public ScriptedAI
tmpMobList.pop_front();
if (!curr->IsAlive())
{
continue;
}
if (apply && me->IsAlive())
{
if (me->IsWithinDistInMap(curr, 40.f))
{
if (!curr->HasAura(spellId))
{
curr->AddAura(spellId, curr);
}
}
else
{
if (curr->HasAura(spellId))
{
curr->RemoveAurasDueToSpell(spellId);
}
}
}
else
@ -899,9 +846,7 @@ struct npc_corrupted_totem : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
if (me->GetEntry() != NPC_TOTEM_C_FIRE_NOVA)
{
SetAura(false);
}
scheduler.CancelAll();
}
@ -909,9 +854,7 @@ struct npc_corrupted_totem : public ScriptedAI
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
scheduler.Update(diff);
}
@ -952,9 +895,7 @@ struct npc_drakonid_spawner : public ScriptedAI
void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override
{
if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner))
{
victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED);
}
ObjectGuid summonGuid = summon->GetGUID();
@ -1002,15 +943,11 @@ class spell_class_call_handler : public SpellScript
{
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
{
return true;
}
auto it = classCallSpells.find(spellInfo->Id);
if (it != classCallSpells.end()) // should never happen but only to be sure.
{
return target->ToPlayer()->getClass() != it->second;
}
return false;
});
@ -1022,9 +959,7 @@ class spell_class_call_handler : public SpellScript
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
{
return;
}
Position tp = caster->GetFirstCollisionPosition(5.f, 0.f);
target->NearTeleportTo(tp.GetPositionX(), tp.GetPositionY(), tp.GetPositionZ(), tp.GetOrientation());
@ -1033,9 +968,7 @@ class spell_class_call_handler : public SpellScript
void HandleOnHitWarlock()
{
if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_SUMMON_INFERNALS, true);
}
}
void Register() override
@ -1065,9 +998,7 @@ class aura_class_call_wild_magic : public AuraScript
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
if (!GetTarget())
{
return;
}
GetTarget()->CastSpell(GetTarget(), SPELL_POLYMORPH, true);
}
@ -1092,12 +1023,8 @@ class aura_class_call_siphon_blessing : public AuraScript
PreventDefaultAction();
if (Unit* target = GetTarget())
{
if (Unit* nefarian = target->FindNearestCreature(NPC_NEFARIAN, 100.f))
{
target->CastSpell(nefarian, SPELL_BLESSING_PROTECTION, true);
}
}
}
void Register() override
@ -1154,9 +1081,7 @@ class spell_corrupted_totems : public SpellScript
{
PreventHitDefaultEffect(effIndex);
if (!GetCaster())
{
return;
}
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);
@ -1207,15 +1132,11 @@ class spell_shadowblink : public SpellScript
{
Unit* caster = GetCaster();
if (!caster || !caster->ToCreature() || !caster->ToCreature()->AI())
{
return;
}
Unit* target = caster->ToCreature()->AI()->SelectTarget(SelectTargetMethod::Random, 0, 200.f, true);
if (!target)
{
return;
}
for (auto& itr : spellPos)
{
@ -1252,9 +1173,7 @@ class spell_spawn_drakonid : public SpellScript
{
Unit* caster = GetCaster();
if (!caster)
{
return;
}
caster->CastSpell(caster, spawnerSpells[caster->GetEntry()], true);
}
@ -1267,7 +1186,7 @@ class spell_spawn_drakonid : public SpellScript
void AddSC_boss_nefarian()
{
new boss_victor_nefarius();
RegisterBlackwingLairCreatureAI(boss_victor_nefarius);
RegisterCreatureAI(boss_nefarian);
RegisterCreatureAI(npc_corrupted_totem);
RegisterCreatureAI(npc_drakonid_spawner);

View file

@ -16,6 +16,8 @@
*/
#include "CreatureScript.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
@ -70,214 +72,190 @@ enum EVENTS
EVENT_CONFLAGRATION = 4
};
class boss_razorgore : public CreatureScript
struct boss_razorgore : public BossAI
{
public:
boss_razorgore() : CreatureScript("boss_razorgore") { }
boss_razorgore(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { }
struct boss_razorgoreAI : public BossAI
void Reset() override
{
boss_razorgoreAI(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { }
void Reset() override
{
_Reset();
_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);
_Reset();
_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;
};
class go_orb_of_domination : public GameObjectScript
struct go_orb_of_domination : public GameObjectAI
{
public:
go_orb_of_domination() : GameObjectScript("go_orb_of_domination") { }
go_orb_of_domination(GameObject* go) : GameObjectAI(go) { }
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 (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->Attack(player, true);
@ -294,12 +272,9 @@ class spell_egg_event : public SpellScript
void HandleOnHit()
{
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
{
instance->SetData(DATA_EGG_EVENT, SPECIAL);
}
if (Creature* razorgore = GetCaster()->ToCreature())
{
if (GameObject* egg = GetHitGObj())
{
razorgore->AI()->DoAction(TALK_EGG_BROKEN_RAND);
@ -307,7 +282,6 @@ class spell_egg_event : public SpellScript
egg->UseDoorOrButton(10000);
egg->SetRespawnTime(WEEK);
}
}
}
void Register() override
@ -318,7 +292,7 @@ class spell_egg_event : public SpellScript
void AddSC_boss_razorgore()
{
new boss_razorgore();
new go_orb_of_domination();
RegisterBlackwingLairCreatureAI(boss_razorgore);
RegisterBlackwingLairGameObjectAI(go_orb_of_domination);
RegisterSpellScript(spell_egg_event);
}

View file

@ -72,227 +72,214 @@ enum Events
EVENT_BURNING_ADRENALINE = 12,
};
class boss_vaelastrasz : public CreatureScript
struct boss_vaelastrasz : public BossAI
{
public:
boss_vaelastrasz() : CreatureScript("boss_vaelastrasz") { }
struct boss_vaelAI : public BossAI
boss_vaelastrasz(Creature* creature) : BossAI(creature, DATA_VAELASTRAZ_THE_CORRUPT)
{
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();
_eventsIntro.Reset();
}
void Initialize()
else
{
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
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();
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())
while (uint32 eventId = _eventsIntro.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CLEAVE:
events.ScheduleEvent(EVENT_CLEAVE, 15s);
DoCastVictim(SPELL_CLEAVE);
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_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
case EVENT_SPEECH_2:
if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid))
{
//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++;
nefarius->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY);
nefarius->Yell(SAY_NEFARIAN_VAEL_INTRO);
nefarius->SetStandState(UNIT_STAND_STATE_STAND);
}
else
{
me->CastSpell(me->GetVictim(), SPELL_BURNING_ADRENALINE, true);
_burningAdrenalineCast = 0;
}
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s);
_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;
}
}
}
// 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
summoned->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
m_nefariusGuid = summoned->GetGUID();
case EVENT_CLEAVE:
events.ScheduleEvent(EVENT_CLEAVE, 15s);
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)
{
CloseGossipMenuFor(player);
BeginSpeech(player);
}
Talk(SAY_HALFLIFE);
HasYelled = true;
}
private:
ObjectGuid PlayerGUID;
ObjectGuid m_nefariusGuid;
bool HasYelled;
bool _introDone;
EventMap _eventsIntro;
uint8 _burningAdrenalineCast;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetBlackwingLairAI<boss_vaelAI>(creature);
DoMeleeAttackIfReady();
}
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
@ -308,9 +295,7 @@ class spell_vael_burning_adrenaline : public AuraScript
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (!GetTarget())
{
return;
}
// Do the explosion, then kill the target.
GetTarget()->CastSpell(GetTarget(), SPELL_BURNING_ADRENALINE_EXPLOSION, true);
@ -325,6 +310,6 @@ class spell_vael_burning_adrenaline : public AuraScript
void AddSC_boss_vaelastrasz()
{
new boss_vaelastrasz();
RegisterBlackwingLairCreatureAI(boss_vaelastrasz);
RegisterSpellScript(spell_vael_burning_adrenaline);
}

View file

@ -72,404 +72,355 @@ Position const SummonPosition[8] =
uint32 const Entry[3] = { 12422, 12416, 12420 };
class instance_blackwing_lair : public InstanceMapScript
struct instance_blackwing_lair : public InstanceScript
{
public:
instance_blackwing_lair() : InstanceMapScript(BWLScriptName, MAP_BLACKWING_LAIR) { }
struct instance_blackwing_lair_InstanceMapScript : public InstanceScript
instance_blackwing_lair(Map* map) : InstanceScript(map)
{
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);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
LoadObjectData(creatureData, objectData);
case NPC_RAZORGORE:
razorgoreGUID = creature->GetGUID();
break;
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
EggCount = 0;
EggEvent = 0;
NefarianLeftTunnel = 0;
NefarianRightTunnel = 0;
addsCount.fill(0);
case DATA_BROODLORD_LASHLAYER:
if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE)
return false;
break;
default:
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.
if (creature->GetEntry() == NPC_VICTOR_NEFARIUS && creature->ToTempSummon())
{
return;
}
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))
case DATA_RAZORGORE_THE_UNTAMED:
if (state == DONE)
{
for (ObjectGuid const& guid : EggList)
{
if (CreatureAI* razorAI = razor->AI())
{
razorAI->JustSummoned(creature);
}
// Eggs should be destroyed instead
/// @todo: after dynamic spawns
if (GameObject* egg = instance->GetGameObject(guid))
egg->SetPhaseMask(2, true);
}
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;
}
}
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 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
void SetData(uint32 type, uint32 data) override
{
if (type == DATA_EGG_EVENT)
{
switch (data)
{
case DATA_NEFARIAN_LEFT_TUNNEL:
return NefarianLeftTunnel;
case DATA_NEFARIAN_RIGHT_TUNNEL:
return NefarianRightTunnel;
case DATA_EGG_EVENT:
return EggEvent;
default:
case DONE:
EggEvent = data;
break;
}
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;
case FAIL:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
break;
default:
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);
return true;
}
for (ObjectGuid const& guid : EggList)
DoRespawnGameObject(guid, 0);
bool SetBossState(uint32 type, EncounterState state) override
{
if (!InstanceScript::SetBossState(type, state))
return false;
DoRespawnCreature(DATA_GRETHOK);
switch (type)
{
case DATA_RAZORGORE_THE_UNTAMED:
if (state == DONE)
for (ObjectGuid const& guid : guardList)
DoRespawnCreature(guid);
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
/// @todo: after dynamic spawns
if (GameObject* egg = instance->GetGameObject(guid))
{
egg->SetPhaseMask(2, true);
}
SetData(DATA_EGG_EVENT, DONE);
razor->RemoveAurasDueToSpell(19832); // MindControl
DoRemoveAurasDueToSpellOnPlayers(19832);
}
}
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.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1s);
_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;
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())
return;
case DATA_RAZORGORE_THE_UNTAMED:
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;
for (uint8 i = urand(2, 5); i > 0; --i)
{
uint32 mobEntry = Entry[urand(0, 2)];
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 (dragonkinsCount >= 12)
// If more than 12 dragonkins...
if (dragonkinsCount >= 12)
{
//... and more than 40 orcs - stop spawning more adds.
if (orcsCount >= 40)
{
//... and more than 40 orcs - stop spawning more adds.
if (orcsCount >= 40)
{
spawnMoreAdds = false;
break;
}
//... - stop spawning them.
else if (mobEntry == NPC_BLACKWING_DRAGON)
{
continue;
}
spawnMoreAdds = false;
break;
}
// If more than 40 orcs - stop spawning them.
else if (orcsCount >= 40 && mobEntry != NPC_BLACKWING_DRAGON)
//... - stop spawning them.
else if (mobEntry == NPC_BLACKWING_DRAGON)
{
continue;
}
if (Creature* summon = instance->SummonCreature(mobEntry, SummonPosition[urand(0, 7)]))
{
summon->AI()->DoZoneInCombat();
}
}
if (spawnMoreAdds)
// If more than 40 orcs - stop spawning them.
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:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
if (Creature* razor = instance->GetCreature(razorgoreGUID))
razor->AI()->DoAction(ACTION_PHASE_TWO);
break;
case EVENT_RESPAWN_NEFARIUS:
if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS))
{
nefarius->SetPhaseMask(1, true);
nefarius->setActive(true);
nefarius->Respawn();
nefarius->GetMotionMaster()->MoveTargetedHome();
}
break;
}
if (spawnMoreAdds)
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15s);
}
break;
case EVENT_RAZOR_PHASE_TWO:
_events.CancelEvent(EVENT_RAZOR_SPAWN);
if (Creature* razor = instance->GetCreature(razorgoreGUID))
razor->AI()->DoAction(ACTION_PHASE_TWO);
break;
case EVENT_RESPAWN_NEFARIUS:
if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS))
{
nefarius->SetPhaseMask(1, true);
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
@ -527,7 +478,7 @@ public:
void AddSC_instance_blackwing_lair()
{
new instance_blackwing_lair();
RegisterInstanceScript(instance_blackwing_lair, MAP_BLACKWING_LAIR);
RegisterSpellScript(spell_bwl_shadowflame);
new at_orb_of_command();
}

View file

@ -43,88 +43,73 @@ enum Events
EVENT_LIVING_BOMB,
};
class boss_baron_geddon : public CreatureScript
struct boss_baron_geddon : public BossAI
{
public:
boss_baron_geddon() : CreatureScript("boss_baron_geddon") { }
struct boss_baron_geddonAI : public BossAI
boss_baron_geddon(Creature* creature) : BossAI(creature, DATA_GEDDON),
armageddonCasted(false)
{
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
@ -149,9 +134,7 @@ class spell_geddon_inferno_aura : public AuraScript
void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* pCreatureTarget = GetTarget()->ToCreature())
{
pCreatureTarget->SetReactState(REACT_AGGRESSIVE);
}
}
void PeriodicTick(AuraEffect const* aurEff)
@ -209,9 +192,7 @@ class spell_geddon_armageddon_aura : public AuraScript
void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* pCreatureTarget = GetTarget()->ToCreature())
{
pCreatureTarget->SetReactState(REACT_AGGRESSIVE);
}
}
void Register() override
@ -223,7 +204,7 @@ class spell_geddon_armageddon_aura : public AuraScript
void AddSC_boss_baron_geddon()
{
new boss_baron_geddon();
RegisterMoltenCoreCreatureAI(boss_baron_geddon);
// Spells
RegisterSpellScript(spell_geddon_inferno_aura);

View file

@ -51,123 +51,93 @@ enum Events
EVENT_MAGMA_SHACKLES,
};
class boss_garr : public CreatureScript
struct boss_garr : public BossAI
{
public:
boss_garr() : CreatureScript("boss_garr") {}
struct boss_garrAI : public BossAI
boss_garr(Creature* creature) : BossAI(creature, DATA_GARR),
massEruptionTimer(600000) // 10 mins
{
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();
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())
switch (eventId)
{
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))
{
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:
uint32 massEruptionTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_garrAI>(creature);
DoMeleeAttackIfReady();
}
private:
uint32 massEruptionTimer;
};
class npc_garr_firesworn : public CreatureScript
struct npc_garr_firesworn : public ScriptedAI
{
public:
npc_garr_firesworn() : CreatureScript("npc_garr_firesworn") {}
npc_garr_firesworn(Creature* creature) : ScriptedAI(creature) {}
struct npc_garr_fireswornAI : public ScriptedAI
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override
{
npc_garr_fireswornAI(Creature* creature) : ScriptedAI(creature) {}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override
if (damage >= me->GetHealth())
{
if (damage >= me->GetHealth())
{
// Prevent double damage because Firesworn can kill himself with Massive Erruption
if (me != attacker)
{
DoCastSelf(SPELL_ERUPTION, true);
}
// Prevent double damage because Firesworn can kill himself with Massive Eruption
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*/)
{
if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_FRENZY);
}
}
void Register() override
@ -223,8 +191,8 @@ class spell_garr_frenzy : public SpellScript
void AddSC_boss_garr()
{
new boss_garr();
new npc_garr_firesworn();
RegisterMoltenCoreCreatureAI(boss_garr);
RegisterMoltenCoreCreatureAI(npc_garr_firesworn);
// Spells
RegisterSpellScript(spell_garr_separation_anxiety_aura);

View file

@ -34,74 +34,57 @@ enum Events
EVENT_SHADOW_BOLT,
};
class boss_gehennas : public CreatureScript
struct boss_gehennas : public BossAI
{
public:
boss_gehennas() : CreatureScript("boss_gehennas") { }
boss_gehennas(Creature* creature) : BossAI(creature, DATA_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();
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:
{
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);
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))
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
{
DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
}
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
}
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
else
{
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()
{
new boss_gehennas();
RegisterMoltenCoreCreatureAI(boss_gehennas);
}

View file

@ -40,191 +40,157 @@ enum Spells
SPELL_FULL_HEAL = 17683,
};
class boss_golemagg : public CreatureScript
struct boss_golemagg : public BossAI
{
public:
boss_golemagg() : CreatureScript("boss_golemagg") { }
boss_golemagg(Creature* creature) : BossAI(creature, DATA_GOLEMAGG),
earthquakeTimer(0),
pyroblastTimer(0),
enraged(false)
{}
struct boss_golemaggAI : public BossAI
void Reset() override
{
boss_golemaggAI(Creature* creature) : BossAI(creature, DATA_GOLEMAGG),
earthquakeTimer(0),
pyroblastTimer(0),
enraged(false)
{}
_Reset();
earthquakeTimer = 0;
pyroblastTimer = urand(3000, 7000);
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();
earthquakeTimer = 0;
pyroblastTimer = urand(3000, 7000);
enraged = false;
DoCastSelf(SPELL_MAGMASPLASH);
DoCastSelf(SPELL_GOLEMAGG_TRUST_AURA);
DoCastSelf(SPELL_DOUBLE_ATTACK);
DoCastSelf(SPELL_ATTRACK_RAGER, true);
DoCastAOE(SPELL_EARTHQUAKE, true);
earthquakeTimer = 5000;
enraged = true;
}
}
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);
DoCastAOE(SPELL_EARTHQUAKE, true);
DoCastSelf(SPELL_EARTHQUAKE, true);
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
{
pyroblastTimer -= diff;
earthquakeTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
uint32 earthquakeTimer;
uint32 pyroblastTimer;
bool enraged;
};
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_golemaggAI>(creature);
if (pyroblastTimer <= diff)
{
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() : CreatureScript("npc_core_rager") { }
struct npc_core_ragerAI : public ScriptedAI
npc_core_rager(Creature* creature) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
mangleTimer(7000),
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()
{
new boss_golemagg();
new npc_core_rager();
RegisterMoltenCoreCreatureAI(boss_golemagg);
RegisterMoltenCoreCreatureAI(npc_core_rager);
}

View file

@ -33,56 +33,45 @@ enum Events
EVENT_SHADOW_SHOCK = 3,
};
class boss_lucifron : public CreatureScript
struct boss_lucifron : public BossAI
{
public:
boss_lucifron() : CreatureScript("boss_lucifron") { }
boss_lucifron(Creature* creature) : BossAI(creature, DATA_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();
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:
{
case EVENT_IMPENDING_DOOM:
{
DoCastVictim(SPELL_IMPENDING_DOOM);
events.Repeat(20s);
break;
}
case EVENT_LUCIFRON_CURSE:
{
DoCastVictim(SPELL_LUCIFRON_CURSE);
events.Repeat(20s);
break;
}
case EVENT_SHADOW_SHOCK:
{
DoCastVictim(SPELL_SHADOW_SHOCK);
events.Repeat(5s);
break;
}
DoCastVictim(SPELL_IMPENDING_DOOM);
events.Repeat(20s);
break;
}
case EVENT_LUCIFRON_CURSE:
{
DoCastVictim(SPELL_LUCIFRON_CURSE);
events.Repeat(20s);
break;
}
case EVENT_SHADOW_SHOCK:
{
DoCastVictim(SPELL_SHADOW_SHOCK);
events.Repeat(5s);
break;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_lucifronAI>(creature);
}
};
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;
class boss_magmadar : public CreatureScript
struct boss_magmadar : public BossAI
{
public:
boss_magmadar() : CreatureScript("boss_magmadar") {}
boss_magmadar(Creature* creature) : BossAI(creature, DATA_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();
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:
{
case EVENT_FRENZY:
{
Talk(EMOTE_FRENZY);
DoCastSelf(SPELL_FRENZY);
events.Repeat(15s, 20s);
break;
}
case EVENT_PANIC:
{
DoCastVictim(SPELL_PANIC);
events.Repeat(31s, 38s);
break;
}
case EVENT_LAVA_BOMB:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true))
{
DoCast(target, SPELL_LAVA_BOMB);
}
Talk(EMOTE_FRENZY);
DoCastSelf(SPELL_FRENZY);
events.Repeat(15s, 20s);
break;
}
case EVENT_PANIC:
{
DoCastVictim(SPELL_PANIC);
events.Repeat(31s, 38s);
break;
}
case EVENT_LAVA_BOMB:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true))
DoCast(target, SPELL_LAVA_BOMB);
events.Repeat(12s, 15s);
break;
}
case EVENT_LAVA_BOMB_RANGED:
events.Repeat(12s, 15s);
break;
}
case EVENT_LAVA_BOMB_RANGED:
{
std::list<Unit*> targets;
SelectTargetList(targets, 1, SelectTargetMethod::Random, 1, [this](Unit* target)
{
std::list<Unit*> targets;
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;
});
return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f;
});
if (!targets.empty())
{
DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED);
}
events.Repeat(12s, 15s);
break;
}
if (!targets.empty())
DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED);
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()
{
new boss_magmadar();
RegisterMoltenCoreCreatureAI(boss_magmadar);
// Spells
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) { }
};
class boss_majordomo : public CreatureScript
struct boss_majordomo : public BossAI
{
public:
boss_majordomo() : CreatureScript("boss_majordomo") {}
boss_majordomo(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {}
struct boss_majordomoAI : public BossAI
void JustDied(Unit* /*killer*/) override
{
boss_majordomoAI(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {}
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;
Talk(SAY_DEATH);
me->DespawnOrUnsummon(10s, 0s);
}
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);
switch (action)
@ -544,40 +521,39 @@ public:
case GOSSIP_ACTION_INFO_DEF:
{
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;
}
case GOSSIP_ACTION_INFO_DEF+1:
{
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;
}
case GOSSIP_ACTION_INFO_DEF+2:
{
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;
}
case GOSSIP_ACTION_INFO_DEF+3:
{
CloseGossipMenuFor(player);
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
creature->AI()->Talk(SAY_RAG_SUM_1, player);
creature->AI()->DoAction(ACTION_START_RAGNAROS_INTRO);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
Talk(SAY_RAG_SUM_1, player);
DoAction(ACTION_START_RAGNAROS_INTRO);
break;
}
default:
CloseGossipMenuFor(player);
break;
}
return true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<boss_majordomoAI>(creature);
}
private:
GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion
GuidSet aliveMinionsGUIDS; // used for calculations
std::unordered_map<uint32, MajordomoAddData> majordomoSummonsData;
};
// 20538 Hate to Zero (SERVERSIDE)
@ -593,12 +569,8 @@ class spell_hate_to_zero : public SpellScript
void HandleHit(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (Creature* creatureCaster = caster->ToCreature())
{
creatureCaster->GetThreatMgr().ResetAllThreat();
}
}
}
void Register() override
@ -641,9 +613,7 @@ class spell_summon_ragnaros : public SpellScript
void HandleHit()
{
if (Unit* caster = GetCaster())
{
caster->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2 * HOUR * IN_MILLISECONDS);
}
}
void Register() override
@ -654,7 +624,7 @@ class spell_summon_ragnaros : public SpellScript
void AddSC_boss_majordomo()
{
new boss_majordomo();
RegisterMoltenCoreCreatureAI(boss_majordomo);
// Spells
RegisterSpellScript(spell_hate_to_zero);

View file

@ -112,390 +112,353 @@ enum Misc
constexpr float DEATH_ORIENTATION = 4.0f;
class boss_ragnaros : public CreatureScript
struct boss_ragnaros : public BossAI
{
public:
boss_ragnaros() : CreatureScript("boss_ragnaros") {}
struct boss_ragnarosAI : public BossAI
boss_ragnaros(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
_isIntroDone(false),
_hasYelledMagmaBurst(false),
_processingMagmaBurst(false),
_hasSubmergedOnce(false),
_isKnockbackEmoteAllowed(true)
{
boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
_isIntroDone(false),
_hasYelledMagmaBurst(false),
_processingMagmaBurst(false),
_hasSubmergedOnce(false),
_isKnockbackEmoteAllowed(true)
}
void Reset() override
{
_Reset();
// 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();
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);
}
}
void AttackStart(Unit* target) override
else
{
if (target && me->Attack(target, true))
{
DoStartNoMovement(target);
}
BossAI::EnterEvadeMode(why);
}
}
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())
{
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);
}
}
extraEvents.Update(diff);
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())
{
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())
while (uint32 const eventId = extraEvents.ExecuteEvent())
{
switch (eventId)
{
case EVENT_WRATH_OF_RAGNAROS:
// Intro events
case EVENT_INTRO_SAY:
{
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
if (urand(0, 1))
{
Talk(SAY_WRATH);
}
events.Repeat(25s);
Talk(SAY_ARRIVAL5_RAG);
extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500ms, 0, PHASE_INTRO);
break;
}
case EVENT_HAND_OF_RAGNAROS:
case EVENT_INTRO_MAKE_ATTACKABLE:
{
DoCastSelf(SPELL_HAND_OF_RAGNAROS);
if (_isKnockbackEmoteAllowed)
_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())
{
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;
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;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
case EVENT_SUBMERGE:
{
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();
}
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))
{
if (me->HasUnitState(UNIT_STATE_CASTING))
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);
}
DoMeleeAttackIfReady();
}
bool IsVictimWithinMeleeRange() const
{
return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim());
}
};
private:
EventMap extraEvents;
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())
{
for (uint32 spell : RagnarosSoFSpells)
{
caster->CastSpell(caster, spell, true);
}
}
}
@ -561,7 +522,7 @@ class spell_ragnaros_summon_sons_of_flame : public SpellScript
void AddSC_boss_ragnaros()
{
new boss_ragnaros();
RegisterMoltenCoreCreatureAI(boss_ragnaros);
RegisterSpellScript(spell_ragnaros_lava_burst_randomizer);
RegisterSpellScript(spell_ragnaros_summon_sons_of_flame);
}

View file

@ -41,70 +41,57 @@ enum Events
EVENT_SHAZZRAH_GATE,
};
class boss_shazzrah : public CreatureScript
struct boss_shazzrah : public BossAI
{
public:
boss_shazzrah() : CreatureScript("boss_shazzrah") { }
boss_shazzrah(Creature* creature) : BossAI(creature, DATA_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();
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:
{
case EVENT_ARCANE_EXPLOSION:
{
DoCastVictim(SPELL_ARCANE_EXPLOSION);
events.Repeat(4s, 5s);
break;
}
case EVENT_SHAZZRAH_CURSE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE))
{
DoCast(target, SPELL_SHAZZRAH_CURSE);
}
events.Repeat(23s, 26s);
break;
}
case EVENT_MAGIC_GROUNDING:
{
DoCastSelf(SPELL_MAGIC_GROUNDING);
events.Repeat(7s, 9s);
break;
}
case EVENT_COUNTERSPELL:
{
DoCastAOE(SPELL_COUNTERSPELL);
events.Repeat(15s, 18s);
break;
}
case EVENT_SHAZZRAH_GATE:
{
DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, 3s, 6s);
events.Repeat(45s);
break;
}
DoCastVictim(SPELL_ARCANE_EXPLOSION);
events.Repeat(4s, 5s);
break;
}
case EVENT_SHAZZRAH_CURSE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE))
DoCast(target, SPELL_SHAZZRAH_CURSE);
events.Repeat(23s, 26s);
break;
}
case EVENT_MAGIC_GROUNDING:
{
DoCastSelf(SPELL_MAGIC_GROUNDING);
events.Repeat(7s, 9s);
break;
}
case EVENT_COUNTERSPELL:
{
DoCastAOE(SPELL_COUNTERSPELL);
events.Repeat(15s, 18s);
break;
}
case EVENT_SHAZZRAH_GATE:
{
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();
// Should not target non player targets
if (!plrTarget)
{
return true;
}
// Should skip current victim
if (caster->GetVictim() == plrTarget)
{
return true;
}
// Should not target enemies within melee range
if (plrTarget->IsWithinMeleeRange(caster))
{
return true;
}
return false;
});
}
if (!targets.empty())
{
Acore::Containers::RandomResize(targets, 1);
}
}
void HandleScript(SpellEffIndex /*effIndex*/)
@ -182,7 +161,7 @@ class spell_shazzrah_gate_dummy : public SpellScript
void AddSC_boss_shazzrah()
{
new boss_shazzrah();
RegisterMoltenCoreCreatureAI(boss_shazzrah);
// Spells
RegisterSpellScript(spell_shazzrah_gate_dummy);

View file

@ -47,172 +47,138 @@ enum Events
EVENT_IMMOLATE,
};
class boss_sulfuron : public CreatureScript
struct boss_sulfuron : public BossAI
{
public:
boss_sulfuron() : CreatureScript("boss_sulfuron") {}
boss_sulfuron(Creature* creature) : BossAI(creature, DATA_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();
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:
{
case EVENT_DEMORALIZING_SHOUT:
{
DoCastVictim(SPELL_DEMORALIZING_SHOUT);
events.Repeat(12s, 18s);
break;
}
case EVENT_INSPIRE:
{
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
if (!healers.empty())
{
DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
}
DoCastVictim(SPELL_DEMORALIZING_SHOUT);
events.Repeat(12s, 18s);
break;
}
case EVENT_INSPIRE:
{
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
if (!healers.empty())
DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
DoCastSelf(SPELL_INSPIRE);
events.Repeat(13s, 20s);
break;
}
case EVENT_KNOCKDOWN:
{
DoCastVictim(SPELL_KNOCKDOWN);
events.Repeat(10s, 20s);
break;
}
case EVENT_FLAMESPEAR:
{
DoCastRandomTarget(SPELL_FLAMESPEAR);
events.Repeat(12s, 16s);
break;
}
DoCastSelf(SPELL_INSPIRE);
events.Repeat(13s, 20s);
break;
}
case EVENT_KNOCKDOWN:
{
DoCastVictim(SPELL_KNOCKDOWN);
events.Repeat(10s, 20s);
break;
}
case EVENT_FLAMESPEAR:
{
DoCastRandomTarget(SPELL_FLAMESPEAR);
events.Repeat(12s, 16s);
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() : CreatureScript("npc_flamewaker_priest") {}
npc_flamewaker_priest(Creature* creature) : ScriptedAI(creature) {}
struct npc_flamewaker_priestAI : public ScriptedAI
void Reset() override
{
npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature) {}
events.Reset();
}
void Reset() override
{
events.Reset();
}
void JustDied(Unit* /*killer*/) override
{
events.Reset();
}
void JustDied(Unit* /*killer*/) override
{
events.Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
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
{
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 UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
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))
{
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:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_flamewaker_priestAI>(creature);
DoMeleeAttackIfReady();
}
private:
EventMap events;
};
void AddSC_boss_sulfuron()
{
new boss_sulfuron();
new npc_flamewaker_priest();
RegisterMoltenCoreCreatureAI(boss_sulfuron);
RegisterMoltenCoreCreatureAI(npc_flamewaker_priest);
}

View file

@ -53,384 +53,331 @@ MCBossObject const linkedBossObjData[MAX_MC_LINKED_BOSS_OBJ]=
constexpr uint8 SAY_SPAWN = 1;
class instance_molten_core : public InstanceMapScript
struct instance_molten_core : public InstanceScript
{
public:
instance_molten_core() : InstanceMapScript(MCScriptName, MAP_MOLTEN_CORE) {}
struct instance_molten_core_InstanceMapScript : public InstanceScript
instance_molten_core(Map* map) : InstanceScript(map)
{
instance_molten_core_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
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);
SetHeaders(DataHeader);
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;
};
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
class npc_mc_core_hound : public CreatureScript
struct npc_mc_core_hound : public CreatureAI
{
public:
npc_mc_core_hound() : CreatureScript("npc_mc_core_hound") {}
struct npc_mc_core_houndAI : public CreatureAI
npc_mc_core_hound(Creature* creature) :
CreatureAI(creature),
instance(creature->GetInstanceScript()),
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
@ -136,9 +121,7 @@ class spell_mc_play_dead_aura : public AuraScript
{
Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget)
{
return;
}
creatureTarget->CastSpell(creatureTarget, SPELL_PLAY_DEAD_PACIFY, true);
creatureTarget->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
@ -154,9 +137,7 @@ class spell_mc_play_dead_aura : public AuraScript
{
Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget)
{
return;
}
creatureTarget->RemoveAurasDueToSpell(SPELL_PLAY_DEAD_PACIFY);
creatureTarget->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD);
@ -166,9 +147,7 @@ class spell_mc_play_dead_aura : public AuraScript
creatureTarget->SetReactState(REACT_AGGRESSIVE);
if (!creatureTarget->IsInCombat())
{
return;
}
bool shouldDie = true;
std::list<Creature*> hounds;
@ -246,9 +225,7 @@ struct npc_lava_spawn : public ScriptedAI
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
_scheduler.Update(diff);
@ -262,7 +239,7 @@ private:
void AddSC_molten_core()
{
// Creatures
new npc_mc_core_hound();
RegisterMoltenCoreCreatureAI(npc_mc_core_hound);
RegisterCreatureAI(npc_lava_spawn);
// Spells

View file

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