aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoroffl <11556157+offl@users.noreply.github.com>2025-06-10 22:05:55 +0300
committerGitHub <noreply@github.com>2025-06-10 21:05:55 +0200
commita23262869685e66d68be233b9020d611ffdb5db0 (patch)
tree60e0c7c6a55cd44171207e6c746389dd879cebda
parent0bd56da09b1f0ae34605a1a6fdd14ca26cd42d4c (diff)
Scripts/Gruul's Lair: Update scripts (#30913)
-rw-r--r--sql/updates/world/3.3.5/2025_06_10_06_world.sql19
-rw-r--r--src/server/scripts/Outland/GruulsLair/boss_gruul.cpp507
-rw-r--r--src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp681
-rw-r--r--src/server/scripts/Outland/GruulsLair/gruuls_lair.h2
4 files changed, 513 insertions, 696 deletions
diff --git a/sql/updates/world/3.3.5/2025_06_10_06_world.sql b/sql/updates/world/3.3.5/2025_06_10_06_world.sql
new file mode 100644
index 00000000000..fb111f71de1
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_06_10_06_world.sql
@@ -0,0 +1,19 @@
+--
+DELETE FROM `spell_script_names` WHERE
+(`spell_id` = 33525 AND `ScriptName` = "spell_gruul_ground_slam") OR
+(`spell_id` = 33965 AND `ScriptName` = "spell_gruul_look_around") OR
+(`spell_id` = 33812 AND `ScriptName` = "spell_gruul_hurtful_strike_primer");
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(33525,"spell_gruul_ground_slam"),
+(33965,"spell_gruul_look_around"),
+(33812,"spell_gruul_hurtful_strike_primer");
+
+UPDATE `creature_text` SET `Text` = "%s roars!", `Type` = 16, `Sound` = 0, `BroadcastTextId` = 14029, `comment` = "gruul EMOTE_ROAR" WHERE `CreatureID` = 19044 AND `GroupID` = 4 AND `ID` = 0;
+UPDATE `creature_text` SET `TextRange` = 3 WHERE `CreatureID` = 19044;
+
+UPDATE `creature_template` SET `AIName` = "SmartAI" WHERE `entry` = 19198;
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 19198 AND `source_type` = 0;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`event_param5`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_param4`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(19198,0,0,0,60,0,100,1,0,0,0,0,0,11,33496,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Invisible Tractor Beam Source - On Update - Cast 'Tractor Beam Creator' (No Repeat)"),
+(19198,0,1,0,60,0,100,1,500,500,0,0,0,11,33497,0,0,0,0,0,23,0,0,0,0,0,0,0,0,"Invisible Tractor Beam Source - On Update - Cast 'Tractor Beam' (No Repeat)"),
+(19198,0,2,0,60,0,100,1,1000,1000,0,0,0,41,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Invisible Tractor Beam Source - On Update - Despawn Instant (No Repeat)");
diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp
index 3b519ae2bc0..1a15d9a7a35 100644
--- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp
+++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp
@@ -16,330 +16,291 @@
*/
/*
-TO-DO:
-Slighly(400ms) after spell cast 33965 creatures 19198 are spawned. I guess he forces all enemies including pets(9 summoned units
-and 9 units in his threatlist) to cast 39186(19198 were created by that spell(sniff)). Summoned by that spell creature 19198 casts 33496
-on self after being summoned. Then probably they casts 33497(Pull Towards: (150)) on their creators and that's how that knockback is handled.
-If you look closely, players are knocked to random destinations with random angles, means there is no only one spell which handles knockback.
-19198 despawns after 800ms after being summoned.
-*/
+ * Dummy spell 39188 apparently handles actions from EVENT_GROUND_SLAM but maybe something else
+ * The way Reverberation & Ground Slam timers are handled may be wrong. Both timers are random but sometimes
+ because of that first Reverberation cast may be skipped while so far I never seen it in movies. He can cast
+ it twice between Ground Slam sequences or skip one of 2 casts but never skips all. Maybe it's just random
+ * The way knock back is handled should be re-checked
+ */
#include "ScriptMgr.h"
#include "gruuls_lair.h"
-#include "MotionMaster.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
-enum Yells
+enum GruulTexts
{
SAY_AGGRO = 0,
SAY_SLAM = 1,
SAY_SHATTER = 2,
SAY_SLAY = 3,
- SAY_DEATH = 4,
-
+ EMOTE_ROAR = 4,
EMOTE_GROW = 5
};
-enum Spells
+enum GruulSpells
{
- SPELL_GROWTH = 36300,
+ SPELL_HURTFUL_STRIKE_PRIMER = 33812,
+ SPELL_HURTFUL_STRIKE = 33813,
SPELL_CAVE_IN = 36240,
- SPELL_GROUND_SLAM = 33525, // AoE Ground Slam applying Ground Slam to everyone with a script effect (most likely the knock back, we can code it to a set knockback)
SPELL_REVERBERATION = 36297,
- SPELL_SHATTER = 33654,
+ SPELL_GROWTH = 36300,
+ SPELL_GROUND_SLAM_DUMMY = 39188,
+ SPELL_GROUND_SLAM = 33525,
+ SPELL_LOOK_AROUND = 33965,
+ SPELL_SUMMON_RANDOM_TRACTOR = 39186,
+ SPELL_SHATTER = 33654,
SPELL_SHATTER_EFFECT = 33671,
- SPELL_HURTFUL_STRIKE = 33813,
- SPELL_STONED = 33652, // Spell is self cast by target
-
- SPELL_MAGNETIC_PULL = 28337,
- SPELL_KNOCK_BACK = 24199, // Knockback spell until correct implementation is made
+ SPELL_STONED = 33652
};
-enum Events
+enum GruulEvents
{
- EVENT_GROWTH = 1,
+ EVENT_HURTFUL_STRIKE = 1,
EVENT_CAVE_IN,
- EVENT_CAVE_IN_STATIC,
- EVENT_GROUND_SLAM,
- EVENT_HURTFUL_STRIKE,
- EVENT_REVERBERATION
+ EVENT_REVERBERATION,
+ EVENT_GROWTH,
+ EVENT_GROUND_SLAM
};
-class boss_gruul : public CreatureScript
+enum GruulMisc
{
- public:
- boss_gruul() : CreatureScript("boss_gruul") { }
-
- struct boss_gruulAI : public BossAI
- {
- boss_gruulAI(Creature* creature) : BossAI(creature, DATA_GRUUL)
- {
- Initialize();
- }
-
- void Initialize()
- {
- m_uiGrowth_Timer = 30000;
- m_uiCaveIn_Timer = 27000;
- m_uiCaveIn_StaticTimer = 30000;
- m_uiGroundSlamTimer = 35000;
- m_bPerformingGroundSlam = false;
- m_uiHurtfulStrike_Timer = 8000;
- m_uiReverberation_Timer = 60000 + 45000;
- }
-
- uint32 m_uiGrowth_Timer;
- uint32 m_uiCaveIn_Timer;
- uint32 m_uiCaveIn_StaticTimer;
- uint32 m_uiGroundSlamTimer;
- uint32 m_uiHurtfulStrike_Timer;
- uint32 m_uiReverberation_Timer;
-
- bool m_bPerformingGroundSlam;
-
- void Reset() override
- {
- _Reset();
- Initialize();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- BossAI::JustEngagedWith(who);
- Talk(SAY_AGGRO);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_SLAY);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- Talk(SAY_DEATH);
- }
+ SOUND_ID_DEATH = 11363
+};
- void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
- {
- //This to emulate effect1 (77) of SPELL_GROUND_SLAM, knock back to any direction
- //It's initially wrong, since this will cause fall damage, which is by comments, not intended.
- if (spellInfo->Id == SPELL_GROUND_SLAM)
- {
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- switch (urand(0, 1))
- {
- case 0:
- target->CastSpell(target, SPELL_MAGNETIC_PULL, me->GetGUID());
- break;
-
- case 1:
- target->CastSpell(target, SPELL_KNOCK_BACK, me->GetGUID());
- break;
- }
- }
- }
-
- //this part should be in the core
- if (spellInfo->Id == SPELL_SHATTER)
- {
- /// @todo use eventmap to kill this stuff
- //clear this, if we are still performing
- if (m_bPerformingGroundSlam)
- {
- m_bPerformingGroundSlam = false;
-
- //and correct movement, if not already
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE)
- {
- if (me->GetVictim())
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- }
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- /// @todo: convert this shit to eventmap
-
- // Growth
- // Gruul can cast this spell up to 30 times
- if (m_uiGrowth_Timer <= diff)
- {
- Talk(EMOTE_GROW);
- DoCast(me, SPELL_GROWTH);
- m_uiGrowth_Timer = 30000;
- }
- else
- m_uiGrowth_Timer -= diff;
-
- if (m_bPerformingGroundSlam)
- {
- if (m_uiGroundSlamTimer <= diff)
- {
- m_uiGroundSlamTimer =120000;
- m_uiHurtfulStrike_Timer= 8000;
-
- if (m_uiReverberation_Timer < 10000) //Give a little time to the players to undo the damage from shatter
- m_uiReverberation_Timer += 10000;
-
- DoCast(me, SPELL_SHATTER);
- }
- else
- m_uiGroundSlamTimer -= diff;
- }
- else
- {
- // Hurtful Strike
- if (m_uiHurtfulStrike_Timer <= diff)
- {
- Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1);
-
- if (target && me->IsWithinMeleeRange(me->GetVictim()))
- DoCast(target, SPELL_HURTFUL_STRIKE);
- else
- DoCastVictim(SPELL_HURTFUL_STRIKE);
-
- m_uiHurtfulStrike_Timer= 8000;
- }
- else
- m_uiHurtfulStrike_Timer -= diff;
-
- // Reverberation
- if (m_uiReverberation_Timer <= diff)
- {
- DoCastVictim(SPELL_REVERBERATION, true);
- m_uiReverberation_Timer = urand(15000, 25000);
- }
- else
- m_uiReverberation_Timer -= diff;
-
- // Cave In
- if (m_uiCaveIn_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- DoCast(target, SPELL_CAVE_IN);
-
- if (m_uiCaveIn_StaticTimer >= 4000)
- m_uiCaveIn_StaticTimer -= 2000;
-
- m_uiCaveIn_Timer = m_uiCaveIn_StaticTimer;
- }
- else
- m_uiCaveIn_Timer -= diff;
-
- // Ground Slam, Gronn Lord's Grasp, Stoned, Shatter
- if (m_uiGroundSlamTimer <= diff)
- {
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveIdle();
-
- m_bPerformingGroundSlam= true;
- m_uiGroundSlamTimer = 10000;
-
- DoCast(me, SPELL_GROUND_SLAM);
- }
- else
- m_uiGroundSlamTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+// 19044 - Gruul the Dragonkiller
+struct boss_gruul : public BossAI
+{
+ boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { }
+
+ void Reset() override
+ {
+ _Reset();
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(SAY_AGGRO);
+
+ events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 6s);
+ events.ScheduleEvent(EVENT_CAVE_IN, 8s);
+ events.ScheduleEvent(EVENT_REVERBERATION, 105s, 115s);
+ events.ScheduleEvent(EVENT_GROWTH, 30s);
+ events.ScheduleEvent(EVENT_GROUND_SLAM, 40s);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ DoPlaySoundToSet(me, SOUND_ID_DEATH);
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
- return GetGruulsLairAI<boss_gruulAI>(creature);
+ case EVENT_HURTFUL_STRIKE:
+ DoCastSelf(SPELL_HURTFUL_STRIKE_PRIMER);
+ events.Repeat(8s);
+ break;
+ case EVENT_CAVE_IN:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_CAVE_IN);
+ events.Repeat(8s);
+ break;
+ case EVENT_REVERBERATION:
+ DoCastSelf(SPELL_REVERBERATION);
+ events.Repeat(30s, 45s);
+ break;
+ case EVENT_GROWTH:
+ DoCastSelf(SPELL_GROWTH);
+ Talk(EMOTE_GROW);
+ events.Repeat(30s);
+ break;
+ case EVENT_GROUND_SLAM:
+ DoCastSelf(SPELL_GROUND_SLAM_DUMMY);
+ Talk(SAY_SLAM);
+ DoCastSelf(SPELL_GROUND_SLAM);
+ events.RescheduleEvent(EVENT_HURTFUL_STRIKE, 21s);
+ events.RescheduleEvent(EVENT_CAVE_IN, 15s);
+ events.Repeat(70s, 90s);
+ break;
+ default:
+ break;
}
+ }
};
-class spell_gruul_shatter : public SpellScriptLoader
+// 33812 - Hurtful Strike Primer
+class spell_gruul_hurtful_strike_primer : public SpellScript
{
- public:
- spell_gruul_shatter() : SpellScriptLoader("spell_gruul_shatter") { }
+ PrepareSpellScript(spell_gruul_hurtful_strike_primer);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ Unit* caster = GetCaster();
- class spell_gruul_shatter_SpellScript : public SpellScript
+ // First we get rid of all targets that are not within melee range
+ targets.remove_if([&](WorldObject* target)
{
- PrepareSpellScript(spell_gruul_shatter_SpellScript);
+ if (Unit* unit = target->ToUnit())
+ return !unit->IsWithinMeleeRange(caster);
- bool Validate(SpellInfo const* /*spell*/) override
- {
- return ValidateSpellInfo({ SPELL_STONED, SPELL_SHATTER_EFFECT });
- }
+ return true;
+ });
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- if (Unit* target = GetHitUnit())
- {
- target->RemoveAurasDueToSpell(SPELL_STONED);
- target->CastSpell(nullptr, SPELL_SHATTER_EFFECT, true);
- }
- }
-
- void Register() override
+ if (targets.size() >= 2)
+ {
+ // Now we sort all targets by threat
+ targets.sort([&](WorldObject const* left, WorldObject const* right)
{
- OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
+ Unit const* leftTarget = ASSERT_NOTNULL(left->ToUnit());
+ Unit const* rightTarget = ASSERT_NOTNULL(right->ToUnit());
- SpellScript* GetSpellScript() const override
- {
- return new spell_gruul_shatter_SpellScript();
+ return caster->GetThreatManager().GetThreat(leftTarget) > caster->GetThreatManager().GetThreat(rightTarget);
+ });
+
+ // Now we nuke the top threat target so we are only left with the 2nd top victim
+ targets.pop_front();
+
+ if (targets.size() >= 2)
+ targets.resize(1);
}
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), SPELL_HURTFUL_STRIKE);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gruul_hurtful_strike_primer::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_gruul_hurtful_strike_primer::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
};
-class spell_gruul_shatter_effect : public SpellScriptLoader
+// 33525 - Ground Slam
+class spell_gruul_ground_slam : public SpellScript
{
- public:
- spell_gruul_shatter_effect() : SpellScriptLoader("spell_gruul_shatter_effect") { }
+ PrepareSpellScript(spell_gruul_ground_slam);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_LOOK_AROUND, SPELL_SUMMON_RANDOM_TRACTOR });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ // Stuns Gruul for 8 seconds
+ GetCaster()->CastSpell(GetCaster(), SPELL_LOOK_AROUND);
+ /* I guess he forces all enemies including pets to summon creature 19198 by spell 39186(9 summoned units and
+ 9 units in his threat list). Summoned by that spell creature 19198 casts 33496 on self after being summoned.
+ Then after small delay they casts 33497(Pull Towards: (150)) (guess) on their creators and that's how that
+ knockback without fall damage is handled. If you look closely, players are knocked to random destinations
+ with random angles, means there is no only one spell which handles knockback. However the spell to summon
+ that trigger is TARGET_DEST_CASTER_RADIUS, so creature may be spawned just few yards away from player. In
+ that case player will be knocked back for a really small distance. It may look weird and wrong.
+ Script for 19198 is handled in SAI. 19198 probably is used in Cata dungeons or raids too, also at least in
+ one TBC raid or dungeon since there are more spells to summon that creature. */
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_RANDOM_TRACTOR);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gruul_ground_slam::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
- class spell_gruul_shatter_effect_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_gruul_shatter_effect_SpellScript);
+// 33965 - Look Around
+class spell_gruul_look_around : public AuraScript
+{
+ PrepareAuraScript(spell_gruul_look_around);
- void CalculateDamage()
- {
- if (!GetHitUnit())
- return;
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SHATTER });
+ }
- float radius = GetEffectInfo(EFFECT_0).CalcRadius(GetCaster());
- if (!radius)
- return;
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* creature = GetTarget()->ToCreature())
+ {
+ creature->AI()->Talk(EMOTE_ROAR);
+ creature->AI()->Talk(SAY_SHATTER);
+ creature->CastSpell(creature, SPELL_SHATTER);
+ }
+ }
- float distance = GetCaster()->GetDistance2d(GetHitUnit());
- if (distance > 1.0f)
- SetHitDamage(int32(GetHitDamage() * ((radius - distance) / radius)));
- }
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_gruul_look_around::AfterRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ }
+};
- void Register() override
- {
- OnHit += SpellHitFn(spell_gruul_shatter_effect_SpellScript::CalculateDamage);
- }
- };
+// 33654 - Shatter
+class spell_gruul_shatter : public SpellScript
+{
+ PrepareSpellScript(spell_gruul_shatter);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return ValidateSpellInfo({ SPELL_STONED, SPELL_SHATTER_EFFECT });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ target->RemoveAurasDueToSpell(SPELL_STONED);
+ target->CastSpell(nullptr, SPELL_SHATTER_EFFECT, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
- SpellScript* GetSpellScript() const override
- {
- return new spell_gruul_shatter_effect_SpellScript();
- }
+// 33671 - Shatter
+class spell_gruul_shatter_effect : public SpellScript
+{
+ PrepareSpellScript(spell_gruul_shatter_effect);
+
+ void CalculateDamage()
+ {
+ if (!GetHitUnit())
+ return;
+
+ float radius = GetEffectInfo(EFFECT_0).CalcRadius(GetCaster());
+ if (!radius)
+ return;
+
+ float distance = GetCaster()->GetDistance2d(GetHitUnit());
+ if (distance > 1.0f)
+ SetHitDamage(int32(GetHitDamage() * ((radius - distance) / radius)));
+ }
+
+ void Register() override
+ {
+ OnHit += SpellHitFn(spell_gruul_shatter_effect::CalculateDamage);
+ }
};
void AddSC_boss_gruul()
{
- new boss_gruul();
- new spell_gruul_shatter();
- new spell_gruul_shatter_effect();
+ RegisterGruulsLairCreatureAI(boss_gruul);
+ RegisterSpellScript(spell_gruul_hurtful_strike_primer);
+ RegisterSpellScript(spell_gruul_ground_slam);
+ RegisterSpellScript(spell_gruul_look_around);
+ RegisterSpellScript(spell_gruul_shatter);
+ RegisterSpellScript(spell_gruul_shatter_effect);
}
diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
index 78c3e190c50..dc1a29955ba 100644
--- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
+++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp
@@ -15,41 +15,40 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_High_King_Maulgar
-SD%Complete: 90
-SDComment: Correct timers, after whirlwind melee attack bug, prayer of healing
-SDCategory: Gruul's Lair
-EndScriptData */
+/*
+ * Timers requires update
+ * The door should open after Maulgar's death, not after all NPCs are dead
+ */
#include "ScriptMgr.h"
#include "gruuls_lair.h"
#include "InstanceScript.h"
-#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
-enum HighKingMaulgar
+enum MaulgarTexts
{
SAY_AGGRO = 0,
SAY_ENRAGE = 1,
SAY_OGRE_DEATH = 2,
SAY_SLAY = 3,
- SAY_DEATH = 4,
+ SAY_DEATH = 4
+};
+enum MaulgarSpells
+{
// High King Maulgar
SPELL_ARCING_SMASH = 39144,
SPELL_MIGHTY_BLOW = 33230,
SPELL_WHIRLWIND = 33238,
- SPELL_BERSERKER_C = 26561,
+ SPELL_BERSERKER_CHARGE = 26561,
SPELL_ROAR = 16508,
SPELL_FLURRY = 33232,
- SPELL_DUAL_WIELD = 29651,
// Olm the Summoner
SPELL_DARK_DECAY = 33129,
SPELL_DEATH_COIL = 33130,
- SPELL_SUMMON_WFH = 33131,
+ SPELL_SUMMON_WILD_FELHUNTER = 33131,
// Kiggler the Craed
SPELL_GREATER_POLYMORPH = 33173,
@@ -65,523 +64,359 @@ enum HighKingMaulgar
// Krosh Firehand
SPELL_GREATER_FIREBALL = 33051,
SPELL_SPELLSHIELD = 33054,
- SPELL_BLAST_WAVE = 33061,
+ SPELL_BLAST_WAVE = 33061
+};
+enum MaulgarMisc
+{
ACTION_ADD_DEATH = 1
};
-class boss_high_king_maulgar : public CreatureScript
+// 18831 - High King Maulgar
+struct boss_high_king_maulgar : public BossAI
{
-public:
- boss_high_king_maulgar() : CreatureScript("boss_high_king_maulgar") { }
+ boss_high_king_maulgar(Creature* creature) : BossAI(creature, DATA_MAULGAR), _enraged(false) { }
- struct boss_high_king_maulgarAI : public ScriptedAI
+ void Reset() override
{
- boss_high_king_maulgarAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- ArcingSmash_Timer = 10000;
- MightyBlow_Timer = 40000;
- Whirlwind_Timer = 30000;
- Charging_Timer = 0;
- Roar_Timer = 0;
-
- Phase2 = false;
- }
-
- InstanceScript* instance;
-
- uint32 ArcingSmash_Timer;
- uint32 MightyBlow_Timer;
- uint32 Whirlwind_Timer;
- uint32 Charging_Timer;
- uint32 Roar_Timer;
-
- bool Phase2;
-
- void Reset() override
- {
- Initialize();
-
- DoCast(me, SPELL_DUAL_WIELD, false);
-
- instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
- }
+ _Reset();
+ _enraged = false;
+ }
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_SLAY);
- }
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ Talk(SAY_AGGRO);
- void JustDied(Unit* /*killer*/) override
+ scheduler.Schedule(10s, [this](TaskContext task)
{
- Talk(SAY_DEATH);
-
- instance->SetBossState(DATA_MAULGAR, DONE);
- }
+ DoCastVictim(SPELL_ARCING_SMASH);
+ task.Repeat(10s);
+ });
- void DoAction(int32 actionId) override
+ scheduler.Schedule(30s, [this](TaskContext task)
{
- if (actionId == ACTION_ADD_DEATH)
- Talk(SAY_OGRE_DEATH);
- }
+ DoCastSelf(SPELL_WHIRLWIND);
+ task.Repeat(55s);
+ });
- void JustEngagedWith(Unit* /*who*/) override
+ scheduler.Schedule(40s, [this](TaskContext task)
{
- DoZoneInCombat();
- instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
- Talk(SAY_AGGRO);
- }
+ DoCastVictim(SPELL_MIGHTY_BLOW);
+ task.Repeat(30s, 40s);
+ });
+ }
- void UpdateAI(uint32 diff) override
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ {
+ if (!_enraged && me->HealthBelowPctDamaged(50, damage))
{
- if (!UpdateVictim())
- return;
-
- //ArcingSmash_Timer
- if (ArcingSmash_Timer <= diff)
- {
- DoCastVictim(SPELL_ARCING_SMASH);
- ArcingSmash_Timer = 10000;
- } else ArcingSmash_Timer -= diff;
-
- //Whirlwind_Timer
- if (Whirlwind_Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND);
- Whirlwind_Timer = 55000;
- } else Whirlwind_Timer -= diff;
-
- //MightyBlow_Timer
- if (MightyBlow_Timer <= diff)
+ scheduler.Schedule(0s, [this](TaskContext /*task*/)
{
- DoCastVictim(SPELL_MIGHTY_BLOW);
- MightyBlow_Timer = 30000 + rand32() % 10000;
- } else MightyBlow_Timer -= diff;
-
- //Entering Phase 2
- if (!Phase2 && HealthBelowPct(50))
- {
- Phase2 = true;
+ _enraged = true;
Talk(SAY_ENRAGE);
+ DoCastSelf(SPELL_FLURRY);
+ SetEquipmentSlots(false, EQUIP_UNEQUIP);
+ });
- DoCast(me, SPELL_DUAL_WIELD, true);
- me->SetVirtualItem(0, 0);
- me->SetVirtualItem(1, 0);
- }
+ scheduler.Schedule(0s, 5s, [this](TaskContext task)
+ {
+ DoCastSelf(SPELL_ROAR);
+ task.Repeat(40s, 50s);
+ });
- if (Phase2)
+ scheduler.Schedule(10s, 15s, [this](TaskContext task)
{
- //Charging_Timer
- if (Charging_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- {
- AttackStart(target);
- DoCast(target, SPELL_BERSERKER_C);
- }
- Charging_Timer = 20000;
- } else Charging_Timer -= diff;
-
- //Intimidating Roar
- if (Roar_Timer <= diff)
- {
- DoCast(me, SPELL_ROAR);
- Roar_Timer = 40000 + (rand32() % 10000);
- } else Roar_Timer -= diff;
- }
-
- DoMeleeAttackIfReady();
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_BERSERKER_CHARGE);
+ task.Repeat(20s);
+ });
}
- };
+ }
- CreatureAI* GetAI(Creature* creature) const override
+ void DoAction(int32 actionId) override
{
- return GetGruulsLairAI<boss_high_king_maulgarAI>(creature);
- }
-};
+ if (!me->IsAlive())
+ return;
-class boss_olm_the_summoner : public CreatureScript
-{
-public:
- boss_olm_the_summoner() : CreatureScript("boss_olm_the_summoner") { }
+ if (actionId == ACTION_ADD_DEATH)
+ Talk(SAY_OGRE_DEATH);
+ }
- struct boss_olm_the_summonerAI : public ScriptedAI
+ void KilledUnit(Unit* /*victim*/) override
{
- boss_olm_the_summonerAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
+ Talk(SAY_SLAY);
+ }
- void Initialize()
- {
- DarkDecay_Timer = 10000;
- Summon_Timer = 15000;
- DeathCoil_Timer = 20000;
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
- uint32 DarkDecay_Timer;
- uint32 Summon_Timer;
- uint32 DeathCoil_Timer;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- InstanceScript* instance;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void Reset() override
- {
- Initialize();
+ scheduler.Update(diff);
- instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
- }
+ DoMeleeAttackIfReady();
+ }
- void AttackStart(Unit* who) override
- {
- if (!who)
- return;
+private:
+ bool _enraged;
+};
- if (me->Attack(who, true))
- {
- AddThreat(who, 0.0f);
- me->SetInCombatWith(who);
- who->SetInCombatWith(me);
+// 18834 - Olm the Summoner
+struct boss_olm_the_summoner : public ScriptedAI
+{
+ boss_olm_the_summoner(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- me->GetMotionMaster()->MoveChase(who, 30.0f);
- }
- }
+ void Reset() override
+ {
+ _scheduler.CancelAll();
+ }
- void JustEngagedWith(Unit* /*who*/) override
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _scheduler.Schedule(10s, [this](TaskContext task)
{
- DoZoneInCombat();
- instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
- }
+ DoCastVictim(SPELL_DARK_DECAY);
+ task.Repeat(20s);
+ });
- void JustDied(Unit* /*killer*/) override
+ _scheduler.Schedule(0s, 10s, [this](TaskContext task)
{
- if (Creature* maulgar = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MAULGAR)))
- maulgar->AI()->DoAction(ACTION_ADD_DEATH);
+ DoCastSelf(SPELL_SUMMON_WILD_FELHUNTER);
+ task.Repeat(50s, 60s);
+ });
- instance->SetBossState(DATA_MAULGAR, DONE);
- }
-
- void UpdateAI(uint32 diff) override
+ _scheduler.Schedule(20s, [this](TaskContext task)
{
- if (!UpdateVictim())
- return;
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_DEATH_COIL);
+ task.Repeat(20s);
+ });
+ }
- //DarkDecay_Timer
- if (DarkDecay_Timer <= diff)
- {
- DoCastVictim(SPELL_DARK_DECAY);
- DarkDecay_Timer = 20000;
- } else DarkDecay_Timer -= diff;
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
+ maulgar->AI()->DoAction(ACTION_ADD_DEATH);
- //Summon_Timer
- if (Summon_Timer <= diff)
- {
- DoCast(me, SPELL_SUMMON_WFH);
- Summon_Timer = 30000;
- } else Summon_Timer -= diff;
+ _instance->SetBossState(DATA_MAULGAR, DONE);
+ }
- //DeathCoil Timer /need correct timer
- if (DeathCoil_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- DoCast(target, SPELL_DEATH_COIL);
- DeathCoil_Timer = 20000;
- } else DeathCoil_Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- DoMeleeAttackIfReady();
- }
- };
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetGruulsLairAI<boss_olm_the_summonerAI>(creature);
+ _scheduler.Update(diff);
+
+ DoMeleeAttackIfReady();
}
+
+private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
-//Kiggler The Crazed AI
-class boss_kiggler_the_crazed : public CreatureScript
+// 18835 - Kiggler the Crazed
+struct boss_kiggler_the_crazed : public ScriptedAI
{
-public:
- boss_kiggler_the_crazed() : CreatureScript("boss_kiggler_the_crazed") { }
+ boss_kiggler_the_crazed(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- struct boss_kiggler_the_crazedAI : public ScriptedAI
+ void Reset() override
{
- boss_kiggler_the_crazedAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- GreaterPolymorph_Timer = 5000;
- LightningBolt_Timer = 10000;
- ArcaneShock_Timer = 20000;
- ArcaneExplosion_Timer = 30000;
- }
-
- uint32 GreaterPolymorph_Timer;
- uint32 LightningBolt_Timer;
- uint32 ArcaneShock_Timer;
- uint32 ArcaneExplosion_Timer;
+ _scheduler.CancelAll();
+ }
- InstanceScript* instance;
+ void AttackStart(Unit* who) override
+ {
+ ScriptedAI::AttackStartCaster(who, 40.0f);
+ }
- void Reset() override
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _scheduler.Schedule(5s, [this](TaskContext task)
{
- Initialize();
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_GREATER_POLYMORPH);
+ task.Repeat(15s, 20s);
+ });
- instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- DoZoneInCombat();
- instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
- }
+ DoCastVictim(SPELL_LIGHTNING_BOLT);
+ task.Repeat(2s);
+ });
- void JustDied(Unit* /*killer*/) override
+ _scheduler.Schedule(20s, [this](TaskContext task)
{
- if (Creature* maulgar = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MAULGAR)))
- maulgar->AI()->DoAction(ACTION_ADD_DEATH);
-
- instance->SetBossState(DATA_MAULGAR, DONE);
- }
+ DoCastVictim(SPELL_ARCANE_SHOCK);
+ task.Repeat(20s);
+ });
- void UpdateAI(uint32 diff) override
+ _scheduler.Schedule(30s, [this](TaskContext task)
{
- if (!UpdateVictim())
- return;
-
- //GreaterPolymorph_Timer
- if (GreaterPolymorph_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- DoCast(target, SPELL_GREATER_POLYMORPH);
+ DoCastSelf(SPELL_ARCANE_EXPLOSION);
+ task.Repeat(30s);
+ });
+ }
- GreaterPolymorph_Timer = urand(15000, 20000);
- } else GreaterPolymorph_Timer -= diff;
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
+ maulgar->AI()->DoAction(ACTION_ADD_DEATH);
- //LightningBolt_Timer
- if (LightningBolt_Timer <= diff)
- {
- DoCastVictim(SPELL_LIGHTNING_BOLT);
- LightningBolt_Timer = 15000;
- } else LightningBolt_Timer -= diff;
+ _instance->SetBossState(DATA_MAULGAR, DONE);
+ }
- //ArcaneShock_Timer
- if (ArcaneShock_Timer <= diff)
- {
- DoCastVictim(SPELL_ARCANE_SHOCK);
- ArcaneShock_Timer = 20000;
- } else ArcaneShock_Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- //ArcaneExplosion_Timer
- if (ArcaneExplosion_Timer <= diff)
- {
- DoCastVictim(SPELL_ARCANE_EXPLOSION);
- ArcaneExplosion_Timer = 30000;
- } else ArcaneExplosion_Timer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- DoMeleeAttackIfReady();
- }
- };
+ _scheduler.Update(diff);
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetGruulsLairAI<boss_kiggler_the_crazedAI>(creature);
+ DoMeleeAttackIfReady();
}
+
+private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
-class boss_blindeye_the_seer : public CreatureScript
+// 18836 - Blindeye the Seer
+struct boss_blindeye_the_seer : public ScriptedAI
{
-public:
- boss_blindeye_the_seer() : CreatureScript("boss_blindeye_the_seer") { }
+ boss_blindeye_the_seer(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- struct boss_blindeye_the_seerAI : public ScriptedAI
+ void Reset() override
{
- boss_blindeye_the_seerAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
+ _scheduler.CancelAll();
+ }
- void Initialize()
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _scheduler.Schedule(5s, [this](TaskContext task)
{
- GreaterPowerWordShield_Timer = 5000;
- Heal_Timer = urand(25000, 40000);
- PrayerofHealing_Timer = urand(45000, 55000);
- }
-
- uint32 GreaterPowerWordShield_Timer;
- uint32 Heal_Timer;
- uint32 PrayerofHealing_Timer;
-
- InstanceScript* instance;
+ DoCastSelf(SPELL_GREATER_PW_SHIELD);
+ task.Repeat(40s);
+ });
- void Reset() override
+ _scheduler.Schedule(25s, 40s, [this](TaskContext task)
{
- Initialize();
+ DoCastSelf(SPELL_HEAL);
+ task.Repeat(25s, 40s);
+ });
- instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
+ _scheduler.Schedule(45s, 55s, [this](TaskContext task)
{
- DoZoneInCombat();
- instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (Creature* maulgar = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MAULGAR)))
- maulgar->AI()->DoAction(ACTION_ADD_DEATH);
+ DoCastSelf(SPELL_PRAYER_OH);
+ task.Repeat(35s, 50s);
+ });
+ }
- instance->SetBossState(DATA_MAULGAR, DONE);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
+ maulgar->AI()->DoAction(ACTION_ADD_DEATH);
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ _instance->SetBossState(DATA_MAULGAR, DONE);
+ }
- //GreaterPowerWordShield_Timer
- if (GreaterPowerWordShield_Timer <= diff)
- {
- DoCast(me, SPELL_GREATER_PW_SHIELD);
- GreaterPowerWordShield_Timer = 40000;
- } else GreaterPowerWordShield_Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- //Heal_Timer
- if (Heal_Timer <= diff)
- {
- DoCast(me, SPELL_HEAL);
- Heal_Timer = urand(15000, 40000);
- } else Heal_Timer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- //PrayerofHealing_Timer
- if (PrayerofHealing_Timer <= diff)
- {
- DoCast(me, SPELL_PRAYER_OH);
- PrayerofHealing_Timer = urand(35000, 50000);
- } else PrayerofHealing_Timer -= diff;
+ _scheduler.Update(diff);
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetGruulsLairAI<boss_blindeye_the_seerAI>(creature);
+ DoMeleeAttackIfReady();
}
+
+private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
-class boss_krosh_firehand : public CreatureScript
+// 18832 - Krosh Firehand
+struct boss_krosh_firehand : public ScriptedAI
{
-public:
- boss_krosh_firehand() : CreatureScript("boss_krosh_firehand") { }
+ boss_krosh_firehand(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
- struct boss_krosh_firehandAI : public ScriptedAI
+ void Reset() override
{
- boss_krosh_firehandAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- }
-
- void Initialize()
- {
- GreaterFireball_Timer = 1000;
- SpellShield_Timer = 5000;
- BlastWave_Timer = 20000;
- }
-
- uint32 GreaterFireball_Timer;
- uint32 SpellShield_Timer;
- uint32 BlastWave_Timer;
-
- InstanceScript* instance;
+ _scheduler.CancelAll();
+ }
- void Reset() override
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ _scheduler.Schedule(0s, 5s, [this](TaskContext task)
{
- Initialize();
-
- instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
- }
+ DoCastVictim(SPELL_GREATER_FIREBALL);
+ task.Repeat(2s, 5s);
+ });
- void JustEngagedWith(Unit* /*who*/) override
+ _scheduler.Schedule(0s, [this](TaskContext task)
{
- DoZoneInCombat();
- instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
- }
+ DoCastSelf(SPELL_SPELLSHIELD);
+ task.Repeat(30s);
+ });
- void JustDied(Unit* /*killer*/) override
+ _scheduler.Schedule(10s, 20s, [this](TaskContext task)
{
- if (Creature* maulgar = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MAULGAR)))
- maulgar->AI()->DoAction(ACTION_ADD_DEATH);
+ DoCastSelf(SPELL_BLAST_WAVE);
+ task.Repeat(5s, 15s);
+ });
+ }
- instance->SetBossState(DATA_MAULGAR, DONE);
- }
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
+ maulgar->AI()->DoAction(ACTION_ADD_DEATH);
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
+ _instance->SetBossState(DATA_MAULGAR, DONE);
+ }
- //GreaterFireball_Timer
- if (GreaterFireball_Timer < diff || me->IsWithinDist(me->GetVictim(), 30))
- {
- DoCastVictim(SPELL_GREATER_FIREBALL);
- GreaterFireball_Timer = 2000;
- } else GreaterFireball_Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
- //SpellShield_Timer
- if (SpellShield_Timer <= diff)
- {
- me->InterruptNonMeleeSpells(false);
- DoCastVictim(SPELL_SPELLSHIELD);
- SpellShield_Timer = 30000;
- } else SpellShield_Timer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- //BlastWave_Timer
- if (BlastWave_Timer <= diff)
- {
- std::vector<Unit*> target_list;
- for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
- {
- Unit* target = ref->GetVictim();
- if (target && target->IsWithinDist(me, 15, false)) // 15 yard radius minimum
- target_list.push_back(target);
- }
- Unit* target = nullptr;
- if (!target_list.empty())
- target = *(target_list.begin() + rand32() % target_list.size());
-
- me->InterruptNonMeleeSpells(false);
- DoCast(target, SPELL_BLAST_WAVE);
- BlastWave_Timer = 60000;
- } else BlastWave_Timer -= diff;
- }
- };
+ _scheduler.Update(diff);
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetGruulsLairAI<boss_krosh_firehandAI>(creature);
+ DoMeleeAttackIfReady();
}
+
+private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
};
void AddSC_boss_high_king_maulgar()
{
- new boss_high_king_maulgar();
- new boss_kiggler_the_crazed();
- new boss_blindeye_the_seer();
- new boss_olm_the_summoner();
- new boss_krosh_firehand();
+ RegisterGruulsLairCreatureAI(boss_high_king_maulgar);
+ RegisterGruulsLairCreatureAI(boss_kiggler_the_crazed);
+ RegisterGruulsLairCreatureAI(boss_blindeye_the_seer);
+ RegisterGruulsLairCreatureAI(boss_olm_the_summoner);
+ RegisterGruulsLairCreatureAI(boss_krosh_firehand);
}
diff --git a/src/server/scripts/Outland/GruulsLair/gruuls_lair.h b/src/server/scripts/Outland/GruulsLair/gruuls_lair.h
index 79ef246f518..dfe95fb9db2 100644
--- a/src/server/scripts/Outland/GruulsLair/gruuls_lair.h
+++ b/src/server/scripts/Outland/GruulsLair/gruuls_lair.h
@@ -53,4 +53,6 @@ inline AI* GetGruulsLairAI(T* obj)
return GetInstanceAI<AI>(obj, GLScriptName);
}
+#define RegisterGruulsLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetGruulsLairAI)
+
#endif // GRUULS_LAIR_H_