diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
index 760b96bd0dd..8c3444e1381 100644
--- a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
@@ -15,15 +15,16 @@
* with this program. If not, see .
*/
+#include "stonecore.h"
#include "ScriptMgr.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "Map.h"
#include "MotionMaster.h"
+#include "PassiveAI.h"
#include "ScriptedCreature.h"
#include "Spell.h"
#include "SpellScript.h"
-#include "stonecore.h"
enum Spells
{
@@ -51,23 +52,16 @@ enum Spells
enum Actions
{
- ACTION_STALACTITE_MISSLE
+ ACTION_STALACTITE_MISSLE = 0
};
enum Events
{
- EVENT_NONE,
-
- // Intro events
- EVENT_LAND_INTRO,
- EVENT_ROAR_EMOTE,
-
- // Slabhide combat
- EVENT_HANDLE_ROCK_WALLS,
+ // Slabhide
+ EVENT_HANDLE_ROCK_WALLS = 1,
EVENT_LAVA_FISSURE,
EVENT_SAND_BLAST,
EVENT_AIR_PHASE,
- EVENT_STALACTITE,
EVENT_LAND,
EVENT_ATTACK,
@@ -86,9 +80,7 @@ enum Phases
enum MovementPoints
{
- POINT_NONE,
-
- POINT_SLABHIDE_INTRO,
+ POINT_SLABHIDE_INTRO = 1,
POINT_SLABHIDE_INTRO_LAND,
POINT_SLABHIDE_MIDDLE,
@@ -103,302 +95,250 @@ Position const SlabhideMiddlePos = { 1280.73f, 1212.31f, 247.3837f };
Position const SlabhideInAirPos = { 1280.73f, 1212.31f, 257.3837f };
Position const SlabhideLandPos = { 1282.7f, 1229.77f, 247.155f, 3.82227f };
-class boss_slabhide : public CreatureScript
+struct boss_slabhide : public BossAI
{
- public:
- boss_slabhide() : CreatureScript("boss_slabhide") { }
+ boss_slabhide(Creature* creature) : BossAI(creature, DATA_SLABHIDE), _isFlying(false) { }
- struct boss_slabhideAI : public BossAI
- {
- boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE)
- {
- Initialize();
- }
-
- void Initialize()
- {
- _isFlying = false;
- }
-
- void Reset() override
- {
- _Reset();
- Initialize();
-
- if (instance->GetData(DATA_EVENT_PROGRESS) == EVENT_INDEX_SLABHIDE_INTRO)
- {
- me->SetCanFly(false);
- me->SetDisableGravity(false);
- }
- else
- {
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->setActive(true);
- me->SetCanFly(true);
- me->SetDisableGravity(true);
- me->SetReactState(REACT_PASSIVE);
- events.SetPhase(PHASE_INTRO);
- }
- }
-
- void DamageTaken(Unit* /*attacker*/, uint32& damage) override
- {
- if (_isFlying && damage >= me->GetHealth())
- damage = me->GetHealth() - 1; // Let creature health fall to 1 hp but prevent it from dying during air phase.
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
-
- events.SetPhase(PHASE_COMBAT);
- events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, Seconds(4));
- events.ScheduleEvent(EVENT_LAVA_FISSURE, Seconds(6), Seconds(8));
- events.ScheduleEvent(EVENT_SAND_BLAST, Seconds(8), Seconds(10));
- events.ScheduleEvent(EVENT_AIR_PHASE, Seconds(10));
- }
-
- void EnterEvadeMode(EvadeReason /*why*/) override
- {
- _EnterEvadeMode();
- instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
- instance->SetBossState(DATA_SLABHIDE, FAIL);
- DespawnAll();
- summons.DespawnAll();
- me->DespawnOrUnsummon();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
- DespawnAll();
- }
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_SLABHIDE_INTRO:
- me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos, false);
- break;
- default:
- break;
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
- return;
-
- switch (id)
- {
- case POINT_SLABHIDE_INTRO:
- me->SetFacingTo(SlabhideIntroLandPos.GetOrientation());
- events.ScheduleEvent(EVENT_LAND_INTRO, Milliseconds(200));
- break;
- case POINT_SLABHIDE_INTRO_LAND:
- me->SetCanFly(false);
- me->SetDisableGravity(false);
- me->SetHover(false);
- me->SetHomePosition(SlabhideIntroLandPos);
- me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- break;
- case POINT_SLABHIDE_MIDDLE:
- _isFlying = true;
- me->SetCanFly(true);
- me->SetDisableGravity(true);
- me->SetHover(true);
- me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos);
- break;
- case POINT_SLABHIDE_IN_AIR:
- events.ScheduleEvent(EVENT_STALACTITE, Milliseconds(400));
- break;
- case POINT_SLABHIDE_LAND:
- _isFlying = false;
- me->SetCanFly(false);
- me->SetDisableGravity(false);
- me->SetHover(false);
- DoCast(me, SPELL_COOLDOWN_5S);
- events.ScheduleEvent(EVENT_ATTACK, Seconds(1) + Milliseconds(200));
- break;
- default:
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
- return;
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_LAND_INTRO:
- me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos);
- break;
- case EVENT_HANDLE_ROCK_WALLS:
- instance->SetData(DATA_SLABHIDE_ROCK_WALL, false);
- break;
- case EVENT_LAVA_FISSURE:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
- DoCast(target, SPELL_LAVA_FISSURE);
- events.Repeat(Seconds(6), Seconds(8));
- break;
- case EVENT_SAND_BLAST:
- DoCast(me, SPELL_SAND_BLAST);
- events.Repeat(Seconds(8), Seconds(11));
- break;
- case EVENT_AIR_PHASE:
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- me->AttackStop();
- me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos);
- events.Repeat(Seconds(60));
- break;
- case EVENT_STALACTITE:
- DoCast(me, SPELL_STALACTITE_SUMMON);
- events.ScheduleEvent(EVENT_LAND, Seconds(8));
- break;
- case EVENT_LAND:
- me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, SlabhideMiddlePos);
- break;
- case EVENT_ATTACK:
- events.ScheduleEvent(EVENT_LAVA_FISSURE, Seconds(6), Seconds(8));
- events.ScheduleEvent(EVENT_SAND_BLAST, Seconds(8), Seconds(10));
- me->SetReactState(REACT_AGGRESSIVE);
- if (IsHeroic())
- DoCast(me, SPELL_CRYSTAL_STORM_PERIODIC);
- break;
- default:
- break;
- }
- }
-
- DoMeleeAttackIfReady();
- }
-
- private:
- void DespawnAll()
- {
- // Despawn stalactite triggers npcs
- std::vector listStalactiteTrigger;
- me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f);
- for (Creature* creature : listStalactiteTrigger)
- creature->DespawnOrUnsummon();
-
- // Despawn stalactite objects
- std::vector listStalactite;
- me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f);
- for (GameObject* go : listStalactite)
- go->Delete();
- }
-
- bool _isFlying;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetStonecoreAI(creature);
- }
-};
-
-class npc_slabhide_lava_fissure : public CreatureScript
-{
- public:
- npc_slabhide_lava_fissure() : CreatureScript("npc_slabhide_lava_fissure") { }
-
- struct npc_slabhide_lava_fissureAI : public ScriptedAI
- {
- npc_slabhide_lava_fissureAI(Creature* creature) : ScriptedAI(creature) { }
-
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- DoCast(me, SPELL_LAVA_FISSURE_CRACK, true);
- _events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, IsHeroic() ? Seconds(3) : Seconds(5));
- }
-
- void UpdateAI(uint32 diff) override
- {
- _events.Update(diff);
-
- while (uint32 eventId = _events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_LAVA_FISSURE_ERUPTION:
- me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK);
- DoCast(me, SPELL_LAVA_FISSURE_ERUPTION, true);
- me->DespawnOrUnsummon(IsHeroic() ? Seconds(30) : Seconds(10));
- break;
- default:
- break;
- }
- }
- }
-
- private:
- EventMap _events;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetStonecoreAI(creature);
- }
-};
-
-class npc_slabhide_stalactite_trigger : public CreatureScript
-{
- public:
- npc_slabhide_stalactite_trigger() : CreatureScript("npc_slabhide_stalactite_trigger") { }
-
- struct npc_slabhide_stalactite_triggerAI : public ScriptedAI
- {
- npc_slabhide_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature) { }
-
- void IsSummonedBy(Unit* /*summoner*/) override
- {
- DoCast(me, SPELL_STALACTITE_SHADE, true);
- _events.ScheduleEvent(EVENT_STALACTITE_MISSLE, Seconds(1) + Milliseconds(300));
- }
-
- void UpdateAI(uint32 diff) override
- {
- _events.Update(diff);
-
- while (uint32 eventId = _events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_STALACTITE_MISSLE:
- DoCast(me, SPELL_STALACTITE_MISSILE);
- me->DespawnOrUnsummon(Seconds(11));
- break;
- default:
- break;
- }
- }
- }
-
- private:
- EventMap _events;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+ void InitializeAI() override
{
- return GetStonecoreAI(creature);
+ if (instance->GetData(DATA_EVENT_PROGRESS) == EVENT_INDEX_SLABHIDE_INTRO)
+ {
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ }
+ else
+ {
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+ me->SetReactState(REACT_PASSIVE);
+ events.SetPhase(PHASE_INTRO);
+ }
}
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (_isFlying && damage >= me->GetHealth())
+ damage = me->GetHealth() - 1; // Let creature health fall to 1 hp but prevent it from dying during air phase.
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+
+ events.SetPhase(PHASE_COMBAT);
+ events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4s);
+ events.ScheduleEvent(EVENT_LAVA_FISSURE, 6s, 8s);
+ events.ScheduleEvent(EVENT_SAND_BLAST, 8s, 10s);
+ events.ScheduleEvent(EVENT_AIR_PHASE, 10s);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ _EnterEvadeMode();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ instance->SetBossState(DATA_SLABHIDE, FAIL);
+ DespawnAll();
+ summons.DespawnAll();
+ me->DespawnOrUnsummon();
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ DespawnAll();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_SLABHIDE_INTRO:
+ me->setActive(true);
+ me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos, false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
+ return;
+
+ switch (id)
+ {
+ case POINT_SLABHIDE_INTRO:
+ me->SetFacingTo(SlabhideIntroLandPos.GetOrientation());
+ me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos);
+ break;
+ case POINT_SLABHIDE_INTRO_LAND:
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ me->SetHomePosition(SlabhideIntroLandPos);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ case POINT_SLABHIDE_MIDDLE:
+ _isFlying = true;
+ me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos);
+ break;
+ case POINT_SLABHIDE_IN_AIR:
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+ DoCastSelf(SPELL_STALACTITE_SUMMON);
+ events.ScheduleEvent(EVENT_LAND, 8s);
+ break;
+ case POINT_SLABHIDE_LAND:
+ _isFlying = false;
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ DoCastSelf(SPELL_COOLDOWN_5S);
+ events.ScheduleEvent(EVENT_ATTACK, 1s + 200ms);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_HANDLE_ROCK_WALLS:
+ instance->SetData(DATA_SLABHIDE_ROCK_WALL, false);
+ break;
+ case EVENT_LAVA_FISSURE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_LAVA_FISSURE);
+ events.Repeat(6s, 8s);
+ break;
+ case EVENT_SAND_BLAST:
+ DoCast(me, SPELL_SAND_BLAST);
+ events.Repeat(8s, 11s);
+ break;
+ case EVENT_AIR_PHASE:
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos);
+ events.Repeat(60s);
+ break;
+ case EVENT_LAND:
+ me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, SlabhideMiddlePos);
+ break;
+ case EVENT_ATTACK:
+ events.ScheduleEvent(EVENT_LAVA_FISSURE, 6s, 8s);
+ events.ScheduleEvent(EVENT_SAND_BLAST, 8s, 10s);
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (IsHeroic())
+ DoCast(me, SPELL_CRYSTAL_STORM_PERIODIC);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ void DespawnAll()
+ {
+ // Despawn stalactite triggers npcs
+ std::vector listStalactiteTrigger;
+ me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f);
+ for (Creature* creature : listStalactiteTrigger)
+ creature->DespawnOrUnsummon();
+
+ // Despawn stalactite objects
+ std::vector listStalactite;
+ me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f);
+ for (GameObject* go : listStalactite)
+ go->Delete();
+ }
+
+ bool _isFlying;
+};
+
+struct npc_slabhide_lava_fissure : public NullCreatureAI
+{
+ npc_slabhide_lava_fissure(Creature* creature) : NullCreatureAI(creature) { }
+
+ void JustAppeared() override
+ {
+ DoCast(me, SPELL_LAVA_FISSURE_CRACK);
+ bool isHeroic = me->GetMap()->IsHeroic();
+ _events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, isHeroic ? 3s : 5s);
+ me->DespawnOrUnsummon(isHeroic ? 33s : 15s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_LAVA_FISSURE_ERUPTION:
+ me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK);
+ DoCast(me, SPELL_LAVA_FISSURE_ERUPTION);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+private:
+ EventMap _events;
+};
+
+struct npc_slabhide_stalactite_trigger : public NullCreatureAI
+{
+ npc_slabhide_stalactite_trigger(Creature* creature) : NullCreatureAI(creature) { }
+
+ void IsSummonedBy(Unit* /*summoner*/) override
+ {
+ DoCast(me, SPELL_STALACTITE_SHADE, true);
+ _events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 1s + 300ms);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_STALACTITE_MISSLE:
+ DoCastSelf(SPELL_STALACTITE_MISSILE);
+ me->DespawnOrUnsummon(11s);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+private:
+ EventMap _events;
};
class spell_slabhide_stalactite : public SpellScript
@@ -483,9 +423,9 @@ class spell_slabhide_crystal_storm_periodic : public SpellScript
void AddSC_boss_slabhide()
{
- new boss_slabhide();
- new npc_slabhide_lava_fissure();
- new npc_slabhide_stalactite_trigger();
+ RegisterStonecoreCreatureAI(boss_slabhide);
+ RegisterStonecoreCreatureAI(npc_slabhide_lava_fissure);
+ RegisterStonecoreCreatureAI(npc_slabhide_stalactite_trigger);
RegisterSpellScript(spell_slabhide_stalactite);
RegisterSpellScript(spell_slabhide_stalactite_summon);
RegisterSpellScript(spell_slabhide_stalactite_dest_relocation);
diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.h b/src/server/scripts/Maelstrom/Stonecore/stonecore.h
index de8d8ecf2d7..10934d49da6 100644
--- a/src/server/scripts/Maelstrom/Stonecore/stonecore.h
+++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.h
@@ -125,4 +125,6 @@ inline AI* GetStonecoreAI(T* obj)
return GetInstanceAI(obj, SCScriptName);
}
+#define RegisterStonecoreCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetStonecoreAI)
+
#endif // DEF_STONECORE