From 3d9a55996d9b42c676db924254e608fc3f2e5cc8 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Sun, 12 Feb 2023 14:14:15 +0100 Subject: [PATCH] fix(Scripts/GruulsLair): Fixed Ground Slam. (#14780) Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> --- .../rev_1674905348348106300.sql | 8 + .../scripts/Outland/GruulsLair/boss_gruul.cpp | 415 ++++++++++-------- 2 files changed, 230 insertions(+), 193 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1674905348348106300.sql diff --git a/data/sql/updates/pending_db_world/rev_1674905348348106300.sql b/data/sql/updates/pending_db_world/rev_1674905348348106300.sql new file mode 100644 index 000000000..3269953f1 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1674905348348106300.sql @@ -0,0 +1,8 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id`=33496; +INSERT INTO `spell_script_names` VALUES +(33496,'spell_tractor_beam_creator'); + +UPDATE `spell_dbc` SET `Effect_1`=28, `EffectMiscValueB_1`=64 WHERE `ID` IN (33495,33514,33515,33516,33517,33518,33519,33520); + +UPDATE `creature_template` SET `ScriptName`='npc_invisible_tractor_beam_source' WHERE `entry`=19198; diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp index f9c387a64..9458e8bde 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp @@ -19,6 +19,7 @@ #include "ScriptedCreature.h" #include "SpellScript.h" #include "gruuls_lair.h" +#include "PassiveAI.h" enum Yells { @@ -33,15 +34,28 @@ enum Yells enum Spells { - SPELL_GROWTH = 36300, - SPELL_CAVE_IN = 36240, - SPELL_GROUND_SLAM = 33525, - SPELL_REVERBERATION = 36297, - SPELL_HURTFUL_STRIKE = 33813, - SPELL_SHATTER = 33654, + SPELL_GROWTH = 36300, + SPELL_CAVE_IN = 36240, + SPELL_GROUND_SLAM = 33525, + SPELL_REVERBERATION = 36297, + SPELL_HURTFUL_STRIKE = 33813, + SPELL_SHATTER = 33654, + SPELL_LOOK_AROUND = 33965, - SPELL_SHATTER_EFFECT = 33671, - SPELL_STONED = 33652, + // Ground Slam spells + SPELL_SUMMON_TRACTOR_BEAM_CREATOR = 33496, + SPELL_TRACTOR_BEAM_PULL = 33497, + SPELL_SUMMON_TRACTOR_BEAM_1 = 33495, + SPELL_SUMMON_TRACTOR_BEAM_2 = 33514, + SPELL_SUMMON_TRACTOR_BEAM_3 = 33515, + SPELL_SUMMON_TRACTOR_BEAM_4 = 33516, + SPELL_SUMMON_TRACTOR_BEAM_5 = 33517, + SPELL_SUMMON_TRACTOR_BEAM_6 = 33518, + SPELL_SUMMON_TRACTOR_BEAM_7 = 33519, + SPELL_SUMMON_TRACTOR_BEAM_8 = 33520, + + SPELL_SHATTER_EFFECT = 33671, + SPELL_STONED = 33652, }; enum Events @@ -55,241 +69,256 @@ enum Events EVENT_RECENTLY_SPOKEN = 7 }; -class boss_gruul : public CreatureScript +struct boss_gruul : public BossAI { -public: - boss_gruul() : CreatureScript("boss_gruul") { } + boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { } - struct boss_gruulAI : public BossAI + void Reset() override { - boss_gruulAI(Creature* creature) : BossAI(creature, DATA_GRUUL) { } + _Reset(); + _caveInTimer = 29000; + } - void Reset() override - { - _Reset(); - _caveInTimer = 29000; - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - Talk(SAY_AGGRO); - - events.ScheduleEvent(EVENT_GROWTH, 30000); - events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); - events.ScheduleEvent(EVENT_REVERBERATION, 20000); - events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 10000); - events.ScheduleEvent(EVENT_GROUND_SLAM, 35000); - } - - void KilledUnit(Unit* /*who*/) override - { - if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0) - { - events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5000); - Talk(SAY_SLAY); - } - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - Talk(SAY_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_GROWTH: - Talk(EMOTE_GROW); - DoCast(me, SPELL_GROWTH); - events.ScheduleEvent(EVENT_GROWTH, 30000); - break; - case EVENT_CAVE_IN: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CAVE_IN, false); - if (_caveInTimer >= 4000) - _caveInTimer -= 1500; - events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); - break; - case EVENT_REVERBERATION: - me->CastSpell(me, SPELL_REVERBERATION, false); - events.ScheduleEvent(EVENT_REVERBERATION, 22000); - break; - case EVENT_HURTFUL_STRIKE: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f)) - { - me->CastSpell(target, SPELL_HURTFUL_STRIKE, false); - } - else - { - me->CastSpell(me->GetVictim(), SPELL_HURTFUL_STRIKE, false); - } - events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 15000); - break; - case EVENT_GROUND_SLAM: - Talk(SAY_SLAM); - me->CastSpell(me, SPELL_GROUND_SLAM, false); - events.DelayEvents(8001); - events.ScheduleEvent(EVENT_GROUND_SLAM, 60000); - events.ScheduleEvent(EVENT_SHATTER, 8000); - me->SetControlled(true, UNIT_STATE_ROOT); - break; - case EVENT_SHATTER: - Talk(SAY_SHATTER); - me->SetControlled(false, UNIT_STATE_ROOT); - me->CastSpell(me, SPELL_SHATTER, false); - break; - } - - if (!me->HasUnitState(UNIT_STATE_ROOT)) - { - DoMeleeAttackIfReady(); - } - } - - private: - uint32 _caveInTimer; - }; - - CreatureAI* GetAI(Creature* creature) const override + void EnterCombat(Unit* /*who*/) override { - return GetGruulsLairAI(creature); + _EnterCombat(); + Talk(SAY_AGGRO); + + events.ScheduleEvent(EVENT_GROWTH, 30000); + events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); + events.ScheduleEvent(EVENT_REVERBERATION, 20000); + events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 10000); + events.ScheduleEvent(EVENT_GROUND_SLAM, 35000); + } + + void KilledUnit(Unit* /*who*/) override + { + if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0) + { + events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5000); + Talk(SAY_SLAY); + } + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_DEATH); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_GROWTH: + Talk(EMOTE_GROW); + DoCast(me, SPELL_GROWTH); + events.ScheduleEvent(EVENT_GROWTH, 30000); + break; + case EVENT_CAVE_IN: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_CAVE_IN, false); + if (_caveInTimer >= 4000) + _caveInTimer -= 1500; + events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer); + break; + case EVENT_REVERBERATION: + me->CastSpell(me, SPELL_REVERBERATION, false); + events.ScheduleEvent(EVENT_REVERBERATION, 22000); + break; + case EVENT_HURTFUL_STRIKE: + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f)) + { + me->CastSpell(target, SPELL_HURTFUL_STRIKE, false); + } + else + { + me->CastSpell(me->GetVictim(), SPELL_HURTFUL_STRIKE, false); + } + events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 15000); + break; + case EVENT_GROUND_SLAM: + Talk(SAY_SLAM); + me->CastSpell(me, SPELL_GROUND_SLAM, false); + events.DelayEvents(8001); + events.ScheduleEvent(EVENT_GROUND_SLAM, 60000); + events.ScheduleEvent(EVENT_SHATTER, 8000); + break; + case EVENT_SHATTER: + Talk(SAY_SHATTER); + me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND); + me->CastSpell(me, SPELL_SHATTER, false); + break; + } + + if (!me->HasUnitState(UNIT_STATE_ROOT)) + { + DoMeleeAttackIfReady(); + } + } + +private: + uint32 _caveInTimer; +}; + +struct npc_invisible_tractor_beam_source : public NullCreatureAI +{ + npc_invisible_tractor_beam_source(Creature* creature) : NullCreatureAI(creature) { } + + void IsSummonedBy(WorldObject* summoner) override + { + if (Unit* summonerUnit = summoner->ToUnit()) + { + DoCast(summonerUnit, SPELL_TRACTOR_BEAM_PULL, true); + } } }; -class spell_gruul_ground_slam : public SpellScriptLoader +class spell_gruul_ground_slam : public SpellScript { -public: - spell_gruul_ground_slam() : SpellScriptLoader("spell_gruul_ground_slam") { } + PrepareSpellScript(spell_gruul_ground_slam); - class spell_gruul_ground_slam_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spellInfo*/) override { - PrepareSpellScript(spell_gruul_ground_slam_SpellScript); + return ValidateSpellInfo({ SPELL_SUMMON_TRACTOR_BEAM_CREATOR }); + } - void HandleScriptEffect(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - target->KnockbackFrom(GetCaster()->GetPositionX(), GetCaster()->GetPositionY(), 15.0f, 15.0f); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_gruul_ground_slam_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override + void ApplyStun() { - return new spell_gruul_ground_slam_SpellScript(); + if (Unit* caster = GetCaster()) + { + caster->CastSpell(caster, SPELL_LOOK_AROUND, true); + } + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_SUMMON_TRACTOR_BEAM_CREATOR, true); + } + } + + void Register() override + { + AfterCast += SpellCastFn(spell_gruul_ground_slam::ApplyStun); + OnEffectHitTarget += SpellEffectFn(spell_gruul_ground_slam::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; -class spell_gruul_ground_slam_trigger : public SpellScriptLoader +class spell_tractor_beam_creator : public SpellScript { -public: - spell_gruul_ground_slam_trigger() : SpellScriptLoader("spell_gruul_ground_slam_trigger") { } + PrepareSpellScript(spell_tractor_beam_creator); - class spell_gruul_ground_slam_trigger_AuraScript : public AuraScript + void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - PrepareAuraScript(spell_gruul_ground_slam_trigger_AuraScript); - - void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + if (Unit* caster = GetCaster()) { - if (GetUnitOwner()->GetAuraCount(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell) == 5) - GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_STONED, true); + std::vector tractorBeamSummons = { SPELL_SUMMON_TRACTOR_BEAM_1, SPELL_SUMMON_TRACTOR_BEAM_2, SPELL_SUMMON_TRACTOR_BEAM_3, SPELL_SUMMON_TRACTOR_BEAM_4, + SPELL_SUMMON_TRACTOR_BEAM_5, SPELL_SUMMON_TRACTOR_BEAM_6, SPELL_SUMMON_TRACTOR_BEAM_7, SPELL_SUMMON_TRACTOR_BEAM_8 }; + uint32 randomTractorSpellID = Acore::Containers::SelectRandomContainerElement(tractorBeamSummons); + caster->CastSpell(caster, randomTractorSpellID, true); } + } - void Register() override - { - AfterEffectRemove += AuraEffectRemoveFn(spell_gruul_ground_slam_trigger_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_gruul_ground_slam_trigger_AuraScript(); + OnEffectHitTarget += SpellEffectFn(spell_tractor_beam_creator::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; -class spell_gruul_shatter : public SpellScriptLoader +class spell_gruul_ground_slam_trigger : public AuraScript { -public: - spell_gruul_shatter() : SpellScriptLoader("spell_gruul_shatter") { } + PrepareAuraScript(spell_gruul_ground_slam_trigger); - class spell_gruul_shatter_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spellInfo*/) override { - PrepareSpellScript(spell_gruul_shatter_SpellScript); + return ValidateSpellInfo({ SPELL_STONED }); + } - void HandleScriptEffect(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - { - target->RemoveAurasDueToSpell(SPELL_STONED); - target->CastSpell((Unit*)nullptr, SPELL_SHATTER_EFFECT, true); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override + void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - return new spell_gruul_shatter_SpellScript(); + if (GetUnitOwner()->GetAuraCount(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell) == 5) + { + GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_STONED, true); + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_gruul_ground_slam_trigger::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); } }; -class spell_gruul_shatter_effect : public SpellScriptLoader +class spell_gruul_shatter : public SpellScript { -public: - spell_gruul_shatter_effect() : SpellScriptLoader("spell_gruul_shatter_effect") { } + PrepareSpellScript(spell_gruul_shatter); - class spell_gruul_shatter_effect_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spellInfo*/) override { - PrepareSpellScript(spell_gruul_shatter_effect_SpellScript); + return ValidateSpellInfo({ SPELL_SHATTER_EFFECT }); + } - void CalculateDamage() + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) { - if (!GetHitUnit()) - return; + target->RemoveAurasDueToSpell(SPELL_STONED); + target->CastSpell((Unit*)nullptr, SPELL_SHATTER_EFFECT, true); + } + } - float radius = GetSpellInfo()->Effects[EFFECT_0].CalcRadius(GetCaster()); - if (!radius) - return; + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; - float distance = GetCaster()->GetDistance2d(GetHitUnit()); - if (distance > 1.0f) - SetHitDamage(int32(GetHitDamage() * ((radius - distance) / radius))); +class spell_gruul_shatter_effect : public SpellScript +{ + PrepareSpellScript(spell_gruul_shatter_effect); + + void CalculateDamage() + { + if (!GetHitUnit()) + { + return; } - void Register() override + float radius = GetSpellInfo()->Effects[EFFECT_0].CalcRadius(GetCaster()); + if (!radius) { - OnHit += SpellHitFn(spell_gruul_shatter_effect_SpellScript::CalculateDamage); + return; } - }; - SpellScript* GetSpellScript() const override + float distance = GetCaster()->GetDistance2d(GetHitUnit()); + if (distance > 1.0f) + { + SetHitDamage(int32(GetHitDamage() * ((radius - distance) / radius))); + } + } + + void Register() override { - return new spell_gruul_shatter_effect_SpellScript(); + OnHit += SpellHitFn(spell_gruul_shatter_effect::CalculateDamage); } }; void AddSC_boss_gruul() { - new boss_gruul(); - new spell_gruul_ground_slam(); - new spell_gruul_ground_slam_trigger(); - new spell_gruul_shatter(); - new spell_gruul_shatter_effect(); + RegisterGruulsLairAI(boss_gruul); + RegisterGruulsLairAI(npc_invisible_tractor_beam_source); + + RegisterSpellScript(spell_gruul_ground_slam); + RegisterSpellScript(spell_tractor_beam_creator); + RegisterSpellScript(spell_gruul_ground_slam_trigger); + RegisterSpellScript(spell_gruul_shatter); + RegisterSpellScript(spell_gruul_shatter_effect); }