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>
This commit is contained in:
Nefertumm
2022-06-03 09:26:18 -03:00
committed by GitHub
parent c027e907e1
commit 8e0b1ca286
2 changed files with 209 additions and 184 deletions
@@ -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;
@@ -15,8 +15,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "GameObjectAI.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "zulgurub.h" #include "zulgurub.h"
enum Says enum Says
@@ -49,7 +52,8 @@ enum Spells
SPELL_GREATER_HEAL = 23954, SPELL_GREATER_HEAL = 23954,
// Batriders Spell // 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 enum BatIds
@@ -93,214 +97,227 @@ Position const SpawnBat[6] =
{ -12293.6220f, -1380.2640f, 144.8304f, 5.483f } { -12293.6220f, -1380.2640f, 144.8304f, 5.483f }
}; };
class boss_jeklik : public CreatureScript struct boss_jeklik : public BossAI
{ {
public: boss_jeklik(Creature* creature) : BossAI(creature, DATA_JEKLIK) { }
boss_jeklik() : CreatureScript("boss_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); me->RemoveAurasDueToSpell(SPELL_BAT_FORM);
_Reset(); 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(); switch (eventId)
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))
{ {
me->RemoveAurasDueToSpell(SPELL_BAT_FORM); // Phase one
me->SetDisableGravity(false); case EVENT_CHARGE_JEKLIK:
DoResetThreat(); if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
events.SetPhase(PHASE_TWO); {
DoCast(target, SPELL_CHARGE);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(5000, 15000), PHASE_TWO); AttackStart(target);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(10000, 15000), PHASE_TWO); }
events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(25000, 35000), PHASE_TWO); events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(15000, 30000), PHASE_ONE);
events.ScheduleEvent(EVENT_MIND_FLAY, urand(10000, 30000), PHASE_TWO); break;
events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); case EVENT_PIERCE_ARMOR:
events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, 10000, PHASE_TWO); DoCastVictim(SPELL_PIERCE_ARMOR);
events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(20000, 30000), PHASE_ONE);
return; break;
} case EVENT_BLOOD_LEECH:
} DoCastVictim(SPELL_BLOOD_LEECH);
events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(10000, 20000), PHASE_ONE);
void UpdateAI(uint32 diff) override break;
{ case EVENT_SONIC_BURST:
if (!UpdateVictim()) DoCastVictim(SPELL_SONIC_BURST);
return; events.ScheduleEvent(EVENT_SONIC_BURST, urand(20000, 30000), PHASE_ONE);
break;
events.Update(diff); case EVENT_SWOOP:
DoCastVictim(SPELL_SWOOP);
if (me->HasUnitState(UNIT_STATE_CASTING)) events.ScheduleEvent(EVENT_SWOOP, urand(20000, 30000), PHASE_ONE);
return; break;
case EVENT_SPAWN_BATS:
while (uint32 eventId = events.ExecuteEvent()) Talk(EMOTE_SUMMON_BATS);
{ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
switch (eventId) for (uint8 i = 0; i < 6; ++i)
{ if (Creature* bat = me->SummonCreature(NPC_BLOODSEEKER_BAT, SpawnBat[i], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
// Phase one bat->AI()->AttackStart(target);
case EVENT_CHARGE_JEKLIK: events.ScheduleEvent(EVENT_SPAWN_BATS, 30000, PHASE_ONE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) break;
{
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 //Phase two
case EVENT_CURSE_OF_BLOOD: case EVENT_CURSE_OF_BLOOD:
DoCastSelf(SPELL_CURSE_OF_BLOOD); DoCastSelf(SPELL_CURSE_OF_BLOOD);
events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(25000, 30000), PHASE_TWO); events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(25000, 30000), PHASE_TWO);
break; break;
case EVENT_PSYCHIC_SCREAM: case EVENT_PSYCHIC_SCREAM:
DoCastVictim(SPELL_PSYCHIC_SCREAM); DoCastVictim(SPELL_PSYCHIC_SCREAM);
events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(35000, 45000), PHASE_TWO); events.ScheduleEvent(EVENT_PSYCHIC_SCREAM, urand(35000, 45000), PHASE_TWO);
break; break;
case EVENT_SHADOW_WORD_PAIN: case EVENT_SHADOW_WORD_PAIN:
DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN, 0, true); DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN, 0, true);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(12000, 18000), PHASE_TWO); events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(12000, 18000), PHASE_TWO);
break; break;
case EVENT_MIND_FLAY: case EVENT_MIND_FLAY:
DoCastVictim(SPELL_MIND_FLAY); DoCastVictim(SPELL_MIND_FLAY);
events.ScheduleEvent(EVENT_MIND_FLAY, urand(20000, 40000), PHASE_TWO); events.ScheduleEvent(EVENT_MIND_FLAY, urand(20000, 40000), PHASE_TWO);
break; break;
case EVENT_GREATER_HEAL: case EVENT_GREATER_HEAL:
Talk(EMOTE_GREAT_HEAL); Talk(EMOTE_GREAT_HEAL);
me->InterruptNonMeleeSpells(false); me->InterruptNonMeleeSpells(false);
DoCastSelf(SPELL_GREATER_HEAL); DoCastSelf(SPELL_GREATER_HEAL);
events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO); events.ScheduleEvent(EVENT_GREATER_HEAL, 25000, PHASE_TWO);
break; break;
case EVENT_SPAWN_FLYING_BATS: case EVENT_SPAWN_FLYING_BATS:
Talk(SAY_CALL_RIDERS); Talk(SAY_CALL_RIDERS);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) 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)) 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); flyingBat->AI()->DoZoneInCombat();
events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, urand(10000, 15000), PHASE_TWO); events.ScheduleEvent(EVENT_SPAWN_FLYING_BATS, urand(10000, 15000), PHASE_TWO);
break; break;
default: default:
break; break;
}
} }
DoMeleeAttackIfReady();
} }
};
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetZulGurubAI<boss_jeklikAI>(creature);
} }
}; };
// Flying Bat // Flying Bat
class npc_batrider : public CreatureScript struct npc_batrider : public ScriptedAI
{ {
public: npc_batrider(Creature* creature) : ScriptedAI(creature)
npc_batrider() : CreatureScript("npc_batrider") { }
struct npc_batriderAI : public ScriptedAI
{ {
npc_batriderAI(Creature* creature) : ScriptedAI(creature) { } _scheduler.SetValidator([this]
uint32 Bomb_Timer;
void Reset() override
{ {
Bomb_Timer = 2000; return !me->HasUnitState(UNIT_STATE_CASTING);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); });
me->AddUnitState(UNIT_STATE_ROOT); }
}
void EnterCombat(Unit* /*who*/) override { } void Reset() override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (Bomb_Timer <= diff)
{
std::list<Unit*> targets;
SelectTargetList(targets, 1, SelectTargetMethod::Random, 500.0f, true);
if (!targets.empty())
{
if (targets.size() > 1)
{
targets.resize(1);
}
}
for (std::list<Unit*>::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
{ {
return GetZulGurubAI<npc_batriderAI>(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() void AddSC_boss_jeklik()
{ {
new boss_jeklik(); RegisterCreatureAI(boss_jeklik);
new npc_batrider(); RegisterCreatureAI(npc_batrider);
RegisterSpellScript(spell_batrider_bomb);
} }