Scripts/Gruul's Lair: Update scripts (#30913)
(cherry picked from commit a23262869685e66d68be233b9020d611ffdb5db0)
This commit is contained in:
@@ -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)");
|
||||
@@ -16,331 +16,286 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
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_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_SHATTER_EFFECT = 33671,
|
||||
SPELL_HURTFUL_STRIKE_PRIMER = 33812,
|
||||
SPELL_HURTFUL_STRIKE = 33813,
|
||||
SPELL_STONED = 33652, // Spell is self cast by target
|
||||
SPELL_CAVE_IN = 36240,
|
||||
SPELL_REVERBERATION = 36297,
|
||||
SPELL_GROWTH = 36300,
|
||||
|
||||
SPELL_MAGNETIC_PULL = 28337,
|
||||
SPELL_KNOCK_BACK = 24199, // Knockback spell until correct implementation is made
|
||||
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_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);
|
||||
}
|
||||
|
||||
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, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
|
||||
.SetOriginalCaster(me->GetGUID()));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
target->CastSpell(target, SPELL_KNOCK_BACK, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
|
||||
.SetOriginalCaster(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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_gruulAI>(creature);
|
||||
}
|
||||
SOUND_ID_DEATH = 11363
|
||||
};
|
||||
|
||||
class spell_gruul_shatter : public SpellScriptLoader
|
||||
// 19044 - Gruul the Dragonkiller
|
||||
struct boss_gruul : public BossAI
|
||||
{
|
||||
public:
|
||||
spell_gruul_shatter() : SpellScriptLoader("spell_gruul_shatter") { }
|
||||
boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { }
|
||||
|
||||
class spell_gruul_shatter_SpellScript : public SpellScript
|
||||
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)
|
||||
{
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_STONED, SPELL_SHATTER_EFFECT });
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
target->RemoveAurasDueToSpell(SPELL_STONED);
|
||||
target->CastSpell(nullptr, SPELL_SHATTER_EFFECT, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_gruul_shatter_SpellScript();
|
||||
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_effect : public SpellScriptLoader
|
||||
// 33812 - Hurtful Strike Primer
|
||||
class spell_gruul_hurtful_strike_primer : public SpellScript
|
||||
{
|
||||
public:
|
||||
spell_gruul_shatter_effect() : SpellScriptLoader("spell_gruul_shatter_effect") { }
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
class spell_gruul_shatter_effect_SpellScript : public SpellScript
|
||||
// First we get rid of all targets that are not within melee range
|
||||
targets.remove_if([&](WorldObject* target)
|
||||
{
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } });
|
||||
}
|
||||
if (Unit* unit = target->ToUnit())
|
||||
return !unit->IsWithinMeleeRange(caster);
|
||||
|
||||
void CalculateDamage()
|
||||
{
|
||||
if (!GetHitUnit())
|
||||
return;
|
||||
return true;
|
||||
});
|
||||
|
||||
float radius = GetEffectInfo(EFFECT_0).CalcRadius(GetCaster(), SpellTargetIndex::TargetB).Max;
|
||||
if (radius <= 0.0f)
|
||||
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_SpellScript::CalculateDamage);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
if (targets.size() >= 2)
|
||||
{
|
||||
return new spell_gruul_shatter_effect_SpellScript();
|
||||
// Now we sort all targets by threat
|
||||
targets.sort([&](WorldObject const* left, WorldObject const* right)
|
||||
{
|
||||
Unit const* leftTarget = ASSERT_NOTNULL(left->ToUnit());
|
||||
Unit const* rightTarget = ASSERT_NOTNULL(right->ToUnit());
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 33525 - Ground Slam
|
||||
class spell_gruul_ground_slam : public SpellScript
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 33965 - Look Around
|
||||
class spell_gruul_look_around : public AuraScript
|
||||
{
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_SHATTER });
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_gruul_look_around::AfterRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
// 33654 - Shatter
|
||||
class spell_gruul_shatter : public SpellScript
|
||||
{
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 33671 - Shatter
|
||||
class spell_gruul_shatter_effect : public SpellScript
|
||||
{
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return ValidateSpellEffect({ { spellInfo->Id, EFFECT_0 } });
|
||||
}
|
||||
|
||||
void CalculateDamage()
|
||||
{
|
||||
if (!GetHitUnit())
|
||||
return;
|
||||
|
||||
float radius = GetEffectInfo(EFFECT_0).CalcRadius(GetCaster(), SpellTargetIndex::TargetB).Max;
|
||||
if (radius <= 0.0f)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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,515 +64,349 @@ 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)
|
||||
_Reset();
|
||||
_enraged = false;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
scheduler.Schedule(10s, [this](TaskContext& task)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
DoCastVictim(SPELL_ARCING_SMASH);
|
||||
task.Repeat(10s);
|
||||
});
|
||||
|
||||
void Initialize()
|
||||
scheduler.Schedule(30s, [this](TaskContext& task)
|
||||
{
|
||||
ArcingSmash_Timer = 10000;
|
||||
MightyBlow_Timer = 40000;
|
||||
Whirlwind_Timer = 30000;
|
||||
Charging_Timer = 0;
|
||||
Roar_Timer = 0;
|
||||
DoCastSelf(SPELL_WHIRLWIND);
|
||||
task.Repeat(55s);
|
||||
});
|
||||
|
||||
Phase2 = false;
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
uint32 ArcingSmash_Timer;
|
||||
uint32 MightyBlow_Timer;
|
||||
uint32 Whirlwind_Timer;
|
||||
uint32 Charging_Timer;
|
||||
uint32 Roar_Timer;
|
||||
|
||||
bool Phase2;
|
||||
|
||||
void Reset() override
|
||||
scheduler.Schedule(40s, [this](TaskContext& task)
|
||||
{
|
||||
Initialize();
|
||||
DoCastVictim(SPELL_MIGHTY_BLOW);
|
||||
task.Repeat(30s, 40s);
|
||||
});
|
||||
}
|
||||
|
||||
DoCast(me, SPELL_DUAL_WIELD, false);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (!_enraged && me->HealthBelowPctDamaged(50, damage))
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (actionId == ACTION_ADD_DEATH)
|
||||
Talk(SAY_OGRE_DEATH);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
DoZoneInCombat();
|
||||
instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//ArcingSmash_Timer
|
||||
if (ArcingSmash_Timer <= diff)
|
||||
scheduler.Schedule(0s, [this](TaskContext const& /*task*/)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (Phase2)
|
||||
scheduler.Schedule(0s, 5s, [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;
|
||||
DoCastSelf(SPELL_ROAR);
|
||||
task.Repeat(40s, 50s);
|
||||
});
|
||||
|
||||
//Intimidating Roar
|
||||
if (Roar_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_ROAR);
|
||||
Roar_Timer = 40000 + (rand32() % 10000);
|
||||
} else Roar_Timer -= diff;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_high_king_maulgarAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_olm_the_summoner : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_olm_the_summoner() : CreatureScript("boss_olm_the_summoner") { }
|
||||
|
||||
struct boss_olm_the_summonerAI : public ScriptedAI
|
||||
{
|
||||
boss_olm_the_summonerAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
DarkDecay_Timer = 10000;
|
||||
Summon_Timer = 15000;
|
||||
DeathCoil_Timer = 20000;
|
||||
}
|
||||
|
||||
uint32 DarkDecay_Timer;
|
||||
uint32 Summon_Timer;
|
||||
uint32 DeathCoil_Timer;
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
AddThreat(who, 0.0f);
|
||||
me->SetInCombatWith(who);
|
||||
who->SetInCombatWith(me);
|
||||
|
||||
me->GetMotionMaster()->MoveChase(who, 30.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
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);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//DarkDecay_Timer
|
||||
if (DarkDecay_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_DARK_DECAY);
|
||||
DarkDecay_Timer = 20000;
|
||||
} else DarkDecay_Timer -= diff;
|
||||
|
||||
//Summon_Timer
|
||||
if (Summon_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_WFH);
|
||||
Summon_Timer = 30000;
|
||||
} else Summon_Timer -= diff;
|
||||
|
||||
//DeathCoil Timer /need correct timer
|
||||
if (DeathCoil_Timer <= diff)
|
||||
scheduler.Schedule(10s, 15s, [this](TaskContext& task)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_DEATH_COIL);
|
||||
DeathCoil_Timer = 20000;
|
||||
} else DeathCoil_Timer -= diff;
|
||||
DoCast(target, SPELL_BERSERKER_CHARGE);
|
||||
task.Repeat(20s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_olm_the_summonerAI>(creature);
|
||||
}
|
||||
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
return;
|
||||
|
||||
if (actionId == ACTION_ADD_DEATH)
|
||||
Talk(SAY_OGRE_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _enraged;
|
||||
};
|
||||
|
||||
//Kiggler The Crazed AI
|
||||
class boss_kiggler_the_crazed : public CreatureScript
|
||||
// 18834 - Olm the Summoner
|
||||
struct boss_olm_the_summoner : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_kiggler_the_crazed() : CreatureScript("boss_kiggler_the_crazed") { }
|
||||
boss_olm_the_summoner(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;
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
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);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//GreaterPolymorph_Timer
|
||||
if (GreaterPolymorph_Timer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_GREATER_POLYMORPH);
|
||||
|
||||
GreaterPolymorph_Timer = urand(15000, 20000);
|
||||
} else GreaterPolymorph_Timer -= diff;
|
||||
|
||||
//LightningBolt_Timer
|
||||
if (LightningBolt_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_LIGHTNING_BOLT);
|
||||
LightningBolt_Timer = 15000;
|
||||
} else LightningBolt_Timer -= diff;
|
||||
|
||||
//ArcaneShock_Timer
|
||||
if (ArcaneShock_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_ARCANE_SHOCK);
|
||||
ArcaneShock_Timer = 20000;
|
||||
} else ArcaneShock_Timer -= diff;
|
||||
|
||||
//ArcaneExplosion_Timer
|
||||
if (ArcaneExplosion_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_ARCANE_EXPLOSION);
|
||||
ArcaneExplosion_Timer = 30000;
|
||||
} else ArcaneExplosion_Timer -= diff;
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_kiggler_the_crazedAI>(creature);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(10s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastVictim(SPELL_DARK_DECAY);
|
||||
task.Repeat(20s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(0s, 10s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_WILD_FELHUNTER);
|
||||
task.Repeat(50s, 60s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(20s, [this](TaskContext& task)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_DEATH_COIL);
|
||||
task.Repeat(20s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
|
||||
maulgar->AI()->DoAction(ACTION_ADD_DEATH);
|
||||
|
||||
_instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
class boss_blindeye_the_seer : public CreatureScript
|
||||
// 18835 - Kiggler the Crazed
|
||||
struct boss_kiggler_the_crazed : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_blindeye_the_seer() : CreatureScript("boss_blindeye_the_seer") { }
|
||||
boss_kiggler_the_crazed(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();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
GreaterPowerWordShield_Timer = 5000;
|
||||
Heal_Timer = urand(25000, 40000);
|
||||
PrayerofHealing_Timer = urand(45000, 55000);
|
||||
}
|
||||
|
||||
uint32 GreaterPowerWordShield_Timer;
|
||||
uint32 Heal_Timer;
|
||||
uint32 PrayerofHealing_Timer;
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
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);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//GreaterPowerWordShield_Timer
|
||||
if (GreaterPowerWordShield_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_GREATER_PW_SHIELD);
|
||||
GreaterPowerWordShield_Timer = 40000;
|
||||
} else GreaterPowerWordShield_Timer -= diff;
|
||||
|
||||
//Heal_Timer
|
||||
if (Heal_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_HEAL);
|
||||
Heal_Timer = urand(15000, 40000);
|
||||
} else Heal_Timer -= diff;
|
||||
|
||||
//PrayerofHealing_Timer
|
||||
if (PrayerofHealing_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_PRAYER_OH);
|
||||
PrayerofHealing_Timer = urand(35000, 50000);
|
||||
} else PrayerofHealing_Timer -= diff;
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_blindeye_the_seerAI>(creature);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
ScriptedAI::AttackStartCaster(who, 40.0f);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(5s, [this](TaskContext& task)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_GREATER_POLYMORPH);
|
||||
task.Repeat(15s, 20s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(0s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastVictim(SPELL_LIGHTNING_BOLT);
|
||||
task.Repeat(2s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(20s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastVictim(SPELL_ARCANE_SHOCK);
|
||||
task.Repeat(20s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(30s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_ARCANE_EXPLOSION);
|
||||
task.Repeat(30s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
|
||||
maulgar->AI()->DoAction(ACTION_ADD_DEATH);
|
||||
|
||||
_instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
class boss_krosh_firehand : public CreatureScript
|
||||
// 18836 - Blindeye the Seer
|
||||
struct boss_blindeye_the_seer : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_krosh_firehand() : CreatureScript("boss_krosh_firehand") { }
|
||||
boss_blindeye_the_seer(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;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
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);
|
||||
|
||||
instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//GreaterFireball_Timer
|
||||
if (GreaterFireball_Timer < diff || me->IsWithinDist(me->GetVictim(), 30))
|
||||
{
|
||||
DoCastVictim(SPELL_GREATER_FIREBALL);
|
||||
GreaterFireball_Timer = 2000;
|
||||
} else GreaterFireball_Timer -= diff;
|
||||
|
||||
//SpellShield_Timer
|
||||
if (SpellShield_Timer <= diff)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
DoCastVictim(SPELL_SPELLSHIELD);
|
||||
SpellShield_Timer = 30000;
|
||||
} else SpellShield_Timer -= diff;
|
||||
|
||||
//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;
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetGruulsLairAI<boss_krosh_firehandAI>(creature);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(5s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_GREATER_PW_SHIELD);
|
||||
task.Repeat(40s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(25s, 40s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_HEAL);
|
||||
task.Repeat(25s, 40s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(45s, 55s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_PRAYER_OH);
|
||||
task.Repeat(35s, 50s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
|
||||
maulgar->AI()->DoAction(ACTION_ADD_DEATH);
|
||||
|
||||
_instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
// 18832 - Krosh Firehand
|
||||
struct boss_krosh_firehand : public ScriptedAI
|
||||
{
|
||||
boss_krosh_firehand(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(0s, 5s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastVictim(SPELL_GREATER_FIREBALL);
|
||||
task.Repeat(2s, 5s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(0s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_SPELLSHIELD);
|
||||
task.Repeat(30s);
|
||||
});
|
||||
|
||||
_scheduler.Schedule(10s, 20s, [this](TaskContext& task)
|
||||
{
|
||||
DoCastSelf(SPELL_BLAST_WAVE);
|
||||
task.Repeat(5s, 15s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* maulgar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_MAULGAR)))
|
||||
maulgar->AI()->DoAction(ACTION_ADD_DEATH);
|
||||
|
||||
_instance->SetBossState(DATA_MAULGAR, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
Reference in New Issue
Block a user