From 8e0b1ca286e11ccd1474895a5ded3ceae6b01403 Mon Sep 17 00:00:00 2001 From: Nefertumm Date: Fri, 3 Jun 2022 09:26:18 -0300 Subject: [PATCH] fix(Core/ZulGurub): more improvements to High Priestess Jeklik (#11604) * Fix(Core/ZulGurub): more improvements to High Priestess Jeklik * remove old comment * cancel phase one events on phase 2 * Update src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> * Update src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> * style * build Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> --- .../rev_1651544130927167200.sql | 8 + .../EasternKingdoms/ZulGurub/boss_jeklik.cpp | 385 +++++++++--------- 2 files changed, 209 insertions(+), 184 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1651544130927167200.sql diff --git a/data/sql/updates/pending_db_world/rev_1651544130927167200.sql b/data/sql/updates/pending_db_world/rev_1651544130927167200.sql new file mode 100644 index 000000000..4e19d94f6 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1651544130927167200.sql @@ -0,0 +1,8 @@ +-- +UPDATE `creature_template` SET `speed_run` = 1.14286, `speed_walk` = 1.32 WHERE `entry` = 14517; + +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_batrider_bomb'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(23970, 'spell_batrider_bomb'); + +UPDATE `gameobject_template` SET `Data2` = 6 WHERE `entry` = 180125; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp index b6075f954..ebb69ebee 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp @@ -15,8 +15,11 @@ * with this program. If not, see . */ +#include "GameObjectAI.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "TaskScheduler.h" #include "zulgurub.h" enum Says @@ -49,7 +52,8 @@ enum Spells SPELL_GREATER_HEAL = 23954, // Batriders Spell - SPELL_BOMB = 40332 // Wrong ID but Magmadars bomb is not working... + SPELL_THROW_LIQUID_FIRE = 23970, + SPELL_SUMMON_LIQUID_FIRE = 23971 }; enum BatIds @@ -93,214 +97,227 @@ Position const SpawnBat[6] = { -12293.6220f, -1380.2640f, 144.8304f, 5.483f } }; -class boss_jeklik : public CreatureScript +struct boss_jeklik : public BossAI { -public: - boss_jeklik() : CreatureScript("boss_jeklik") { } + boss_jeklik(Creature* creature) : BossAI(creature, DATA_JEKLIK) { } - struct boss_jeklikAI : public BossAI + void Reset() override { - boss_jeklikAI(Creature* creature) : BossAI(creature, DATA_JEKLIK) { } + DoCastSelf(SPELL_GREEN_CHANNELING); + me->SetHover(false); + me->SetDisableGravity(false); + _Reset(); + } - void Reset() override + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterEvadeMode(EvadeReason why) override + { + const Position homePos = me->GetHomePosition(); + me->NearTeleportTo(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation()); + BossAI::EnterEvadeMode(why); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + Talk(SAY_AGGRO); + me->RemoveAurasDueToSpell(SPELL_GREEN_CHANNELING); + me->SetHover(true); + me->SetDisableGravity(true); + me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); + DoCastSelf(SPELL_BAT_FORM); + events.SetPhase(PHASE_ONE); + + events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(10000, 20000), PHASE_ONE); + events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(5000, 15000), PHASE_ONE); + events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(5000, 15000), PHASE_ONE); + events.ScheduleEvent(EVENT_SONIC_BURST, urand(5000, 15000), PHASE_ONE); + events.ScheduleEvent(EVENT_SWOOP, 20000, PHASE_ONE); + events.ScheduleEvent(EVENT_SPAWN_BATS, 30000, PHASE_ONE); + } + + void DamageTaken(Unit* /*who*/, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(50)) { - DoCastSelf(SPELL_GREEN_CHANNELING); - _Reset(); + me->RemoveAurasDueToSpell(SPELL_BAT_FORM); + me->SetHover(false); + me->SetDisableGravity(false); + DoResetThreat(); + events.SetPhase(PHASE_TWO); + events.CancelEventGroup(PHASE_ONE); + + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(5000, 15000), PHASE_TWO); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(10000, 15000), PHASE_TWO); + events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(25000, 35000), PHASE_TWO); + events.ScheduleEvent(EVENT_MIND_FLAY, urand(10000, 30000), PHASE_TWO); + events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); + events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, 10000, PHASE_TWO); + + return; } + } - void JustDied(Unit* /*killer*/) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustDied(); - Talk(SAY_DEATH); - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - Talk(SAY_AGGRO); - me->RemoveAurasDueToSpell(SPELL_GREEN_CHANNELING); - me->SetDisableGravity(true); - DoCastSelf(SPELL_BAT_FORM); - events.SetPhase(PHASE_ONE); - - events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(10000, 20000), PHASE_ONE); - events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(5000, 15000), PHASE_ONE); - events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(5000, 15000), PHASE_ONE); - events.ScheduleEvent(EVENT_SONIC_BURST, urand(5000, 15000), PHASE_ONE); - events.ScheduleEvent(EVENT_SWOOP, 20000, PHASE_ONE); - events.ScheduleEvent(EVENT_SPAWN_BATS, 30000, PHASE_ONE); - } - - void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(50)) + switch (eventId) { - me->RemoveAurasDueToSpell(SPELL_BAT_FORM); - me->SetDisableGravity(false); - DoResetThreat(); - events.SetPhase(PHASE_TWO); - - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(5000, 15000), PHASE_TWO); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(10000, 15000), PHASE_TWO); - events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(25000, 35000), PHASE_TWO); - events.ScheduleEvent(EVENT_MIND_FLAY, urand(10000, 30000), PHASE_TWO); - events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); - events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, 10000, PHASE_TWO); - - return; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - // Phase one - case EVENT_CHARGE_JEKLIK: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - DoCast(target, SPELL_CHARGE); - AttackStart(target); - } - events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(15000, 30000), PHASE_ONE); - break; - case EVENT_PIERCE_ARMOR: - DoCastVictim(SPELL_PIERCE_ARMOR); - events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(20000, 30000), PHASE_ONE); - break; - case EVENT_BLOOD_LEECH: - DoCastVictim(SPELL_BLOOD_LEECH); - events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(10000, 20000), PHASE_ONE); - break; - case EVENT_SONIC_BURST: - DoCastVictim(SPELL_SONIC_BURST); - events.ScheduleEvent(EVENT_SONIC_BURST, urand(20000, 30000), PHASE_ONE); - break; - case EVENT_SWOOP: - DoCastVictim(SPELL_SWOOP); - events.ScheduleEvent(EVENT_SWOOP, urand(20000, 30000), PHASE_ONE); - break; - case EVENT_SPAWN_BATS: - Talk(EMOTE_SUMMON_BATS); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - for (uint8 i = 0; i < 6; ++i) - if (Creature* bat = me->SummonCreature(NPC_BLOODSEEKER_BAT, SpawnBat[i], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - bat->AI()->AttackStart(target); - events.ScheduleEvent(EVENT_SPAWN_BATS, 30000, PHASE_ONE); - break; + // Phase one + case EVENT_CHARGE_JEKLIK: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + DoCast(target, SPELL_CHARGE); + AttackStart(target); + } + events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(15000, 30000), PHASE_ONE); + break; + case EVENT_PIERCE_ARMOR: + DoCastVictim(SPELL_PIERCE_ARMOR); + events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(20000, 30000), PHASE_ONE); + break; + case EVENT_BLOOD_LEECH: + DoCastVictim(SPELL_BLOOD_LEECH); + events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(10000, 20000), PHASE_ONE); + break; + case EVENT_SONIC_BURST: + DoCastVictim(SPELL_SONIC_BURST); + events.ScheduleEvent(EVENT_SONIC_BURST, urand(20000, 30000), PHASE_ONE); + break; + case EVENT_SWOOP: + DoCastVictim(SPELL_SWOOP); + events.ScheduleEvent(EVENT_SWOOP, urand(20000, 30000), PHASE_ONE); + break; + case EVENT_SPAWN_BATS: + Talk(EMOTE_SUMMON_BATS); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + for (uint8 i = 0; i < 6; ++i) + if (Creature* bat = me->SummonCreature(NPC_BLOODSEEKER_BAT, SpawnBat[i], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + bat->AI()->AttackStart(target); + events.ScheduleEvent(EVENT_SPAWN_BATS, 30000, PHASE_ONE); + break; //Phase two - case EVENT_CURSE_OF_BLOOD: - DoCastSelf(SPELL_CURSE_OF_BLOOD); - events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(25000, 30000), PHASE_TWO); - break; - case EVENT_PSYCHIC_SCREAM: - DoCastVictim(SPELL_PSYCHIC_SCREAM); - events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(35000, 45000), PHASE_TWO); - break; - case EVENT_SHADOW_WORD_PAIN: - DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN, 0, true); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(12000, 18000), PHASE_TWO); - break; - case EVENT_MIND_FLAY: - DoCastVictim(SPELL_MIND_FLAY); - events.ScheduleEvent(EVENT_MIND_FLAY, urand(20000, 40000), PHASE_TWO); - break; - case EVENT_GREATER_HEAL: - Talk(EMOTE_GREAT_HEAL); - me->InterruptNonMeleeSpells(false); - DoCastSelf(SPELL_GREATER_HEAL); - events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); - break; - case EVENT_SPAWN_FLYING_BATS: - Talk(SAY_CALL_RIDERS); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - if (Creature* flyingBat = me->SummonCreature(NPC_FRENZIED_BAT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - flyingBat->AI()->AttackStart(target); - events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, urand(10000, 15000), PHASE_TWO); - break; - default: - break; - } + case EVENT_CURSE_OF_BLOOD: + DoCastSelf(SPELL_CURSE_OF_BLOOD); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(25000, 30000), PHASE_TWO); + break; + case EVENT_PSYCHIC_SCREAM: + DoCastVictim(SPELL_PSYCHIC_SCREAM); + events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(35000, 45000), PHASE_TWO); + break; + case EVENT_SHADOW_WORD_PAIN: + DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN, 0, true); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(12000, 18000), PHASE_TWO); + break; + case EVENT_MIND_FLAY: + DoCastVictim(SPELL_MIND_FLAY); + events.ScheduleEvent(EVENT_MIND_FLAY, urand(20000, 40000), PHASE_TWO); + break; + case EVENT_GREATER_HEAL: + Talk(EMOTE_GREAT_HEAL); + me->InterruptNonMeleeSpells(false); + DoCastSelf(SPELL_GREATER_HEAL); + events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); + break; + case EVENT_SPAWN_FLYING_BATS: + Talk(SAY_CALL_RIDERS); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + if (Creature* flyingBat = me->SummonCreature(NPC_FRENZIED_BAT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + flyingBat->AI()->DoZoneInCombat(); + events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, urand(10000, 15000), PHASE_TWO); + break; + default: + break; } - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); + DoMeleeAttackIfReady(); } }; // Flying Bat -class npc_batrider : public CreatureScript +struct npc_batrider : public ScriptedAI { -public: - npc_batrider() : CreatureScript("npc_batrider") { } - - struct npc_batriderAI : public ScriptedAI + npc_batrider(Creature* creature) : ScriptedAI(creature) { - npc_batriderAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 Bomb_Timer; - - void Reset() override + _scheduler.SetValidator([this] { - Bomb_Timer = 2000; - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->AddUnitState(UNIT_STATE_ROOT); - } + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } - void EnterCombat(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (Bomb_Timer <= diff) - { - std::list targets; - SelectTargetList(targets, 1, SelectTargetMethod::Random, 500.0f, true); - if (!targets.empty()) - { - if (targets.size() > 1) - { - targets.resize(1); - } - } - - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - me->CastSpell((*itr), SPELL_BOMB); - } - - Bomb_Timer = 7000; - } - else - Bomb_Timer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetZulGurubAI(creature); + _scheduler.CancelAll(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetHover(true); + me->SetDisableGravity(true); + me->AddUnitState(UNIT_STATE_ROOT); + } + + void EnterCombat(Unit* /*who*/) override + { + _scheduler.Schedule(2s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_THROW_LIQUID_FIRE); + context.Repeat(7s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +class spell_batrider_bomb : public SpellScript +{ + PrepareSpellScript(spell_batrider_bomb); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SUMMON_LIQUID_FIRE }); + } + + void HandleScriptEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_batrider_bomb::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_boss_jeklik() { - new boss_jeklik(); - new npc_batrider(); + RegisterCreatureAI(boss_jeklik); + RegisterCreatureAI(npc_batrider); + RegisterSpellScript(spell_batrider_bomb); }