refactor(Scripts/MagistersTerrace): Felblood Kael'thas (#20642)

* Felblood kael (#14)

* init

* initial ready version

* make scheduler repeatable and correct intro sequence

* some debug and OOC scheduler

* Update boss_felblood_kaelthas.cpp

* finale

* Update boss_felblood_kaelthas.cpp

* Update boss_felblood_kaelthas.cpp

* Update boss_felblood_kaelthas.cpp

* Update boss_felblood_kaelthas.cpp

* simplify target selection
This commit is contained in:
Dan
2024-11-20 23:19:03 +01:00
committed by GitHub
parent bda74c14b8
commit 8c3c751221

View File

@@ -56,20 +56,6 @@ enum Spells
enum Misc
{
EVENT_INIT_COMBAT = 1,
EVENT_SPELL_FIREBALL = 2,
EVENT_SPELL_PHOENIX = 3,
EVENT_SPELL_FLAMESTRIKE = 4,
EVENT_SPELL_SHOCK_BARRIER = 5,
EVENT_CHECK_HEALTH = 6,
EVENT_GRAVITY_LAPSE_1_1 = 7,
EVENT_GRAVITY_LAPSE_1_2 = 8,
EVENT_GRAVITY_LAPSE_2 = 9,
EVENT_GRAVITY_LAPSE_3 = 10,
EVENT_GRAVITY_LAPSE_4 = 11,
EVENT_GRAVITY_LAPSE_5 = 12,
EVENT_FINISH_TALK = 13,
ACTION_TELEPORT_PLAYERS = 1,
ACTION_KNOCKUP = 2,
ACTION_ALLOW_FLY = 3,
@@ -78,216 +64,176 @@ enum Misc
CREATURE_ARCANE_SPHERE = 24708
};
struct boss_felblood_kaelthas : public ScriptedAI
struct boss_felblood_kaelthas : public BossAI
{
boss_felblood_kaelthas(Creature* creature) : ScriptedAI(creature), summons(me)
boss_felblood_kaelthas(Creature* creature) : BossAI(creature, DATA_KAELTHAS)
{
instance = creature->GetInstanceScript();
introSpeak = false;
_hasDoneIntro = false;
}
InstanceScript* instance;
EventMap events;
EventMap events2;
SummonList summons;
bool introSpeak;
void Reset() override
{
events.Reset();
summons.DespawnAll();
BossAI::Reset();
_OOCScheduler.CancelAll();
_gravityLapseCounter = 0;
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
instance->SetBossState(DATA_KAELTHAS, NOT_STARTED);
me->SetImmuneToAll(false);
ScheduleHealthCheckEvent(50, [&]{
me->CastStop();
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
DoCastSelf(SPELL_TELEPORT_CENTER, true);
scheduler.CancelAll();
me->StopMoving();
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
ScheduleTimedEvent(5s, [&]{
summons.DoForAllSummons([&](WorldObject* summon){
if (Unit* player = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
if (Creature* summonedCreature = summon->ToCreature())
summonedCreature->GetMotionMaster()->MoveChase(player);
});
}, 10s, 15s);
GravityLapseSequence(true);
});
}
void JustSummoned(Creature* summon) override
{
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
if (*itr == summon->GetGUID())
return;
summons.Summon(summon);
BossAI::JustSummoned(summon);
summon->SetReactState(REACT_PASSIVE);
}
void GravityLapseSequence(bool firstTime)
{
Talk(firstTime ? SAY_GRAVITY_LAPSE : SAY_RECAST_GRAVITY);
DoCastSelf(SPELL_GRAVITY_LAPSE_INITIAL);
scheduler.Schedule(2s, [this](TaskContext){
LapseAction(ACTION_TELEPORT_PLAYERS);
}).Schedule(3s, [this](TaskContext){
LapseAction(ACTION_KNOCKUP);
}).Schedule(4s, [this](TaskContext){
LapseAction(ACTION_ALLOW_FLY);
for (uint8 i = 0; i < 3; ++i)
DoCastSelf(SPELL_SUMMON_ARCANE_SPHERE, true);
DoCastSelf(SPELL_GRAVITY_LAPSE_CHANNEL);
scheduler.Schedule(30s, [this](TaskContext){
LapseAction(ACTION_REMOVE_FLY);
me->InterruptNonMeleeSpells(false);
Talk(SAY_TIRED);
DoCastSelf(SPELL_POWER_FEEDBACK);
scheduler.Schedule(10s, [this](TaskContext){
GravityLapseSequence(false);
});
});
});
}
void InitializeAI() override
{
ScriptedAI::InitializeAI();
BossAI::InitializeAI();
me->SetImmuneToAll(true);
}
void JustDied(Unit*) override
void JustDied(Unit* killer) override
{
instance->SetBossState(DATA_KAELTHAS, DONE);
summons.DespawnAll();
BossAI::JustDied(killer);
if (GameObject* orb = instance->GetGameObject(DATA_ESCAPE_ORB))
orb->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
me->SetInCombatWithZone();
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 0);
events.ScheduleEvent(EVENT_SPELL_PHOENIX, 15000);
events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 22000);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
ScheduleTimedEvent(0ms, [&]{
DoCastVictim(SPELL_FIREBALL);
}, 3000ms, 4500ms);
ScheduleTimedEvent(15s, [&]{
Talk(SAY_PHOENIX);
DoCastSelf(SPELL_PHOENIX);
}, 60s);
ScheduleTimedEvent(22s, [&]{
DoCastRandomTarget(SPELL_FLAMESTRIKE_SUMMON, 0, 100.0f);
Talk(SAY_FLAMESTRIKE);
}, 25s);
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_SHOCK_BARRIER, 50000);
ScheduleTimedEvent(50s, [&]{
DoCastSelf(SPELL_SHOCK_BARRIER, true);
me->CastCustomSpell(SPELL_PYROBLAST, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
}, 50s);
}
void MoveInLineOfSight(Unit* who) override
{
if (!introSpeak && me->IsWithinDistInMap(who, 40.0f) && who->IsPlayer())
if (!_hasDoneIntro && me->IsWithinDistInMap(who, 40.0f) && who->IsPlayer())
{
Talk(SAY_AGGRO);
introSpeak = true;
events2.ScheduleEvent(EVENT_INIT_COMBAT, 35000);
_hasDoneIntro = true;
_OOCScheduler.Schedule(35s, [this](TaskContext){
me->SetReactState(REACT_AGGRESSIVE);
me->SetImmuneToAll(false);
me->SetInCombatWithZone();
});
}
ScriptedAI::MoveInLineOfSight(who);
BossAI::MoveInLineOfSight(who);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override
{
if (damage >= me->GetHealth())
{
damage = me->GetHealth() - 1;
if (me->isRegeneratingHealth())
{
me->CastStop();
me->SetRegeneratingHealth(false);
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
me->SetImmuneToAll(true);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->CombatStop();
me->SetReactState(REACT_PASSIVE);
LapseAction(ACTION_REMOVE_FLY);
events.Reset();
events2.ScheduleEvent(EVENT_FINISH_TALK, 6000);
scheduler.CancelAll();
_OOCScheduler.Schedule(6s, [this](TaskContext){
me->KillSelf();
});
Talk(SAY_DEATH);
}
}
BossAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask);
}
void LapseAction(uint8 action)
{
uint8 counter = 0;
Map::PlayerList const& playerList = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr, ++counter)
if (Player* player = itr->GetSource())
_gravityLapseCounter = 0;
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (action == ACTION_TELEPORT_PLAYERS)
DoCast(player, SPELL_GRAVITY_LAPSE_PLAYER + _gravityLapseCounter, true);
else if (action == ACTION_KNOCKUP)
player->CastSpell(player, SPELL_GRAVITY_LAPSE_DOT, true, nullptr, nullptr, me->GetGUID());
else if (action == ACTION_ALLOW_FLY)
player->CastSpell(player, SPELL_GRAVITY_LAPSE_FLY, true, nullptr, nullptr, me->GetGUID());
else if (action == ACTION_REMOVE_FLY)
{
if (action == ACTION_TELEPORT_PLAYERS)
me->CastSpell(player, SPELL_GRAVITY_LAPSE_PLAYER + counter, true);
else if (action == ACTION_KNOCKUP)
player->CastSpell(player, SPELL_GRAVITY_LAPSE_DOT, true, nullptr, nullptr, me->GetGUID());
else if (action == ACTION_ALLOW_FLY)
player->CastSpell(player, SPELL_GRAVITY_LAPSE_FLY, true, nullptr, nullptr, me->GetGUID());
else if (action == ACTION_REMOVE_FLY)
{
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT);
}
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT);
}
++_gravityLapseCounter;
});
}
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_INIT_COMBAT:
me->SetImmuneToAll(false);
if (Unit* target = SelectTargetFromPlayerList(50.0f))
AttackStart(target);
return;
case EVENT_FINISH_TALK:
me->KillSelf();
return;
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (uint32 eventId = events.ExecuteEvent())
{
case EVENT_SPELL_FIREBALL:
me->CastSpell(me->GetVictim(), SPELL_FIREBALL, false);
events.ScheduleEvent(EVENT_SPELL_FIREBALL, urand(3000, 4500));
break;
case EVENT_SPELL_FLAMESTRIKE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
me->CastSpell(target, SPELL_FLAMESTRIKE_SUMMON, true);
Talk(SAY_FLAMESTRIKE);
}
events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 25000);
break;
case EVENT_SPELL_SHOCK_BARRIER:
me->CastSpell(me, SPELL_SHOCK_BARRIER, true);
me->CastCustomSpell(SPELL_PYROBLAST, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
events.ScheduleEvent(EVENT_SPELL_SHOCK_BARRIER, 50000);
break;
case EVENT_SPELL_PHOENIX:
Talk(SAY_PHOENIX);
me->CastSpell(me, SPELL_PHOENIX, false);
events.ScheduleEvent(EVENT_SPELL_PHOENIX, 60000);
break;
case EVENT_CHECK_HEALTH:
if (HealthBelowPct(50))
{
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
me->CastSpell(me, SPELL_TELEPORT_CENTER, true);
events.Reset();
me->StopMoving();
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
events.SetPhase(1);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_1_1, 0);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
break;
case EVENT_GRAVITY_LAPSE_1_1:
case EVENT_GRAVITY_LAPSE_1_2:
Talk(eventId == EVENT_GRAVITY_LAPSE_1_1 ? SAY_GRAVITY_LAPSE : SAY_RECAST_GRAVITY);
me->CastSpell(me, SPELL_GRAVITY_LAPSE_INITIAL, false);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_2, 2000);
break;
case EVENT_GRAVITY_LAPSE_2:
LapseAction(ACTION_TELEPORT_PLAYERS);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_3, 1000);
break;
case EVENT_GRAVITY_LAPSE_3:
LapseAction(ACTION_KNOCKUP);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_4, 1000);
break;
case EVENT_GRAVITY_LAPSE_4:
LapseAction(ACTION_ALLOW_FLY);
for (uint8 i = 0; i < 3; ++i)
me->CastSpell(me, SPELL_SUMMON_ARCANE_SPHERE, true);
me->CastSpell(me, SPELL_GRAVITY_LAPSE_CHANNEL, false);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_5, 30000);
break;
case EVENT_GRAVITY_LAPSE_5:
LapseAction(ACTION_REMOVE_FLY);
me->InterruptNonMeleeSpells(false);
Talk(SAY_TIRED);
me->CastSpell(me, SPELL_POWER_FEEDBACK, false);
events.ScheduleEvent(EVENT_GRAVITY_LAPSE_1_2, 10000);
break;
}
if (events.GetPhaseMask() == 0)
DoMeleeAttackIfReady();
_OOCScheduler.Update(diff);
BossAI::UpdateAI(diff);
}
private:
TaskScheduler _OOCScheduler;
bool _hasDoneIntro;
uint8 _gravityLapseCounter;
};
class spell_mt_phoenix_burn : public SpellScript