refactor(Scripts/SSC): Leotheras the Blind boss script updated (#17080)

* initial

* remove unused parameter

* fix timers

* useless commit to revive actions

* fixes

* weird mistake fixed

* browser programming kekW
This commit is contained in:
Dan
2023-10-01 09:24:47 +02:00
committed by GitHub
parent 93cc0b9bc7
commit 57f5c6fb0c
@@ -19,6 +19,7 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "serpent_shrine.h" #include "serpent_shrine.h"
#include "TaskScheduler.h"
enum Talk enum Talk
{ {
@@ -59,18 +60,12 @@ enum Misc
NPC_GREYHEART_SPELLBINDER = 21806, NPC_GREYHEART_SPELLBINDER = 21806,
NPC_SHADOW_OF_LEOTHERAS = 21875, NPC_SHADOW_OF_LEOTHERAS = 21875,
};
EVENT_SPELL_BERSERK = 1, enum Groups
EVENT_HEALTH_CHECK = 2, {
EVENT_SWITCH_TO_DEMON = 3, GROUP_COMBAT = 1,
EVENT_SPELL_WHIRLWIND = 4, GROUP_DEMON = 2
EVENT_KILL_TALK = 5,
EVENT_SWITCH_TO_ELF = 6,
EVENT_SPELL_INSIDIOUS_WHISPER = 7,
EVENT_SUMMON_DEMON = 8,
EVENT_RESTORE_FIGHT = 9,
EVENT_SPELL_SHADOW_BOLT = 20
}; };
const Position channelersPos[MAX_CHANNELERS] = const Position channelersPos[MAX_CHANNELERS] =
@@ -80,56 +75,71 @@ const Position channelersPos[MAX_CHANNELERS] =
{362.11f, -437.48f, 29.52f, 0.9f} {362.11f, -437.48f, 29.52f, 0.9f}
}; };
class boss_leotheras_the_blind : public CreatureScript struct boss_leotheras_the_blind : public BossAI
{ {
public: boss_leotheras_the_blind(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
boss_leotheras_the_blind() : CreatureScript("boss_leotheras_the_blind") { }
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetSerpentShrineAI<boss_leotheras_the_blindAI>(creature); scheduler.SetValidator([this]
}
struct boss_leotheras_the_blindAI : public BossAI
{
boss_leotheras_the_blindAI(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
{ {
return !me->HasUnitState(UNIT_STATE_CASTING);
});
} }
void Reset() override void Reset() override
{ {
BossAI::Reset(); BossAI::Reset();
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true); DoCastSelf(SPELL_CLEAR_CONSUMING_MADNESS, true);
me->CastSpell(me, SPELL_DUAL_WIELD, true); DoCastSelf(SPELL_DUAL_WIELD, true);
me->SetStandState(UNIT_STAND_STATE_KNEEL); me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->LoadEquipment(0, true); me->LoadEquipment(0, true);
me->SetReactState(REACT_PASSIVE); me->SetReactState(REACT_PASSIVE);
} _recentlySpoken = false;
void InitializeAI() override
{
BossAI::InitializeAI();
SummonChannelers(); SummonChannelers();
}
void JustReachedHome() override ScheduleHealthCheckEvent(15, [&]{
if (me->GetDisplayId() != me->GetNativeDisplayId())
{ {
BossAI::JustReachedHome(); //is currently in metamorphosis
SummonChannelers(); DoResetThreatList();
me->LoadEquipment();
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
scheduler.RescheduleGroup(GROUP_COMBAT, 10s);
}
scheduler.CancelGroup(GROUP_DEMON);
scheduler.DelayAll(10s);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->Clear();
me->StopMoving();
Talk(SAY_FINAL_FORM);
scheduler.Schedule(4s, [this](TaskContext)
{
DoCastSelf(SPELL_SUMMON_SHADOW_OF_LEOTHERAS);
}).Schedule(6s, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveChase(me->GetVictim());
});
});
} }
void SummonChannelers() void SummonChannelers()
{ {
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false);
me->CastSpell(me, SPELL_BANISH, true); DoCastSelf(SPELL_BANISH);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true);
//probably needs a spell instead
summons.DespawnAll(); summons.DespawnAll();
for (uint8 i = 0; i < MAX_CHANNELERS; ++i) for (uint8 i = 0; i < MAX_CHANNELERS; ++i)
{
me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
} }
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void JustSummoned(Creature* summon) override void JustSummoned(Creature* summon) override
{ {
@@ -141,6 +151,7 @@ public:
me->SetInCombatWithZone(); me->SetInCombatWithZone();
summons.Despawn(summon); summons.Despawn(summon);
if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER) if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER)
{
if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER)) if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER))
{ {
me->RemoveAllAuras(); me->RemoveAllAuras();
@@ -149,39 +160,49 @@ public:
me->SetStandState(UNIT_STAND_STATE_STAND); me->SetStandState(UNIT_STAND_STATE_STAND);
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000); scheduler.Schedule(10min, [this](TaskContext)
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); {
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000); DoCastSelf(SPELL_BERSERK);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000); });
ElfTime();
}
} }
} }
void KilledUnit(Unit* /*victim*/) override void ElfTime()
{ {
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) scheduler.Schedule(25050ms, 32550ms, GROUP_COMBAT, [this](TaskContext context)
{ {
Talk(me->GetDisplayId() != me->GetNativeDisplayId() ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY); DoCastSelf(SPELL_WHIRLWIND);
events.ScheduleEvent(EVENT_KILL_TALK, 6000); context.Repeat(30250ms, 34900ms);
} }).Schedule(60350ms, GROUP_DEMON, [this](TaskContext)
{
DoResetThreatList();
Talk(SAY_SWITCH_TO_DEMON);
DemonTime();
});
} }
void JustDied(Unit* killer) override void DemonTime()
{ {
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true); me->LoadEquipment(0, true);
Talk(SAY_DEATH); me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
BossAI::JustDied(killer); DoCastSelf(SPELL_METAMORPHOSIS, true);
}
void JustEngagedWith(Unit* who) override scheduler.CancelGroup(GROUP_COMBAT);
scheduler.Schedule(24250ms, GROUP_DEMON, [this](TaskContext)
{ {
BossAI::JustEngagedWith(who); Talk(SAY_INNER_DEMONS);
me->SetStandState(UNIT_STAND_STATE_KNEEL); me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
} }).Schedule(60s, [this](TaskContext)
void AttackStart(Unit* who) override
{ {
if (who && me->Attack(who, true)) DoResetThreatList();
me->GetMotionMaster()->MoveChase(who, me->GetDisplayId() == me->GetNativeDisplayId() ? 0.0f : 25.0f); me->LoadEquipment();
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
ElfTime();
});
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -189,106 +210,36 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
events.Update(diff); scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
break;
case EVENT_HEALTH_CHECK:
if (me->HealthBelowPct(15))
{
if (me->GetDisplayId() != me->GetNativeDisplayId())
{
DoResetThreatList();
me->LoadEquipment();
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
}
events.CancelEvent(EVENT_SWITCH_TO_DEMON);
events.CancelEvent(EVENT_SPELL_INSIDIOUS_WHISPER);
events.DelayEvents(10000);
events.ScheduleEvent(EVENT_SUMMON_DEMON, 4000);
events.ScheduleEvent(EVENT_RESTORE_FIGHT, 6000);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->Clear();
me->StopMoving();
Talk(SAY_FINAL_FORM);
break;
}
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
break;
case EVENT_SWITCH_TO_DEMON:
DoResetThreatList();
Talk(SAY_SWITCH_TO_DEMON);
me->LoadEquipment(0, true);
me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
me->CastSpell(me, SPELL_METAMORPHOSIS, true);
events.CancelEvent(EVENT_SPELL_WHIRLWIND);
events.ScheduleEvent(EVENT_SPELL_INSIDIOUS_WHISPER, 25000);
events.ScheduleEvent(EVENT_SWITCH_TO_ELF, 60000);
break;
case EVENT_SWITCH_TO_ELF:
DoResetThreatList();
me->LoadEquipment();
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
break;
case EVENT_SPELL_WHIRLWIND:
me->CastSpell(me, SPELL_WHIRLWIND, false);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 27000);
break;
case EVENT_SPELL_INSIDIOUS_WHISPER:
Talk(SAY_INNER_DEMONS);
me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
break;
case EVENT_SUMMON_DEMON:
me->CastSpell(me, SPELL_SUMMON_SHADOW_OF_LEOTHERAS, true);
break;
case EVENT_RESTORE_FIGHT:
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
}
if (me->GetDisplayId() == me->GetNativeDisplayId()) if (me->GetDisplayId() == me->GetNativeDisplayId())
{
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
}
else if (me->isAttackReady(BASE_ATTACK)) else if (me->isAttackReady(BASE_ATTACK))
{ {
me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false); me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false);
me->setAttackTimer(BASE_ATTACK, 2000); me->setAttackTimer(BASE_ATTACK, 2000);
} }
} }
}; private:
bool _recentlySpoken;
}; };
class npc_inner_demon : public CreatureScript struct npc_inner_demon : public ScriptedAI
{ {
public: npc_inner_demon(Creature* creature) : ScriptedAI(creature)
npc_inner_demon() : CreatureScript("npc_inner_demon") { }
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetSerpentShrineAI<npc_inner_demonAI>(creature); _scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
_instance = creature->GetInstanceScript();
} }
struct npc_inner_demonAI : public ScriptedAI
{
npc_inner_demonAI(Creature* creature) : ScriptedAI(creature)
{
}
ObjectGuid ownerGUID;
EventMap events;
void EnterEvadeMode(EvadeReason /*why*/) override void EnterEvadeMode(EvadeReason /*why*/) override
{ {
me->DespawnOrUnsummon(1); me->DespawnOrUnsummon(1);
@@ -299,48 +250,56 @@ public:
if (!summoner) if (!summoner)
return; return;
ownerGUID = summoner->GetGUID(); _scheduler.CancelAll();
events.Reset(); _scheduler.Schedule(4s, [this](TaskContext context)
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 4000); {
DoCastVictim(SPELL_SHADOW_BOLT);
context.Repeat(6s);
});
} }
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (Unit* unit = ObjectAccessor::GetUnit(*me, ownerGUID)) if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
unit->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER); {
leotheras->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER);
}
} }
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{ {
if (!who || who->GetGUID() != ownerGUID) if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
{
if (!who || who->GetGUID() != leotheras->GetGUID())
{
damage = 0; damage = 0;
} }
}
}
bool CanAIAttack(Unit const* who) const override bool CanAIAttack(Unit const* who) const override
{ {
return who->GetGUID() == ownerGUID; if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
{
return who->GetGUID() == leotheras->GetGUID();
}
return false;
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{ {
case EVENT_SPELL_SHADOW_BOLT: return;
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 6000);
break;
} }
_scheduler.Update(diff);
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
}; private:
TaskScheduler _scheduler;
InstanceScript* _instance;
}; };
class spell_leotheras_whirlwind : public SpellScriptLoader class spell_leotheras_whirlwind : public SpellScriptLoader
@@ -516,8 +475,8 @@ public:
void AddSC_boss_leotheras_the_blind() void AddSC_boss_leotheras_the_blind()
{ {
new boss_leotheras_the_blind(); RegisterSerpentShrineAI(boss_leotheras_the_blind);
new npc_inner_demon(); RegisterSerpentShrineAI(npc_inner_demon);
new spell_leotheras_whirlwind(); new spell_leotheras_whirlwind();
new spell_leotheras_chaos_blast(); new spell_leotheras_chaos_blast();
new spell_leotheras_insidious_whisper(); new spell_leotheras_insidious_whisper();