diff --git a/sql/updates/world/custom/custom_2019_01_18_01_world.sql b/sql/updates/world/custom/custom_2019_01_18_01_world.sql
new file mode 100644
index 00000000000..a55becd5dd1
--- /dev/null
+++ b/sql/updates/world/custom/custom_2019_01_18_01_world.sql
@@ -0,0 +1,37 @@
+-- Template Updates
+-- Berserker Boulder Roller
+UPDATE `creature_template` SET `DamageModifier`= 120, `BaseVariance`= 0.5, `flags_extra`= 0x40000000, `mechanic_immune_mask`= 634338303, `ScriptName`= 'npc_zulgurub_berserking_boulder_roller' WHERE `entry`= 52348;
+-- Boulder
+UPDATE `creature_template` SET `speed_run`= 2.1428, `unit_flags`= 33554432, `unit_flags2`= 2099200, `VehicleId`= 1594, `flags_extra`= 2 WHERE `entry` IN (52353, 52351, 52354);
+UPDATE `creature_template` SET `unit_flags`= 33554432, `unit_flags2`= 2099200, `flags_extra`= 2, `ScriptName`= '' WHERE `entry`= 52350;
+
+-- Spells
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN
+('spell_zulgurub_rolling_boulders',
+'spell_zulgurub_boulder_smash');
+
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(96826, 'spell_zulgurub_rolling_boulders'),
+(96837, 'spell_zulgurub_rolling_boulders'),
+(96834, 'spell_zulgurub_boulder_smash');
+
+-- Addons
+DELETE FROM `creature_template_addon` WHERE `entry` IN (52353, 52351, 52354, 52350);
+INSERT INTO `creature_template_addon` (`entry`, `bytes1`, `bytes2`, `auras`) VALUES
+(52353, 0, 1, '96831'),
+(52351, 0, 1, '96831'),
+(52354, 0, 1, '96831');
+
+-- Spellclicks
+DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (52353, 52351, 52354);
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES
+(52353, 46598, 1, 1),
+(52351, 46598, 1, 1),
+(52354, 46598, 1, 1);
+
+-- Vehicle accessories
+DELETE FROM `vehicle_template_accessory` WHERE `entry` IN (52353, 52351, 52354);
+INSERT INTO `vehicle_template_accessory` (`entry`, `accessory_entry`, `seat_id`, `minion`, `description`, `summontype`, `summontimer`) VALUES
+(52353, 52350, 0, 1, 'Boulder - Boulder', 8, 0),
+(52351, 52350, 0, 1, 'Boulder - Boulder', 8, 0),
+(52354, 52350, 0, 1, 'Boulder - Boulder', 8, 0);
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 77e927504b7..a174eda0cba 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -4837,6 +4837,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 1;
});
+ // Rolling Boulders Search Effect
+ ApplySpellFix({ 96839 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->MaxAffectedTargets = 1;
+ });
+
// Sunder Rift
ApplySpellFix({ 96964 }, [](SpellInfo* spellInfo)
{
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.cpp
new file mode 100644
index 00000000000..fad5a6a5313
--- /dev/null
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2008-2019 TrinityCore
+ *
+ * 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 .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "zulgurub.h"
+#include "GridNotifiers.h"
+#include "MoveSplineInit.h"
+#include "Spell.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "Vehicle.h"
+
+enum RollingBoulders
+{
+ SPELL_ROLLING_BOULDERS_PERIODIC_AURA = 96837,
+ SPELL_ROLLING_BOULDERS_SEARCH_EFFECT = 96839,
+ SPELL_ROLLING_BOULDERS_SUMMON_LEFT = 96827,
+ SPELL_ROLLING_BOULDERS_SUMMON_CENTER = 96828,
+ SPELL_ROLLING_BOULDERS_SUMMON_RIGHT = 96829,
+ SPELL_THUNDERCLAP = 15588,
+ SPELL_KNOCK_AWAY = 97616,
+ SPELL_EXPLODING_BOULDER = 96836,
+ SPELL_EXPLODING_BOULDER_VISUAL = 96831,
+ SPELL_ROLLING_BOULDERS = 96833,
+
+ NPC_BOULDER_LEFT = 52351,
+ NPC_BOULDER_CENTER = 52354,
+ NPC_BOULDER_RIGHT = 52353,
+
+ EVENT_THUNDERCLAP = 1,
+ EVENT_KNOCK_AWAY = 2,
+
+ ACTION_ROLL_BOULDER = 0,
+ SEAT_0 = 0
+};
+
+uint32 boulderCombinationFirst[] =
+{
+ SPELL_ROLLING_BOULDERS_SUMMON_RIGHT,
+ SPELL_ROLLING_BOULDERS_SUMMON_CENTER,
+ SPELL_ROLLING_BOULDERS_SUMMON_LEFT
+};
+
+uint32 boulderCombinationSecond[] =
+{
+ SPELL_ROLLING_BOULDERS_SUMMON_RIGHT,
+ SPELL_ROLLING_BOULDERS_SUMMON_LEFT,
+ SPELL_ROLLING_BOULDERS_SUMMON_CENTER
+};
+
+Position const BoulderMovePosLeft = { -12128.5f, -1809.7f, 81.73696f }; // jump to -12134.33 Y: -1809.78 Z: 83.9827
+Position const BoulderMovePosCenter = { -12117.74f, -1818.293f, 80.22023f }; // jump to -12123.57 Y: -1818.352 Z: 80.20083
+Position const BoulderMovePosRight = { -12126.91f, -1827.861f, 81.26235f }; // jump to -12132.74 Y: -1827.843 Z: 83.37392
+
+class ExplodingBoulderEvent : public BasicEvent
+{
+ public:
+ ExplodingBoulderEvent(Creature* owner) : _owner(owner) { }
+
+ bool Execute(uint64 /*time*/, uint32 /*diff*/) override
+ {
+ _owner->RemoveAurasDueToSpell(SPELL_EXPLODING_BOULDER_VISUAL);
+ _owner->CastSpell(_owner, SPELL_EXPLODING_BOULDER);
+ _owner->DespawnOrUnsummon(1s);
+ if (Vehicle* vehicle = _owner->GetVehicleKit())
+ if (Unit* passenger = vehicle->GetPassenger(SEAT_0))
+ if (Creature* creature = passenger->ToCreature())
+ creature->DespawnOrUnsummon(1s);
+ return true;
+ }
+ private:
+ Creature* _owner;
+};
+
+class RollingBouldersCastEvent : public BasicEvent
+{
+ public:
+ RollingBouldersCastEvent(Creature* owner) : _owner(owner) { }
+
+ bool Execute(uint64 /*time*/, uint32 /*diff*/) override
+ {
+ _owner->CastSpell(_owner, SPELL_ROLLING_BOULDERS);
+ return true;
+ }
+ private:
+ Creature* _owner;
+};
+
+struct npc_zulgurub_berserking_boulder_roller : public ScriptedAI
+{
+ npc_zulgurub_berserking_boulder_roller(Creature* creature) : ScriptedAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ me->SetReactState(REACT_PASSIVE);
+ _useSecondCombination = false;
+ }
+
+ void Reset() override
+ {
+ Initialize();
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _events.ScheduleEvent(EVENT_THUNDERCLAP, 2s);
+ _events.ScheduleEvent(EVENT_KNOCK_AWAY, 6s, 7s);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ _EnterEvadeMode();
+ _events.Reset();
+ me->GetMotionMaster()->MoveTargetedHome();
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_ROLLING_BOULDERS_SEARCH_EFFECT)
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveAurasDueToSpell(SPELL_ROLLING_BOULDERS_PERIODIC_AURA);
+ AttackStart(target);
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_ROLL_BOULDER)
+ {
+ uint32 spellId = !_useSecondCombination ? boulderCombinationFirst[_boulderCount] : boulderCombinationSecond[_boulderCount];
+ DoCastSelf(spellId, true);
+
+ if (_boulderCount < 2)
+ _boulderCount++;
+ else
+ {
+ _boulderCount = 0;
+ _useSecondCombination = !_useSecondCombination ? true : false;
+ }
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ Position destination;
+ switch (summon->GetEntry())
+ {
+ case NPC_BOULDER_LEFT:
+ destination = BoulderMovePosLeft;
+ break;
+ case NPC_BOULDER_CENTER:
+ destination = BoulderMovePosCenter;
+ break;
+ case NPC_BOULDER_RIGHT:
+ destination = BoulderMovePosRight;
+ break;
+ default:
+ break;
+ }
+
+ Movement::MoveSplineInit init(summon);
+ init.MoveTo(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
+ if (uint32 time = init.Launch())
+ summon->m_Events.AddEventAtOffset(new ExplodingBoulderEvent(summon), Milliseconds(time));
+
+ summon->m_Events.AddEventAtOffset(new RollingBouldersCastEvent(summon), 600ms);
+ }
+
+ 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_THUNDERCLAP:
+ DoCastAOE(SPELL_THUNDERCLAP);
+ _events.Repeat(15s, 16s);
+ break;
+ case EVENT_KNOCK_AWAY:
+ DoCastVictim(SPELL_KNOCK_AWAY);
+ _events.Repeat(19s, 20s);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ EventMap _events;
+ uint8 _boulderCount;
+ bool _useSecondCombination;
+};
+
+class spell_zulgurub_rolling_boulders : public AuraScript
+{
+ PrepareAuraScript(spell_zulgurub_rolling_boulders);
+
+ void HandleTick(AuraEffect const* /*aurEff*/)
+ {
+ // Serverside spell. We just skip that part and do it directly via script
+ PreventDefaultAction();
+ if (Creature* creature = GetTarget()->ToCreature())
+ if (creature->IsAIEnabled)
+ creature->AI()->DoAction(ACTION_ROLL_BOULDER);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_zulgurub_rolling_boulders::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+};
+
+void AddSC_zulgurub()
+{
+ RegisterZulGurubCreatureAI(npc_zulgurub_berserking_boulder_roller);
+ RegisterAuraScript(spell_zulgurub_rolling_boulders);
+}
diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
index a17f444a6d7..5e85108f6ea 100644
--- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
+++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
@@ -213,6 +213,7 @@ void AddSC_boss_renataki();
void AddSC_boss_high_priest_venoxis();
void AddSC_boss_wushoolay();
void AddSC_boss_zanzil();
+void AddSC_zulgurub();
void AddSC_instance_zulgurub();
//void AddSC_alterac_mountains();
//void AddSC_arathi_highlands();
@@ -437,6 +438,7 @@ void AddEasternKingdomsScripts()
AddSC_boss_high_priest_venoxis();
AddSC_boss_wushoolay();
AddSC_boss_zanzil();
+ AddSC_zulgurub();
AddSC_instance_zulgurub();
//AddSC_alterac_mountains();
//AddSC_arathi_highlands();