aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp12
-rw-r--r--src/server/scripts/Maelstrom/CMakeLists.txt7
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp319
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp807
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp287
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp599
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp262
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/stonecore.cpp440
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/stonecore.h72
9 files changed, 2805 insertions, 0 deletions
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 0e43a63c98e..ad727fc17d2 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -677,6 +677,12 @@ void AddSC_zangarmarsh();
// Maelstrom
void AddSC_kezan();
+void AddSC_instance_stonecore(); // Stonecore
+void AddSC_stonecore();
+void AddSC_boss_corborus();
+void AddSC_boss_slabhide();
+void AddSC_boss_ozruk();
+void AddSC_boss_high_priestess_azil();
// Events
void AddSC_event_childrens_week();
@@ -1411,6 +1417,12 @@ void AddMaelstromScripts()
{
#ifdef SCRIPTS
AddSC_kezan();
+ AddSC_instance_stonecore(); // Stonecore
+ AddSC_stonecore();
+ AddSC_boss_corborus();
+ AddSC_boss_slabhide();
+ AddSC_boss_ozruk();
+ AddSC_boss_high_priestess_azil();
#endif
}
diff --git a/src/server/scripts/Maelstrom/CMakeLists.txt b/src/server/scripts/Maelstrom/CMakeLists.txt
index 79f0789fd3f..8d3f1ee1c69 100644
--- a/src/server/scripts/Maelstrom/CMakeLists.txt
+++ b/src/server/scripts/Maelstrom/CMakeLists.txt
@@ -9,6 +9,13 @@
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
Maelstrom/kezan.cpp
+ Maelstrom/Stonecore/instance_stonecore.cpp
+ Maelstrom/Stonecore/stonecore.cpp
+ Maelstrom/Stonecore/stonecore.h
+ Maelstrom/Stonecore/boss_corborus.cpp
+ Maelstrom/Stonecore/boss_slabhide.cpp
+ Maelstrom/Stonecore/boss_ozruk.cpp
+ Maelstrom/Stonecore/boss_high_priestess_azil.cpp
)
message(" -> Prepared: The Maelstrom")
diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp
new file mode 100644
index 00000000000..2d522928fce
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "CreatureGroups.h"
+#include "stonecore.h"
+
+// TO-DO:
+// Find heroic sniffs and script spawning Crystal Shards on heroic mode.
+
+enum Spells
+{
+ // Corborus intro
+ SPELL_TWILIGHT_DOCUMENTS = 93167,
+ SPELL_RING_WYRM_CHARGE = 81237,
+ SPELL_DOOR_BREAK = 81232, // cast by World Trigger 22515
+
+ // Corborus boss
+ SPELL_DAMPENING_WAVE = 82415,
+ SPELL_CRYSTAL_BARRAGE = 86881, // 81638 triggers 81637
+// SPELL_CRYSTAL_BARRAGE_SHARD = 92012, // heroic only, summons Crystal Shard (TO-DO!)
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_SUBMERGE = 81629,
+ SPELL_TRASHING_CHARGE_TELEPORT = 81839, // triggers 81864
+// SPELL_TRASHING_CHARGE_TELEPORT_2= 81838, // dummy, targets all players, threat update packet follows
+ SPELL_SUMMON_TRASHING_CHARGE = 81816,
+ SPELL_TRASHING_CHARGE_VISUAL = 81801, // cast time 3.5 sec
+ SPELL_TRASHING_CHARGE_EFFECT = 81828, // 40 yard radius
+ SPELL_EMERGE = 81948,
+
+ // Rock Borer npc (43917)
+ SPELL_ROCK_BORER_EMERGE = 82185,
+ SPELL_ROCK_BORE = 80028,
+};
+
+enum NPCs
+{
+ NPC_TRASHING_CHARGE = 43743,
+// NPC_CRYSTAL_SHARD = 49267, // 49473
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ // Corborus intro
+ EVENT_CORBORUS_CHARGE,
+ EVENT_CORBORUS_KNOCKBACK,
+ EVENT_CORBORUS_FACEPLAYERS,
+
+ // Corborus boss
+ EVENT_DAMPENING_WAVE,
+ EVENT_CRYSTAL_BARRAGE,
+ EVENT_SUBMERGE,
+ EVENT_TELEPORT,
+ EVENT_TRASHING_CHARGE,
+ EVENT_SUMMON_BEETLE,
+ EVENT_EMERGE,
+ EVENT_ATTACK,
+
+ // Rock Borer
+ EVENT_EMERGED,
+ EVENT_ROCK_BORE,
+};
+
+class boss_corborus : public CreatureScript
+{
+ public:
+ boss_corborus() : CreatureScript("boss_corborus") { }
+
+ struct boss_corborusAI : public BossAI
+ {
+ boss_corborusAI(Creature* creature) : BossAI(creature, DATA_CORBORUS)
+ {
+ stateIntro = NOT_STARTED;
+ }
+
+ void Reset() override
+ {
+ _Reset();
+ countTrashingCharge = 0;
+ events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000);
+ events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000);
+ events.ScheduleEvent(EVENT_SUBMERGE, 36000);
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_CORBORUS_INTRO: // Executes Corborus intro event
+ {
+ if (stateIntro != NOT_STARTED)
+ return;
+
+ stateIntro = IN_PROGRESS;
+
+ if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM)))
+ {
+ Millhouse->InterruptNonMeleeSpells(true);
+ Millhouse->RemoveAllAuras();
+ Millhouse->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
+ }
+
+ events.ScheduleEvent(EVENT_CORBORUS_CHARGE, 1000);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && stateIntro != IN_PROGRESS)
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_CORBORUS_CHARGE:
+ // Face Millhouse and other mobs
+ instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0);
+
+ // Open rock gate and cast visual from nearby worldtrigger
+ instance->HandleGameObject(instance->GetGuidData(GAMEOBJECT_CORBORUS_ROCKDOOR), true);
+ if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f))
+ worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true);
+
+ // Make Corborus charge
+ me->CastSpell(me, SPELL_RING_WYRM_CHARGE, true);
+
+ events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000);
+ break;
+ case EVENT_CORBORUS_KNOCKBACK:
+ // Spawn Twilight Documents (quest gameobject)
+ if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM)))
+ Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true);
+
+ // Knockback Millhouse and other mobs
+ instance->SetData(DATA_MILLHOUSE_EVENT_KNOCKBACK, 0);
+
+ events.ScheduleEvent(EVENT_CORBORUS_FACEPLAYERS, 2000);
+ break;
+ case EVENT_CORBORUS_FACEPLAYERS:
+ // Face Corborus to players and set new home position
+ me->SetFacingTo(3.176499f);
+ me->SetHomePosition(1154.55f, 878.843f, 284.963f, 3.176499f);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+
+ // Despawn Millhouse and all trash
+ instance->SetData(DATA_MILLHOUSE_EVENT_DESPAWN, 0);
+
+ stateIntro = DONE;
+ break;
+ case EVENT_DAMPENING_WAVE:
+ DoCastVictim(SPELL_DAMPENING_WAVE);
+ events.ScheduleEvent(EVENT_DAMPENING_WAVE, 15000);
+ break;
+ case EVENT_CRYSTAL_BARRAGE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CRYSTAL_BARRAGE);
+ events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 10000);
+ break;
+ case EVENT_SUBMERGE:
+ events.RescheduleEvent(EVENT_DAMPENING_WAVE, 35000);
+ events.RescheduleEvent(EVENT_CRYSTAL_BARRAGE, 30000);
+ events.RescheduleEvent(EVENT_SUBMERGE, 100000);
+
+ me->SetReactState(REACT_PASSIVE);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
+ me->AttackStop();
+
+ DoCast(me, SPELL_SUBMERGE);
+
+ countTrashingCharge = 0;
+ events.ScheduleEvent(EVENT_TELEPORT, 500);
+ break;
+ case EVENT_TELEPORT:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_TRASHING_CHARGE_TELEPORT);
+ countTrashingCharge += 1;
+ if (countTrashingCharge <= 4)
+ events.ScheduleEvent(EVENT_TRASHING_CHARGE, 1000);
+ else
+ events.ScheduleEvent(EVENT_EMERGE, 2500);
+ break;
+ case EVENT_TRASHING_CHARGE:
+ DoCast(me, SPELL_SUMMON_TRASHING_CHARGE);
+ DoCast(me, SPELL_TRASHING_CHARGE_VISUAL);
+ events.ScheduleEvent(EVENT_TELEPORT, 5000);
+ break;
+ case EVENT_EMERGE:
+ me->RemoveAllAuras();
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ DoCast(me, SPELL_EMERGE);
+ events.ScheduleEvent(EVENT_ATTACK, 2500);
+ break;
+ case EVENT_ATTACK:
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() != NPC_TRASHING_CHARGE)
+ return;
+
+ summon->SetReactState(REACT_PASSIVE);
+ summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT);
+ summon->DespawnOrUnsummon(6000);
+ }
+
+ private:
+ EncounterState stateIntro;
+ uint32 countTrashingCharge;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_corborusAI>(creature);
+ }
+};
+
+// 43391 - Rock Borer
+class npc_rock_borer : public CreatureScript
+{
+ public:
+ npc_rock_borer() : CreatureScript("npc_rock_borer") { }
+
+ struct npc_rock_borerAI : public ScriptedAI
+ {
+ npc_rock_borerAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ me->SetReactState(REACT_PASSIVE);
+ events.ScheduleEvent(EVENT_EMERGED, 1200);
+ events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
+ }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ me->SetInCombatState(false, summoner);
+ DoCast(SPELL_ROCK_BORER_EMERGE);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && me->GetReactState() != REACT_PASSIVE)
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_EMERGED:
+ me->RemoveAurasDueToSpell(SPELL_ROCK_BORER_EMERGE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ case EVENT_ROCK_BORE:
+ DoCast(SPELL_ROCK_BORE);
+ events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_rock_borerAI>(creature);
+ }
+};
+
+void AddSC_boss_corborus()
+{
+ new boss_corborus();
+ new npc_rock_borer();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp
new file mode 100644
index 00000000000..fc14bf7a703
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "Vehicle.h"
+#include "stonecore.h"
+
+enum Spells
+{
+ SPELL_ENERGY_SHIELD = 82858,
+
+ SPELL_CURSE_OF_BLOOD = 79345,
+ SPELL_FORCE_GRIP = 79351,
+ SPELL_SUMMON_GRAVITY_WELL = 79340,
+ SPELL_EARTH_FURY_ENERGY_SHIELD = 79050,
+
+ // Gravity Well
+ SPELL_GRAVITY_WELL_VISUAL = 79245,
+ SPELL_GRAVITY_WELL_AURA_DAMAGE = 79244,
+ SPELL_GRAVITY_WELL_AURA_PULL = 79333,
+
+ SPELL_GRAVITY_WELL_DAMAGE = 79249,
+ SPELL_GRAVITY_WELL_PULL = 79332,
+
+ // Fury of Earth phase
+ SPELL_EARTH_FURY_CASTING_VISUAL = 79002,
+ SPELL_SEISMIC_SHARD_SUMMON_1 = 86860,
+ SPELL_SEISMIC_SHARD_SUMMON_2 = 86858,
+ SPELL_SEISMIC_SHARD_SUMMON_3 = 86856,
+ SPELL_SEISMIC_SHARD_VISUAL = 79009,
+ SPELL_SEISMIC_SHARD_PREPARE = 86862,
+ SPELL_SEISMIC_SHARD_TARGETING = 80511,
+ SPELL_SEISMIC_SHARD_LAUNCH = 79015,
+ SPELL_SEISMIC_SHARD_MISSLE = 79014,
+ SPELL_EJECT_ALL_PASSENGERS = 68576,
+
+ // Add wave spells
+ SPELL_SUMMON_WAVE_SOUTH = 79200,
+ SPELL_SUMMON_WAVE_WEST = 79196,
+ SPELL_SUMMON_ADD_SOUTH = 79193,
+ SPELL_SUMMON_ADD_WEST = 79199,
+};
+
+enum NPCs
+{
+ NPC_DEVOUT_FOLLOWER = 42428,
+ NPC_SEISMIC_SHARD = 42355,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_PHASE_TWO = 1,
+ SAY_DEATH = 2,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ EVENT_INTRO_MOVE,
+
+ EVENT_CURSE_OF_BLOOD,
+ EVENT_FORCE_GRIP,
+ EVENT_SUMMON_GRAVITY_WELL,
+ EVENT_ENERGY_SHIELD,
+ EVENT_EARTH_FURY,
+
+ EVENT_SUMMON_WAVE_SOUTH,
+ EVENT_SUMMON_WAVE_WEST,
+
+ EVENT_GRAVITY_WELL_AURA_DAMAGE,
+ EVENT_GRAVITY_WELL_AURA_PULL,
+
+ // Phase 2: Fury of Earth
+ EVENT_EARTH_FURY_FLY_UP,
+ EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM,
+ EVENT_EARTH_FURY_CHECK_SEAT0,
+ EVENT_EARTH_FURY_LAUNCH_SHARD,
+ EVENT_EARTH_FURY_FLY_DOWN,
+ EVENT_START_ATTACK,
+
+ EVENT_LAUNCH,
+ EVENT_SEISMIC_SHARD_MOUNT
+};
+
+enum EventGroups
+{
+ EVENT_GROUP_PHASE_ONE,
+ EVENT_GROUP_ADDS,
+};
+
+enum Points
+{
+ POINT_NONE,
+
+ POINT_INTRO_MOVE,
+ POINT_FLY_UP,
+ POINT_ABOVE_PLATFORM,
+ POINT_PLATFORM,
+ POINT_GROUND,
+};
+
+Position const GroundPos = { 1331.82f, 980.314f, 207.542f };
+Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f };
+
+// TO-DO:
+// - Find out why NPCs summoned by boss are usually two times bigger than their normal size.
+// - Find more sniffs and script Force Grip spell (79351)
+
+class boss_high_priestess_azil : public CreatureScript
+{
+ public:
+ boss_high_priestess_azil() : CreatureScript("boss_high_priestess_azil") { }
+
+ struct boss_high_priestess_azilAI : public BossAI
+ {
+ boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL), vehicle(creature->GetVehicleKit())
+ {
+ ASSERT(vehicle);
+ }
+
+ Vehicle* vehicle;
+
+ void Reset() override
+ {
+ _Reset();
+
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->SetReactState(REACT_PASSIVE);
+
+ events.ScheduleEvent(EVENT_INTRO_MOVE, 2000);
+ events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE);
+ events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000), EVENT_GROUP_PHASE_ONE);
+ events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE);
+ events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000));
+ events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0);
+ events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000);
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _EnterCombat();
+
+ DoCast(SPELL_ENERGY_SHIELD);
+ Talk(SAY_AGGRO);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ me->Say(SAY_DEATH);
+ }
+
+ /*
+ void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
+ {
+ if (!apply || who->GetEntry() != NPC_SEISMIC_SHARD)
+ return;
+
+ Movement::MoveSplineInit init(who);
+ init.DisableTransportPathTransformations();
+ if (seatId == 0)
+ init.MoveTo(12.13748f, 0.0f, 2.442475f);
+ else if (seatId == 1)
+ init.MoveTo(12.13748f, 17.5f, 11.19248f);
+ else
+ init.MoveTo(12.13748f, -17.5f, 11.19248f);
+ init.Launch();
+ }
+ */
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE && id != POINT_INTRO_MOVE)
+ return;
+
+ switch (id)
+ {
+ case POINT_INTRO_MOVE:
+ me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ case POINT_FLY_UP:
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ events.ScheduleEvent(EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, 1000);
+ break;
+ case POINT_ABOVE_PLATFORM:
+ me->SetFacingTo(5.218534f);
+ DoCast(SPELL_EARTH_FURY_CASTING_VISUAL);
+ DoCast(SPELL_SEISMIC_SHARD_SUMMON_1);
+ DoCast(SPELL_SEISMIC_SHARD_SUMMON_2);
+ DoCast(SPELL_SEISMIC_SHARD_SUMMON_3);
+ events.ScheduleEvent(EVENT_EARTH_FURY_CHECK_SEAT0, 6700);
+ break;
+ case POINT_GROUND:
+ DoCast(SPELL_EJECT_ALL_PASSENGERS);
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ // Find more sniffs to correct these timers, this was copied from Reset() void.
+ events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE);
+ events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000), EVENT_GROUP_PHASE_ONE);
+ events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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_INTRO_MOVE:
+ me->GetMotionMaster()->MoveJump(GroundPos, me->GetSpeed(MOVE_FLIGHT), 1.918408f, POINT_INTRO_MOVE);
+ break;
+ case EVENT_CURSE_OF_BLOOD:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CURSE_OF_BLOOD);
+ events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
+ break;
+ case EVENT_FORCE_GRIP:
+ DoCastVictim(SPELL_FORCE_GRIP);
+ events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
+ break;
+ case EVENT_SUMMON_GRAVITY_WELL:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_SUMMON_GRAVITY_WELL);
+ events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000), EVENT_GROUP_PHASE_ONE);
+ break;
+ case EVENT_ENERGY_SHIELD:
+ events.CancelEventGroup(EVENT_GROUP_PHASE_ONE);
+ DoCast(SPELL_EARTH_FURY_ENERGY_SHIELD);
+ events.ScheduleEvent(EVENT_EARTH_FURY, 0);
+ break;
+ case EVENT_EARTH_FURY:
+ countSeismicShard = 3;
+ me->SetReactState(REACT_PASSIVE);
+ me->SetFacingTo(5.862942f);
+ events.ScheduleEvent(EVENT_EARTH_FURY_FLY_UP, 1600);
+ break;
+ case EVENT_EARTH_FURY_FLY_UP:
+ Talk(SAY_PHASE_TWO);
+ me->GetMotionMaster()->MovePoint(POINT_FLY_UP, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5);
+ break;
+ case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM:
+ me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos);
+ break;
+ case EVENT_EARTH_FURY_CHECK_SEAT0:
+ if (!vehicle->GetPassenger(0))
+ DoCast(SPELL_SEISMIC_SHARD_PREPARE);
+ events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800);
+ break;
+ case EVENT_EARTH_FURY_LAUNCH_SHARD:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ {
+ me->SetFacingToObject(target);
+ DoCast(target, SPELL_SEISMIC_SHARD_TARGETING);
+ DoCast(SPELL_SEISMIC_SHARD_LAUNCH);
+ countSeismicShard -= 1;
+ }
+ events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_CHECK_SEAT0 : EVENT_EARTH_FURY_FLY_DOWN, 4800);
+ break;
+ case EVENT_EARTH_FURY_FLY_DOWN:
+ {
+ me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL);
+ me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD);
+ Position pos = me->GetPosition();
+ pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
+ me->GetMotionMaster()->MovePoint(POINT_GROUND, pos);
+ break;
+ }
+ case EVENT_SUMMON_WAVE_SOUTH:
+ if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
+ worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_SOUTH);
+ events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 12000);
+ break;
+ case EVENT_SUMMON_WAVE_WEST:
+ if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
+ worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_WEST);
+ events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 20000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ uint8 countSeismicShard;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_high_priestess_azilAI>(creature);
+ }
+};
+
+// 42428 - Devout Follower
+class npc_devout_follower : public CreatureScript
+{
+public:
+ npc_devout_follower() : CreatureScript("npc_devout_follower") { }
+
+ struct npc_devout_followerAI : public ScriptedAI
+ {
+ npc_devout_followerAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ if (summoner->GetEntry() != NPC_WORLDTRIGGER)
+ return;
+
+ if (Unit* target = me->SelectNearestPlayer(200.0f))
+ {
+ me->AddThreat(target, 0.0f);
+ me->SetInCombatWith(target);
+ target->SetInCombatWith(me);
+ DoStartMovement(target);
+ me->Attack(target, true);
+ }
+ else
+ me->GetMotionMaster()->MovePoint(POINT_NONE, summoner->GetPosition());
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_devout_followerAI>(creature);
+ }
+};
+
+// 42499 - Gravity Well
+class npc_gravity_well : public CreatureScript
+{
+public:
+ npc_gravity_well() : CreatureScript("npc_gravity_well") { }
+
+ struct npc_gravity_wellAI : public ScriptedAI
+ {
+ npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ DoCast(SPELL_GRAVITY_WELL_VISUAL);
+ events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200);
+ events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500);
+ if (!me->GetMap()->IsHeroic())
+ me->DespawnOrUnsummon(23200);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetEntry() != NPC_DEVOUT_FOLLOWER)
+ return;
+
+ me->SetObjectScale(me->GetObjectScale() - 0.25f);
+ if (me->GetObjectScale() <= 0.0f)
+ me->DespawnOrUnsummon(1000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_GRAVITY_WELL_AURA_DAMAGE:
+ me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL);
+ DoCast(SPELL_GRAVITY_WELL_AURA_DAMAGE);
+ break;
+ case EVENT_GRAVITY_WELL_AURA_PULL:
+ DoCast(SPELL_GRAVITY_WELL_AURA_PULL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_gravity_wellAI>(creature);
+ }
+};
+
+// 42355 - Seismic Shard
+class npc_seismic_shard : public CreatureScript
+{
+public:
+ npc_seismic_shard() : CreatureScript("npc_seismic_shard") { }
+
+ struct npc_seismic_shardAI : public ScriptedAI
+ {
+ npc_seismic_shardAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+ me->SetDisableGravity(true);
+ me->SetReactState(REACT_PASSIVE);
+ DoCast(SPELL_SEISMIC_SHARD_VISUAL);
+
+ Movement::MoveSplineInit init(me);
+ FillPath(me->GetPosition(), init.Path());
+ init.SetFly();
+ init.Launch();
+
+ events.ScheduleEvent(EVENT_SEISMIC_SHARD_MOUNT, 2400);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SEISMIC_SHARD_MOUNT:
+ if (Creature* highPriestAzil = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)))
+ if (Vehicle* vehicle = highPriestAzil->GetVehicleKit())
+ me->EnterVehicle(highPriestAzil, vehicle->GetNextEmptySeat(0, false)->first);
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ private:
+ void FillPath(Position const& pos, Movement::PointsArray& path)
+ {
+ G3D::Vector3 point;
+
+ point.x = pos.GetPositionX();
+ point.y = pos.GetPositionY();
+ point.z = pos.GetPositionZ();
+
+ point.x -= 1.0f;
+ path.push_back(point);
+
+ point.x += 1.0f;
+ path.push_back(point);
+
+ point.z += 25.0f;
+ path.push_back(point);
+
+ path.push_back(point);
+ }
+
+ InstanceScript* instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_seismic_shardAI>(creature);
+ }
+};
+
+// 79200 - Summon Follower
+class spell_summon_wave_south : public SpellScriptLoader
+{
+public:
+ spell_summon_wave_south() : SpellScriptLoader("spell_summon_wave_south") { }
+
+ class spell_summon_wave_south_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_summon_wave_south_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_SOUTH))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ for (uint8 i = 0; i < 3; i++)
+ GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_SOUTH, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_summon_wave_south_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_summon_wave_south_SpellScript();
+ }
+};
+
+// 79196 - Summon Follower
+class spell_summon_wave_west : public SpellScriptLoader
+{
+public:
+ spell_summon_wave_west() : SpellScriptLoader("spell_summon_wave_west") { }
+
+ class spell_summon_wave_west_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_summon_wave_west_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_WEST))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ for (uint8 i = 0; i < 10; i++)
+ GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_WEST, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_summon_wave_west_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_summon_wave_west_SpellScript();
+ }
+};
+
+// 79251 - Gravity Well (casts damage spell on units within 10 yards)
+class PlayerPetOrDevoutFollowerCheck
+{
+public:
+ bool operator()(WorldObject* object) const
+ {
+ // Valid targets are players, pets and Devout Followers
+ if (Creature* creature = object->ToCreature())
+ return (!creature->ToPet() && object->GetEntry() != NPC_DEVOUT_FOLLOWER);
+ return (!object->ToPlayer());
+ }
+};
+
+class spell_gravity_well_damage_nearby : public SpellScriptLoader
+{
+public:
+ spell_gravity_well_damage_nearby() : SpellScriptLoader("spell_gravity_well_damage_nearby") { }
+
+ class spell_gravity_well_damage_nearby_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gravity_well_damage_nearby_SpellScript);
+
+ void SetRadiusMod()
+ {
+ GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
+ }
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ unitList.remove_if(PlayerPetOrDevoutFollowerCheck());
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_GRAVITY_WELL_DAMAGE, true);
+ }
+
+ void Register() override
+ {
+ BeforeCast += SpellCastFn(spell_gravity_well_damage_nearby_SpellScript::SetRadiusMod);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_damage_nearby_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_nearby_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gravity_well_damage_nearby_SpellScript();
+ }
+};
+
+// 79249 - Gravity Well (damage)
+class spell_gravity_well_damage : public SpellScriptLoader
+{
+public:
+ spell_gravity_well_damage() : SpellScriptLoader("spell_gravity_well_damage") { }
+
+ class spell_gravity_well_damage_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gravity_well_damage_SpellScript);
+
+ void CalculateDamage(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ if (!target)
+ return;
+
+ float distance = GetCaster()->GetDistance2d(target);
+
+ if (target->GetEntry() == NPC_DEVOUT_FOLLOWER)
+ SetHitDamage(int32(200000 - (1000 * distance))); //need more research on this formula, damage values from sniffs: 189264, 190318, 190478, 196134, 197672, 199735
+ else
+ SetHitDamage(int32(4000 - (200 * distance)));
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_SpellScript::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gravity_well_damage_SpellScript();
+ }
+};
+
+// 79332 - Gravity Well (pull units within 10 yards)
+class PulledRecentlyCheck
+{
+public:
+ bool operator()(WorldObject* object) const
+ {
+ return (object->ToUnit() && object->ToUnit()->HasAura(SPELL_GRAVITY_WELL_PULL));
+ }
+};
+
+class spell_gravity_well_pull : public SpellScriptLoader
+{
+public:
+ spell_gravity_well_pull() : SpellScriptLoader("spell_gravity_well_pull") { }
+
+ class spell_gravity_well_pull_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gravity_well_pull_SpellScript);
+
+ void SetRadiusMod()
+ {
+ GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3));
+ }
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ unitList.remove_if(PulledRecentlyCheck());
+ }
+
+ void Register() override
+ {
+ BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_pull_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_gravity_well_pull_SpellScript();
+ }
+};
+
+// 86862 - Seismic Shard (forces target to cast 86863)
+class spell_seismic_shard_prepare : public SpellScriptLoader
+{
+public:
+ spell_seismic_shard_prepare() : SpellScriptLoader("spell_seismic_shard_prepare") { }
+
+ class spell_seismic_shard_prepare_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_seismic_shard_prepare_SpellScript);
+
+ void SetTarget(WorldObject*& target)
+ {
+ target = GetCaster()->FindNearestCreature(NPC_SEISMIC_SHARD, 50.0f);
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_prepare_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_seismic_shard_prepare_SpellScript();
+ }
+};
+
+// 86863 - Seismic Shard (moves shard to seat 0)
+class spell_seismic_shard_change_seat : public SpellScriptLoader
+{
+public:
+ spell_seismic_shard_change_seat() : SpellScriptLoader("spell_seismic_shard_change_seat") { }
+
+ class spell_seismic_shard_change_seat_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript);
+
+ void SetTarget(WorldObject*& target)
+ {
+ if (InstanceScript* instance = GetCaster()->GetInstanceScript())
+ target = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL));
+ }
+
+ void ChangeSeat(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->ExitVehicle();
+ if (GetHitUnit()->IsVehicle())
+ GetCaster()->EnterVehicle(GetHitUnit(), 0);
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_change_seat_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_change_seat_SpellScript::ChangeSeat, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_seismic_shard_change_seat_SpellScript();
+ }
+};
+
+// 79015 - Seismic Shard (launches shard)
+class spell_seismic_shard : public SpellScriptLoader
+{
+public:
+ spell_seismic_shard() : SpellScriptLoader("spell_seismic_shard") { }
+
+ class spell_seismic_shard_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_seismic_shard_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Creature* target = GetHitUnit()->ToCreature();
+ if (!target)
+ return;
+
+ target->ExitVehicle();
+ DynamicObject* dynamicObject = GetCaster()->GetDynObject(SPELL_SEISMIC_SHARD_TARGETING);
+ target->CastSpell(dynamicObject->GetPositionX(), dynamicObject->GetPositionY(), dynamicObject->GetPositionZ(), SPELL_SEISMIC_SHARD_MISSLE, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_seismic_shard_SpellScript();
+ }
+};
+
+void AddSC_boss_high_priestess_azil()
+{
+ new boss_high_priestess_azil();
+ new npc_devout_follower();
+ new npc_gravity_well();
+ new npc_seismic_shard();
+ new spell_summon_wave_south();
+ new spell_summon_wave_west();
+ new spell_gravity_well_damage_nearby();
+ new spell_gravity_well_damage();
+ new spell_gravity_well_pull();
+ new spell_seismic_shard_prepare();
+ new spell_seismic_shard_change_seat();
+ new spell_seismic_shard();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp
new file mode 100644
index 00000000000..92c9bba4bc1
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "Vehicle.h"
+#include "stonecore.h"
+
+enum Spells
+{
+ SPELL_ELEMENTIUM_BULWARK = 78939,
+ SPELL_GROUND_SLAM = 78903,
+ SPELL_ELEMENTIUM_SPIKE_SHIELD = 78835,
+ SPELL_SHATTER = 78807,
+ SPELL_ENRAGE = 80467,
+
+ // Rupture Controller and Rupture
+ SPELL_RUPTURE = 92393,
+// SPELL_RUPTURE_SUMMON_CENTER? = 95669, // summons rupture 8 yards front
+// SPELL_RUPTURE_SUMMON_LEFT? = 95348, // summons rupture 3 yards left?
+// SPELL_RUPTURE_SUMMON_RIGHT? = 92383, // summons rupture 3 yards right?
+ SPELL_RUPTURE_DAMAGE = 92381,
+};
+
+enum NPCs
+{
+ NPC_BOUNCER_SPIKE = 42189,
+ NPC_RUPTURE_CONTROLLER = 49597,
+ NPC_RUPTURE = 49576,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_ELEMENTIUM_BULWARK = 1,
+ SAY_ELEMENTIUM_SPIKE_SHIELD = 2,
+ SAY_ENRAGE = 3,
+ SAY_DEATH = 4,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ EVENT_ELEMENTIUM_BULWARK,
+ EVENT_GROUND_SLAM,
+ EVENT_ELEMENTIUM_SPIKE_SHIELD,
+ EVENT_SHATTER,
+ EVENT_ENRAGE,
+
+ EVENT_START_ATTACK,
+};
+
+// TO-DO:
+// - Find heroic sniffs and spawn Ruptures using spells commented above.
+// - Make Bouncer Spikes enter ozruk without jump animation.
+
+class boss_ozruk : public CreatureScript
+{
+ public:
+ boss_ozruk() : CreatureScript("boss_ozruk") { }
+
+ struct boss_ozrukAI : public BossAI
+ {
+ boss_ozrukAI(Creature* creature) : BossAI(creature, DATA_OZRUK) { }
+
+ void Reset() override
+ {
+ _Reset();
+
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000);
+ events.ScheduleEvent(EVENT_GROUND_SLAM, 10000);
+ events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000);
+
+ RemoveBouncerSpikes();
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _EnterCombat();
+
+ Talk(SAY_AGGRO);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() != NPC_RUPTURE_CONTROLLER)
+ return;
+
+ summon->SetReactState(REACT_PASSIVE);
+ summon->CastSpell(summon, SPELL_RUPTURE, true);
+ summon->DespawnOrUnsummon(10000);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
+ {
+ if (!me->HealthBelowPctDamaged(25, damage) || me->HasAura(SPELL_ENRAGE))
+ return;
+
+ DoCast(me, SPELL_ENRAGE);
+ me->Say(SAY_ENRAGE);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ me->Say(SAY_DEATH, killer); // receiver is the killer, sniff source!
+
+ RemoveBouncerSpikes();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_ELEMENTIUM_SPIKE_SHIELD))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_ELEMENTIUM_BULWARK:
+ DoCast(me, SPELL_ELEMENTIUM_BULWARK);
+ Talk(SAY_ELEMENTIUM_BULWARK);
+ break;
+ case EVENT_GROUND_SLAM:
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ DoCast(me, SPELL_GROUND_SLAM);
+ events.ScheduleEvent(EVENT_START_ATTACK, 4600);
+ break;
+ case EVENT_ELEMENTIUM_SPIKE_SHIELD:
+ DoCast(me, SPELL_ELEMENTIUM_SPIKE_SHIELD);
+ Talk(SAY_ELEMENTIUM_SPIKE_SHIELD);
+ events.ScheduleEvent(EVENT_SHATTER, 10000);
+ break;
+ case EVENT_SHATTER:
+ RemoveBouncerSpikes();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ DoCast(me, SPELL_SHATTER);
+ events.ScheduleEvent(EVENT_START_ATTACK, 4600);
+ // Spells are cast in same order everytime after Shatter, so we schedule them here
+ events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, urand(3000,4000));
+ events.ScheduleEvent(EVENT_GROUND_SLAM, urand(7000,9000));
+ events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, urand(10000,12000));
+ break;
+ case EVENT_START_ATTACK:
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void RemoveBouncerSpikes()
+ {
+ Vehicle* vehicle = me->GetVehicleKit();
+ if (!vehicle)
+ return;
+
+ for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++)
+ if (Unit* passenger = vehicle->GetPassenger(i))
+ if (Creature* creature = passenger->ToCreature())
+ creature->RemoveFromWorld();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_ozrukAI>(creature);
+ }
+};
+
+// 92393 - Rupture
+class spell_rupture : public SpellScriptLoader
+{
+public:
+ spell_rupture() : SpellScriptLoader("spell_rupture") { }
+
+ class spell_rupture_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rupture_AuraScript);
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ Unit* caster = GetCaster();
+
+ float dist = aurEff->GetTickNumber() * 8.0f;
+
+ // probably hack, should use spells (see Spells enum above)
+ Position pos = caster->GetNearPosition(dist, 0.0f);
+ SummonRupture(caster, pos);
+
+ pos = caster->GetNearPosition(dist, 0.2f);
+ SummonRupture(caster, pos);
+
+ pos = caster->GetNearPosition(dist, -0.2f);
+ SummonRupture(caster, pos);
+ }
+
+ void SummonRupture(Unit* caster, Position pos)
+ {
+ Creature* rupture = caster->SummonCreature(NPC_RUPTURE, pos, TEMPSUMMON_TIMED_DESPAWN, 2500);
+ if (!rupture)
+ return;
+
+ rupture->SetReactState(REACT_PASSIVE);
+ rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true);
+ }
+
+ void Register()
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_rupture_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_rupture_AuraScript();
+ }
+};
+
+// 78835 - Elementium Spike Shield
+class spell_elementium_spike_shield : public SpellScriptLoader
+{
+public:
+ spell_elementium_spike_shield() : SpellScriptLoader("spell_elementium_spike_shield") { }
+
+ class spell_elementium_spike_shield_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_elementium_spike_shield_SpellScript);
+
+ void HandleBouncerSpikes()
+ {
+ Unit* caster = GetCaster();
+ Vehicle* vehicle = caster->GetVehicleKit();
+ if (!vehicle)
+ return;
+
+ for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++)
+ if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000))
+ summon->EnterVehicle(caster, i);
+ }
+
+ void Register() override
+ {
+ OnCast += SpellCastFn(spell_elementium_spike_shield_SpellScript::HandleBouncerSpikes);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_elementium_spike_shield_SpellScript();
+ }
+};
+
+void AddSC_boss_ozruk()
+{
+ new boss_ozruk();
+ new spell_rupture();
+ new spell_elementium_spike_shield();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
new file mode 100644
index 00000000000..6827312deef
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "stonecore.h"
+
+enum Spells
+{
+ SPELL_FACE_RANDOM_PLAYER = 82530,
+
+ // Stalactite Trigger - Trash, On Ground
+ SPELL_STALACTITE_SUMMON_TRIGGER = 81028,
+
+ // Slabhide
+ SPELL_LAVA_FISSURE = 80803,
+ SPELL_SAND_BLAST = 80807,
+ SPELL_STALACTITE_SUMMON = 80656,
+// SPELL_COOLDOWN_5S = 95323, Cooldown: Creature Special 1 (5s)?
+ SPELL_CRYSTAL_STORM = 92305,
+ SPELL_CRYSTAL_STORM_TRIGGER = 92265,
+
+ // Lava Fissure
+ SPELL_LAVA_FISSURE_CRACK = 80798,
+ SPELL_LAVA_FISSURE_ERUPTION = 80800,
+
+ // Stalactite Trigger - Boss
+ SPELL_STALACTITE_SHADE = 80654,
+ SPELL_STALACTITE_MISSLE = 80643,
+ SPELL_STALACTITE_CREATE = 80647,
+};
+
+enum Entries
+{
+ NPC_LAVA_FISSURE = 43242,
+ NPC_STALACTITE_TRIGGER_GROUND = 43357,
+ NPC_STALACTITE_TRIGGER = 43159,
+ GO_STALACTITE = 204337,
+};
+
+enum Actions
+{
+ ACTION_STALACTITE_MISSLE,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ // Intro events
+ EVENT_ROAR_EMOTE,
+
+ // Slabhide combat
+ EVENT_HANDLE_ROCK_WALLS,
+ EVENT_LAVA_FISSURE,
+ EVENT_SAND_BLAST,
+ EVENT_AIR_PHASE,
+ EVENT_TAKEOFF,
+ EVENT_STALACTITE,
+ EVENT_LAND,
+ EVENT_ATTACK,
+
+ // Lava Fissure
+ EVENT_LAVA_FISSURE_ERUPTION,
+
+ // Stalactite Trigger - Boss
+ EVENT_STALACTITE_MISSLE,
+};
+
+enum MovementPoints
+{
+ POINT_NONE,
+
+ POINT_SLABHIDE_INTRO,
+ POINT_SLABHIDE_INTRO_LAND,
+
+ POINT_SLABHIDE_MIDDLE,
+ POINT_SLABHIDE_IN_AIR,
+ POINT_SLABHIDE_LAND,
+};
+
+Position const SlabhideIntroPos = { 1292.27f, 1226.16f, 265.573f };
+Position const SlabhideIntroLandPos = { 1292.352f, 1226.478f, 247.6368f, 3.630285f };
+
+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
+{
+ public:
+ boss_slabhide() : CreatureScript("boss_slabhide") { }
+
+ struct boss_slabhideAI : public BossAI
+ {
+ boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE)
+ {
+ me->setActive(true);
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ me->SetReactState(REACT_PASSIVE);
+ instance->SetData(DATA_SLABHIDE_INTRO, NOT_STARTED);
+ }
+
+ void Reset()
+ {
+ if (instance->GetData(DATA_SLABHIDE_INTRO) == NOT_STARTED)
+ return;
+
+ _Reset();
+ DespawnAll();
+
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _EnterCombat();
+
+ events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4000);
+ events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
+ events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
+ events.ScheduleEvent(EVENT_AIR_PHASE, 10000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+
+ // Despawn related npcs and gameobjects
+ DespawnAll();
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_SLABHIDE_INTRO:
+ {
+ if (instance->GetData(DATA_SLABHIDE_INTRO) != NOT_STARTED)
+ return;
+
+ instance->SetData(DATA_SLABHIDE_INTRO, IN_PROGRESS);
+
+ // Execute Slabhide intro event
+ me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos);
+ 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->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ me->SetHover(false);
+ me->SetHomePosition(SlabhideIntroLandPos);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ instance->SetData(DATA_SLABHIDE_INTRO, DONE);
+ break;
+ case POINT_SLABHIDE_MIDDLE:
+ events.ScheduleEvent(EVENT_TAKEOFF, 100);
+ break;
+ case POINT_SLABHIDE_IN_AIR:
+ events.ScheduleEvent(EVENT_STALACTITE, 400);
+ break;
+ case POINT_SLABHIDE_LAND:
+ //DoCast(SPELL_COOLDOWN_5S); // unknown purpose
+ events.ScheduleEvent(EVENT_ATTACK, 1200);
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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_HANDLE_ROCK_WALLS: // Close rock walls
+ instance->SetData(DATA_SLABHIDE_ROCK_WALL, false);
+ break;
+ case EVENT_LAVA_FISSURE:
+ DoCast(SPELL_LAVA_FISSURE);
+ events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
+ break;
+ case EVENT_SAND_BLAST:
+ DoCast(SPELL_SAND_BLAST);
+ events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000));
+ break;
+ case EVENT_AIR_PHASE:
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos);
+ events.ScheduleEvent(EVENT_AIR_PHASE, 60000);
+ break;
+ case EVENT_TAKEOFF:
+ me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos);
+ break;
+ case EVENT_STALACTITE:
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ me->SetHover(true);
+
+ DoCast(SPELL_STALACTITE_SUMMON);
+
+ events.ScheduleEvent(EVENT_LAND, 8000);
+ break;
+ case EVENT_LAND:
+ {
+ Position pos = me->GetPosition();
+ pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
+ me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos);
+ break;
+ }
+ case EVENT_ATTACK:
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ me->SetHover(false);
+
+ events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000));
+ events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000));
+ DoCast(SPELL_CRYSTAL_STORM);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ void DespawnAll()
+ {
+ // Despawn stalactite triggers npcs
+ std::list<Creature*> listStalactiteTrigger;
+ me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f);
+ if (!listStalactiteTrigger.empty())
+ for (std::list<Creature*>::const_iterator itr = listStalactiteTrigger.begin(); itr != listStalactiteTrigger.end(); ++itr)
+ (*itr)->DespawnOrUnsummon();
+
+ // Despawn stalactite objects
+ std::list<GameObject*> listStalactite;
+ me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f);
+ if (!listStalactite.empty())
+ for (std::list<GameObject*>::const_iterator itr = listStalactite.begin(); itr != listStalactite.end(); ++itr)
+ (*itr)->Delete();
+ }
+
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_slabhideAI>(creature);
+ }
+};
+
+// 43242 - Lava Fissure
+class npc_lava_fissure : public CreatureScript
+{
+public:
+ npc_lava_fissure() : CreatureScript("npc_lava_fissure") { }
+
+ struct npc_lava_fissureAI : public ScriptedAI
+ {
+ npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->CastSpell(me, SPELL_LAVA_FISSURE_CRACK, true);
+ events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000);
+ }
+
+ 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);
+ me->CastSpell(me, SPELL_LAVA_FISSURE_ERUPTION, true);
+ me->DespawnOrUnsummon(14000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_lava_fissureAI>(creature);
+ }
+};
+
+// 43159 - Stalactite Trigger - Boss
+class npc_stalactite_trigger : public CreatureScript
+{
+public:
+ npc_stalactite_trigger() : CreatureScript("npc_stalactite_trigger") { }
+
+ struct npc_stalactite_triggerAI : public ScriptedAI
+ {
+ npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->SetDisableGravity(true);
+ me->CastSpell(me, SPELL_STALACTITE_SHADE, true);
+ events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_STALACTITE_MISSLE:
+ DoCast(SPELL_STALACTITE_MISSLE);
+ me->DespawnOrUnsummon(11000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_stalactite_triggerAI>(creature);
+ }
+};
+
+// 81035 - Stalactite (check if player is near to summon stalactite)
+class NotPlayerCheck
+{
+ public:
+ bool operator()(WorldObject* object) const
+ {
+ return (object->GetTypeId() != TYPEID_PLAYER);
+ }
+};
+
+class spell_s81035_stalactite : public SpellScriptLoader
+{
+public:
+ spell_s81035_stalactite() : SpellScriptLoader("spell_s81035_stalactite") { }
+
+ class spell_s81035_stalactite_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_s81035_stalactite_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if(NotPlayerCheck());
+ }
+
+ void SummonStalactiteTrigger()
+ {
+ Unit* caster = GetCaster();
+ caster->CastSpell(caster, SPELL_STALACTITE_SUMMON_TRIGGER, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s81035_stalactite_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_s81035_stalactite_SpellScript();
+ }
+};
+
+// 81028 - Stalactite (summons "Stalactite Trigger - Boss", 20 yard radius)
+// 80650 - Stalactite (summons "Stalactite Trigger - Boss", 40 yard radius)
+class spell_s81028_s80650_stalactite : public SpellScriptLoader
+{
+public:
+ spell_s81028_s80650_stalactite() : SpellScriptLoader("spell_s81028_s80650_stalactite") { }
+
+ class spell_s81028_s80650_stalactite_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_s81028_s80650_stalactite_SpellScript);
+
+ void ModDestHeight(SpellDestination& dest)
+ {
+ // All stalactite triggers should have Z position 301.3837f, but no way to relocate (not relocateoffset!) height only.
+ Position offset = { 0.0f, 0.0f, 50.0f, 0.0f };
+ dest.RelocateOffset(offset);
+ }
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_s81028_s80650_stalactite_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_s81028_s80650_stalactite_SpellScript();
+ }
+};
+
+// 80654 - Stalactite (creates visual shade on ground)
+// 80643/92653 - Stalactite (launches missle to the ground)
+// 80647/92309 - Stalactite (creates stalactite object)
+class spell_stalactite_mod_dest_height : public SpellScriptLoader
+{
+public:
+ spell_stalactite_mod_dest_height() : SpellScriptLoader("spell_stalactite_mod_dest_height") { }
+
+ class spell_stalactite_mod_dest_height_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_stalactite_mod_dest_height_SpellScript);
+
+ void ModDestHeight(SpellDestination& dest)
+ {
+ Unit* caster = GetCaster();
+ Position pos = caster->GetPosition();
+ pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f);
+ dest.Relocate(pos);
+ }
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_stalactite_mod_dest_height_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_stalactite_mod_dest_height_SpellScript();
+ }
+};
+
+// 92306 - Crystal storm (heroic mode check)
+class spell_s92306_crystal_storm : public SpellScriptLoader
+{
+public:
+ spell_s92306_crystal_storm() : SpellScriptLoader("spell_s92306_crystal_storm") { }
+
+ class spell_s92306_crystal_storm_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_s92306_crystal_storm_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CRYSTAL_STORM_TRIGGER))
+ return false;
+ return true;
+ }
+
+ void HandleDummyEffect(SpellEffIndex /*eff*/)
+ {
+ Unit* caster = GetCaster();
+ if (caster->GetMap()->IsHeroic())
+ caster->CastSpell(caster, SPELL_CRYSTAL_STORM_TRIGGER, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_s92306_crystal_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_s92306_crystal_storm_SpellScript();
+ }
+};
+
+// 92300 - Crystal Storm (damage)
+class BehindObjectCheck
+{
+ public:
+ BehindObjectCheck(Unit* caster, std::list<GameObject*> objectList) : caster(caster), objectList(objectList) { }
+
+ bool operator()(WorldObject* unit)
+ {
+ for (std::list<GameObject*>::const_iterator itr = objectList.begin(); itr != objectList.end(); ++itr)
+ if (!(*itr)->IsInvisibleDueToDespawn() && (*itr)->IsInBetween(caster, unit, 1.5f))
+ return true;
+ return false;
+ }
+
+ private:
+ Unit* caster;
+ std::list<GameObject*> objectList;
+};
+
+class spell_s92300_crystal_storm : public SpellScriptLoader
+{
+public:
+ spell_s92300_crystal_storm() : SpellScriptLoader("spell_s92300_crystal_storm") { }
+
+ class spell_s92300_crystal_storm_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_s92300_crystal_storm_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ Unit* caster = GetCaster();
+
+ std::list<GameObject*> goList;
+ caster->GetGameObjectListWithEntryInGrid(goList, GO_STALACTITE, 40.0f);
+ if (goList.empty())
+ return;
+
+ unitList.remove_if(BehindObjectCheck(caster, goList));
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s92300_crystal_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_s92300_crystal_storm_SpellScript();
+ }
+};
+
+void AddSC_boss_slabhide()
+{
+ new boss_slabhide();
+ new npc_lava_fissure();
+ new npc_stalactite_trigger();
+ new spell_s81035_stalactite();
+ new spell_s81028_s80650_stalactite();
+ new spell_stalactite_mod_dest_height();
+ new spell_s92306_crystal_storm();
+ new spell_s92300_crystal_storm();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp
new file mode 100644
index 00000000000..8cb4df0622f
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp
@@ -0,0 +1,262 @@
+/*
+* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ScriptMgr.h"
+#include "Player.h"
+#include "CreatureGroups.h"
+#include "InstanceScript.h"
+#include "stonecore.h"
+
+#define MAX_ENCOUNTER 4
+
+/* Stonecore encounters:
+0 - Corborus
+1 - Slabhide
+2 - Ozruk
+3 - High Priestess Azil
+*/
+
+// TO-DO:
+// - Find out spell IDs for both Stonecore Teleporters (spellclick).
+
+class instance_stonecore : public InstanceMapScript
+{
+ public:
+ instance_stonecore() : InstanceMapScript(SCScriptName, 725) { }
+
+ struct instance_stonecore_InstanceScript : public InstanceScript
+ {
+ instance_stonecore_InstanceScript(Map* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(MAX_ENCOUNTER);
+ }
+
+ void OnGameObjectCreate(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GAMEOBJECT_CORBORUS_ROCKDOOR:
+ corborusRockDoorGUID = go->GetGUID();
+ go->SetGoState(GetBossState(DATA_CORBORUS) != DONE ? GO_STATE_READY : GO_STATE_ACTIVE);
+ break;
+ case GAMEOBJECT_SLABHIDE_ROCK_WALL:
+ slabhideRockWallGUIDs.push_back(go->GetGUID());
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnCreatureCreate(Creature* creature) override
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_MILLHOUSE_MANASTORM:
+ millhouseGUID = creature->GetGUID();
+ break;
+ case NPC_CORBORUS:
+ corobrusGUID = creature->GetGUID();
+ break;
+ case NPC_SLABHIDE:
+ slabhideGUID = creature->GetGUID();
+ break;
+ case NPC_HIGH_PRIESTESS_AZIL:
+ highPriestessAzilGUID = creature->GetGUID();
+ break;
+ case NPC_STONECORE_TELEPORTER:
+ case NPC_STONECORE_TELEPORTER_2:
+ if (GetBossState(DATA_SLABHIDE) != DONE)
+ stonecoreTeleporterGUID[creature->GetEntry() - NPC_STONECORE_TELEPORTER] = creature->GetGUID();
+ else // If Slabhide is already dead, no need to store teleporter guids
+ {
+ creature->CastSpell(creature, SPELL_TELEPORTER_ACTIVE_VISUAL, true);
+ creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Check if creature is part of Millhouse event
+ creature->SearchFormation();
+ if (CreatureGroup* group = creature->GetFormation()) // TO-DO: Fix formations
+ {
+ switch (group->GetId())
+ {
+ case CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH:
+ millhouseTrashGUIDs.push_back(creature->GetGUID());
+ break;
+ case CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP:
+ millhouseLastGroupGUIDs.push_back(creature->GetGUID());
+ creature->SetReactState(REACT_PASSIVE);
+ creature->SetMeleeAnimKitId(ANIM_READY2H);
+ break;
+ }
+ }
+ }
+
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ switch (type)
+ {
+ case DATA_SLABHIDE:
+ // Open rock walls (Slabhide AI handles closing because it must be delayed)
+ if (state != IN_PROGRESS)
+ SetData(DATA_SLABHIDE_ROCK_WALL, true);
+
+ // Activate teleporters
+ if (state == DONE)
+ {
+ for (int8 i = 0; i < MAX_STONECORE_TELEPORTERS; i++)
+ {
+ if (Creature* teleporter = GetCreature(stonecoreTeleporterGUID[i]))
+ {
+ teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true);
+ teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return InstanceScript::SetBossState(type, state);
+ }
+
+ uint32 GetData(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_SLABHIDE_INTRO:
+ return slabhideIntro;
+ default:
+ break;
+ }
+
+ return 0;
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
+ case DATA_MILLHOUSE_EVENT_FACE:
+ MillhouseEvent_Face();
+ break;
+ case DATA_MILLHOUSE_EVENT_KNOCKBACK:
+ MillhouseEvent_Knockback();
+ break;
+ case DATA_MILLHOUSE_EVENT_DESPAWN:
+ MillhouseEvent_Despawn();
+ break;
+ case DATA_SLABHIDE_INTRO:
+ slabhideIntro = EncounterState(data);
+ break;
+ case DATA_SLABHIDE_ROCK_WALL: // Handles rock walls
+ for (std::vector<ObjectGuid>::iterator itr = slabhideRockWallGUIDs.begin(); itr != slabhideRockWallGUIDs.end(); ++itr)
+ HandleGameObject((*itr), data ? true : false);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ObjectGuid GetGuidData(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_MILLHOUSE_MANASTORM:
+ return millhouseGUID;
+ case GAMEOBJECT_CORBORUS_ROCKDOOR:
+ return corborusRockDoorGUID;
+ case DATA_CORBORUS:
+ return corobrusGUID;
+ case DATA_SLABHIDE:
+ return slabhideGUID;
+ case DATA_HIGH_PRIESTESS_AZIL:
+ return highPriestessAzilGUID;
+ case NPC_STONECORE_TELEPORTER:
+ case NPC_STONECORE_TELEPORTER_2:
+ return stonecoreTeleporterGUID[type - NPC_STONECORE_TELEPORTER];
+ default:
+ break;
+ }
+
+ return ObjectGuid::Empty;
+ }
+
+ private:
+ // Face Millhouse and other nearby mobs to Corborus
+ void MillhouseEvent_Face()
+ {
+ if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
+ Millhouse->SetFacingTo(1.570796f);
+ for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i)
+ if (Creature* creature = instance->GetCreature(*i))
+ creature->SetFacingTo(1.570796f);
+ }
+
+ // Knock back Millhouse and other mobs
+ void MillhouseEvent_Knockback()
+ {
+ if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
+ Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true);
+ for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
+ if (Creature* creature = instance->GetCreature(*itr))
+ creature->CastSpell(creature, SPELL_RING_WYRM_KNOCKBACK, true);
+ }
+
+ // Despawn all mobs
+ void MillhouseEvent_Despawn()
+ {
+ if (Creature* Millhouse = instance->GetCreature(millhouseGUID))
+ Millhouse->DespawnOrUnsummon(3000);
+ for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr)
+ if (Creature* creature = instance->GetCreature(*itr))
+ creature->DespawnOrUnsummon(3000);
+ for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr)
+ if (Creature* creature = instance->GetCreature(*itr))
+ creature->DespawnOrUnsummon(3000);
+ }
+
+ ObjectGuid millhouseGUID;
+ GuidVector millhouseTrashGUIDs;
+ GuidVector millhouseLastGroupGUIDs;
+ ObjectGuid corborusRockDoorGUID;
+ ObjectGuid corobrusGUID;
+ ObjectGuid slabhideGUID;
+ ObjectGuid highPriestessAzilGUID;
+ ObjectGuid stonecoreTeleporterGUID[2];
+ GuidVector slabhideRockWallGUIDs;
+
+ EncounterState slabhideIntro;
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_stonecore_InstanceScript(map);
+ }
+};
+
+void AddSC_instance_stonecore()
+{
+ new instance_stonecore();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp
new file mode 100644
index 00000000000..2612cd02385
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ObjectGuid.h"
+#include "ObjectMgr.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "stonecore.h"
+
+enum Texts
+{
+ // Millhouse Manastorm
+ SAY_MILLHOUSE_EVENT_1 = 0,
+ SAY_MILLHOUSE_EVENT_2 = 1,
+};
+
+enum NPCs
+{
+ NPC_GENERIC_TRIGGER_LAB = 40350,
+};
+
+enum Spells
+{
+ // Millhouse Manastorm
+ SPELL_SHADOW_BOLT = 81439,
+ SPELL_FROSTBOLT_VOLLEY = 81440,
+ SPELL_SHADOWFURY = 81441,
+ SPELL_FEAR = 81442,
+// SPELL_MILLHOUSE_SAFE_CHECK = 81213, // unknown purpose
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_BLUR = 81216,
+ SPELL_ANCHOR_HERE = 45313,
+ SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND = 81220,
+ SPELL_IMPENDING_DOOM = 86838,
+ SPELL_IMPENDING_DOOM_CHANNEL = 86830,
+
+// SPELL_PORTAL_VISUAL = 79754,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ // Millhouse Manastorm
+ EVENT_FROSTBOLT_VOLLEY,
+ EVENT_SHADOWFURY,
+ EVENT_FEAR,
+
+ EVENT_READY_FOR_COMBAT,
+ EVENT_CAST_IMPENDING_DOOM,
+ EVENT_INTERRUPT_IMPENDING_DOOM,
+};
+
+enum Phase
+{
+ PHASE_NONE,
+
+ PHASE_MILLHOUSE_GROUP_1,
+ PHASE_MILLHOUSE_GROUP_2,
+ PHASE_MILLHOUSE_GROUP_3,
+ PHASE_MILLHOUSE_GROUP_4,
+
+ PHASE_MASK_MILLHOUSE_GROUP_1 = (1 << (PHASE_MILLHOUSE_GROUP_1 - 1)),
+ PHASE_MASK_MILLHOUSE_GROUP_2 = (1 << (PHASE_MILLHOUSE_GROUP_2 - 1)),
+ PHASE_MASK_MILLHOUSE_GROUP_3 = (1 << (PHASE_MILLHOUSE_GROUP_3 - 1)),
+ PHASE_MASK_MILLHOUSE_GROUP_4 = (1 << (PHASE_MILLHOUSE_GROUP_4 - 1)),
+};
+
+enum MovementPoints
+{
+ POINT_NONE,
+
+ POINT_MILLHOUSE_GROUP_2,
+ POINT_MILLHOUSE_GROUP_3,
+ POINT_MILLHOUSE_GROUP_4,
+};
+
+// Millhouse trash groups
+Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f };
+Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f };
+Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f };
+
+// 43391 - Millhouse Manastorm
+class npc_sc_millhouse_manastorm : public CreatureScript
+{
+ public:
+ npc_sc_millhouse_manastorm() : CreatureScript("npc_sc_millhouse_manastorm") { }
+
+ struct npc_sc_millhouse_manastormAI : public ScriptedAI
+ {
+ npc_sc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature),
+ _instance(creature->GetInstanceScript())
+ {
+ events.SetPhase(PHASE_MILLHOUSE_GROUP_1);
+ }
+
+ void ScheduleEvents()
+ {
+ events.ScheduleEvent(EVENT_SHADOWFURY, 3000);
+ events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5000);
+ events.ScheduleEvent(EVENT_FEAR, 8000);
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
+
+ if (!HealthBelowPct(50) || me->HasAura(SPELL_BLUR))
+ return;
+
+ switch (events.GetPhaseMask())
+ {
+ case PHASE_MASK_MILLHOUSE_GROUP_1:
+ events.Reset();
+ events.SetPhase(PHASE_MILLHOUSE_GROUP_2);
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
+ DoCast(me, SPELL_BLUR);
+ Talk(SAY_MILLHOUSE_EVENT_1);
+ me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_2, MillhousePointGroup2);
+ break;
+ case PHASE_MASK_MILLHOUSE_GROUP_2:
+ events.Reset();
+ events.SetPhase(PHASE_MILLHOUSE_GROUP_3);
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
+ DoCast(me, SPELL_BLUR);
+ Talk(SAY_MILLHOUSE_EVENT_1);
+ me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_3, MillhousePointGroup3);
+ break;
+ case PHASE_MASK_MILLHOUSE_GROUP_3:
+ events.Reset();
+ events.SetPhase(PHASE_MILLHOUSE_GROUP_4);
+ me->SetReactState(REACT_PASSIVE);
+ me->InterruptNonMeleeSpells(true);
+ DoCast(me, SPELL_CLEAR_ALL_DEBUFFS);
+ DoCast(me, SPELL_BLUR);
+ me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_4, MillhousePointGroup4);
+ break;
+ default:
+ break;
+ }
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (pointId < POINT_MILLHOUSE_GROUP_2 || pointId > POINT_MILLHOUSE_GROUP_4)
+ return;
+
+ me->RemoveAllAuras();
+ me->CombatStop(true);
+ me->DeleteThreatList();
+
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ switch (pointId)
+ {
+ case POINT_MILLHOUSE_GROUP_2:
+ if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f))
+ me->SetFacingToObject(worldtrigger); // o: 5.497359f (sniff data)
+ me->CastSpell(me, SPELL_ANCHOR_HERE, true);
+ me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me);
+ events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
+ break;
+ case POINT_MILLHOUSE_GROUP_3:
+ me->SetFacingTo(5.931499f);
+ me->CastSpell(me, SPELL_ANCHOR_HERE, true);
+ me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me);
+ events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000);
+ break;
+ case POINT_MILLHOUSE_GROUP_4:
+ me->SetFacingTo(3.455752f);
+ me->CastSpell(me, SPELL_ANCHOR_HERE, true);
+ Talk(SAY_MILLHOUSE_EVENT_2);
+ events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ // Only update events if Millhouse is aggressive
+ if (me->GetReactState() != REACT_AGGRESSIVE)
+ return;
+
+ events.Update(diff);
+
+ // Impending Doom is exception because it needs to be interrupted.
+ if (me->HasUnitState(UNIT_STATE_CASTING) && !me->GetCurrentSpell(SPELL_IMPENDING_DOOM))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_FROSTBOLT_VOLLEY:
+ DoCast(SPELL_FROSTBOLT_VOLLEY);
+ events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000);
+ break;
+ case EVENT_SHADOWFURY:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
+ DoCast(target, SPELL_SHADOWFURY);
+ events.ScheduleEvent(EVENT_SHADOWFURY, 7000);
+ break;
+ case EVENT_FEAR:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
+ DoCast(target, SPELL_FEAR);
+ events.ScheduleEvent(EVENT_FEAR, 18000);
+ break;
+ case EVENT_READY_FOR_COMBAT:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
+ me->SetReactState(REACT_AGGRESSIVE);
+ ScheduleEvents();
+ break;
+ case EVENT_CAST_IMPENDING_DOOM:
+ DoCast(SPELL_IMPENDING_DOOM);
+ DoCast(SPELL_IMPENDING_DOOM_CHANNEL);
+ events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000));
+ break;
+ case EVENT_INTERRUPT_IMPENDING_DOOM:
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAllAuras();
+ me->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN);
+ events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 3000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_SHADOW_BOLT);
+ }
+
+ private:
+ InstanceScript* _instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_sc_millhouse_manastormAI>(creature);
+ }
+};
+
+// 81459 - Force of Earth
+class spell_force_of_earth : public SpellScriptLoader
+{
+ public:
+ spell_force_of_earth() : SpellScriptLoader("spell_force_of_earth") { }
+
+ class spell_force_of_earth_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_force_of_earth_SpellScript);
+
+ void DummyEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->SetDisplayId(26693); // can be moved to SAI part, need sniffs to see what this dummy does (note: npc 43552)
+ }
+
+ void Register()
+ {
+ OnEffectLaunch += SpellEffectFn(spell_force_of_earth_SpellScript::DummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_force_of_earth_SpellScript();
+ }
+};
+
+// 45313 - Anchor Here
+class spell_sc_anchor_here : public SpellScriptLoader
+{
+public:
+ spell_sc_anchor_here() : SpellScriptLoader("spell_sc_anchor_here") { }
+
+ class spell_sc_anchor_here_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sc_anchor_here_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Creature* creature = GetHitUnit()->ToCreature())
+ creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_sc_anchor_here_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sc_anchor_here_SpellScript();
+ }
+};
+
+// 93167 - Twilight Documents
+class spell_sc_twilight_documents : public SpellScriptLoader
+{
+ public:
+ spell_sc_twilight_documents() : SpellScriptLoader("spell_sc_twilight_documents") { }
+
+ class spell_sc_twilight_documents_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sc_twilight_documents_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sObjectMgr->GetGameObjectTemplate(GAMEOBJECT_TWILIGHT_DOCUMENTS))
+ return false;
+ return true;
+ }
+
+ void SetTarget(WorldObject*& target)
+ {
+ target = GetCaster()->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 100.0f);
+ }
+
+ void SpawnGameObject(SpellEffIndex /*effIndex*/)
+ {
+ if (WorldLocation* loc = GetHitDest())
+ GetCaster()->SummonGameObject(GAMEOBJECT_TWILIGHT_DOCUMENTS, loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ(), loc->GetOrientation(), 0, 0, 0, 0, 7200);
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_sc_twilight_documents_SpellScript::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY);
+ OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sc_twilight_documents_SpellScript();
+ }
+};
+
+// 81008 - Quake
+class JumpCheck
+{
+ public:
+ bool operator()(WorldObject* object) const
+ {
+ Player* player = object->ToPlayer();
+ return (player && player->HasUnitState(UNIT_STATE_JUMPING));
+ }
+};
+
+class spell_sc_quake : public SpellScriptLoader
+{
+ public:
+ spell_sc_quake() : SpellScriptLoader("spell_sc_quake") { }
+
+ class spell_sc_quake_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sc_quake_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ unitList.remove_if(JumpCheck());
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sc_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sc_quake_SpellScript();
+ }
+};
+
+class at_sc_corborus_intro : public AreaTriggerScript
+{
+public:
+ at_sc_corborus_intro() : AreaTriggerScript("at_sc_corborus_intro") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* corborus = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CORBORUS)))
+ corborus->AI()->DoAction(ACTION_CORBORUS_INTRO);
+ return true;
+ }
+};
+
+class at_sc_slabhide_intro : public AreaTriggerScript
+{
+public:
+ at_sc_slabhide_intro() : AreaTriggerScript("at_sc_slabhide_intro") { }
+
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* slabhide = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SLABHIDE)))
+ slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO);
+ return true;
+ }
+};
+
+void AddSC_stonecore()
+{
+ new npc_sc_millhouse_manastorm();
+ new spell_force_of_earth();
+ new spell_sc_anchor_here();
+ new spell_sc_twilight_documents();
+ new spell_sc_quake();
+ new at_sc_corborus_intro();
+ new at_sc_slabhide_intro();
+}
diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.h b/src/server/scripts/Maelstrom/Stonecore/stonecore.h
new file mode 100644
index 00000000000..98a9878e0d3
--- /dev/null
+++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.h
@@ -0,0 +1,72 @@
+/*
+* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_STONECORE_H
+#define DEF_STONECORE_H
+
+#define SCScriptName "instance_stonecore"
+#define DataHeader "SC"
+
+enum DataTypes
+{
+ // Encounter States/Boss GUIDs
+ DATA_CORBORUS,
+ DATA_SLABHIDE,
+ DATA_OZRUK,
+ DATA_HIGH_PRIESTESS_AZIL,
+
+ // Additional Data
+ DATA_MILLHOUSE_MANASTORM,
+ DATA_MILLHOUSE_EVENT_FACE,
+ DATA_MILLHOUSE_EVENT_KNOCKBACK,
+ DATA_MILLHOUSE_EVENT_DESPAWN,
+
+ DATA_SLABHIDE_INTRO,
+ DATA_SLABHIDE_ROCK_WALL,
+};
+
+enum Misc
+{
+ ACTION_CORBORUS_INTRO,
+ ACTION_SLABHIDE_INTRO,
+
+ NPC_WORLDTRIGGER = 22515,
+ NPC_MILLHOUSE_MANASTORM = 43391,
+
+ NPC_CORBORUS = 43438,
+ NPC_SLABHIDE = 43214,
+ NPC_OZRUK = 42188,
+ NPC_HIGH_PRIESTESS_AZIL = 42333,
+
+ // Stonecore Teleporter misc
+ MAX_STONECORE_TELEPORTERS = 2,
+ NPC_STONECORE_TELEPORTER = 51396, // Entrance teleporter
+ NPC_STONECORE_TELEPORTER_2 = 51397, // Slabhide teleporter
+ SPELL_TELEPORTER_ACTIVE_VISUAL = 95298,
+
+ GAMEOBJECT_TWILIGHT_DOCUMENTS = 207415,
+ GAMEOBJECT_CORBORUS_ROCKDOOR = 207343,
+ GAMEOBJECT_SLABHIDE_ROCK_WALL = 204381,
+
+ SPELL_RING_WYRM_KNOCKBACK = 81235,
+
+ // Creature Formation IDs
+ CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH = 340418,
+ CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP = 340492,
+};
+
+#endif // DEF_STONECORE