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:
@@ -56,20 +56,6 @@ enum Spells
|
|||||||
|
|
||||||
enum Misc
|
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_TELEPORT_PLAYERS = 1,
|
||||||
ACTION_KNOCKUP = 2,
|
ACTION_KNOCKUP = 2,
|
||||||
ACTION_ALLOW_FLY = 3,
|
ACTION_ALLOW_FLY = 3,
|
||||||
@@ -78,216 +64,176 @@ enum Misc
|
|||||||
CREATURE_ARCANE_SPHERE = 24708
|
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();
|
_hasDoneIntro = false;
|
||||||
introSpeak = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceScript* instance;
|
|
||||||
EventMap events;
|
|
||||||
EventMap events2;
|
|
||||||
SummonList summons;
|
|
||||||
bool introSpeak;
|
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
events.Reset();
|
BossAI::Reset();
|
||||||
summons.DespawnAll();
|
_OOCScheduler.CancelAll();
|
||||||
|
_gravityLapseCounter = 0;
|
||||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
|
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
|
||||||
instance->SetBossState(DATA_KAELTHAS, NOT_STARTED);
|
|
||||||
me->SetImmuneToAll(false);
|
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
|
void JustSummoned(Creature* summon) override
|
||||||
{
|
{
|
||||||
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
BossAI::JustSummoned(summon);
|
||||||
if (*itr == summon->GetGUID())
|
summon->SetReactState(REACT_PASSIVE);
|
||||||
return;
|
}
|
||||||
summons.Summon(summon);
|
|
||||||
|
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
|
void InitializeAI() override
|
||||||
{
|
{
|
||||||
ScriptedAI::InitializeAI();
|
BossAI::InitializeAI();
|
||||||
me->SetImmuneToAll(true);
|
me->SetImmuneToAll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustDied(Unit*) override
|
void JustDied(Unit* killer) override
|
||||||
{
|
{
|
||||||
instance->SetBossState(DATA_KAELTHAS, DONE);
|
BossAI::JustDied(killer);
|
||||||
summons.DespawnAll();
|
|
||||||
|
|
||||||
if (GameObject* orb = instance->GetGameObject(DATA_ESCAPE_ORB))
|
if (GameObject* orb = instance->GetGameObject(DATA_ESCAPE_ORB))
|
||||||
orb->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
orb->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustEngagedWith(Unit* /*who*/) override
|
void JustEngagedWith(Unit* who) override
|
||||||
{
|
{
|
||||||
instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS);
|
BossAI::JustEngagedWith(who);
|
||||||
me->SetInCombatWithZone();
|
|
||||||
|
|
||||||
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 0);
|
ScheduleTimedEvent(0ms, [&]{
|
||||||
events.ScheduleEvent(EVENT_SPELL_PHOENIX, 15000);
|
DoCastVictim(SPELL_FIREBALL);
|
||||||
events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 22000);
|
}, 3000ms, 4500ms);
|
||||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
ScheduleTimedEvent(15s, [&]{
|
||||||
|
Talk(SAY_PHOENIX);
|
||||||
|
DoCastSelf(SPELL_PHOENIX);
|
||||||
|
}, 60s);
|
||||||
|
ScheduleTimedEvent(22s, [&]{
|
||||||
|
DoCastRandomTarget(SPELL_FLAMESTRIKE_SUMMON, 0, 100.0f);
|
||||||
|
Talk(SAY_FLAMESTRIKE);
|
||||||
|
}, 25s);
|
||||||
|
|
||||||
if (IsHeroic())
|
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
|
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);
|
Talk(SAY_AGGRO);
|
||||||
introSpeak = true;
|
_hasDoneIntro = true;
|
||||||
events2.ScheduleEvent(EVENT_INIT_COMBAT, 35000);
|
_OOCScheduler.Schedule(35s, [this](TaskContext){
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetImmuneToAll(false);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
BossAI::MoveInLineOfSight(who);
|
||||||
ScriptedAI::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())
|
if (damage >= me->GetHealth())
|
||||||
{
|
{
|
||||||
damage = me->GetHealth() - 1;
|
damage = me->GetHealth() - 1;
|
||||||
if (me->isRegeneratingHealth())
|
if (me->isRegeneratingHealth())
|
||||||
{
|
{
|
||||||
|
me->CastStop();
|
||||||
me->SetRegeneratingHealth(false);
|
me->SetRegeneratingHealth(false);
|
||||||
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||||
me->SetImmuneToAll(true);
|
me->SetImmuneToAll(true);
|
||||||
|
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||||
me->CombatStop();
|
me->CombatStop();
|
||||||
me->SetReactState(REACT_PASSIVE);
|
me->SetReactState(REACT_PASSIVE);
|
||||||
LapseAction(ACTION_REMOVE_FLY);
|
LapseAction(ACTION_REMOVE_FLY);
|
||||||
events.Reset();
|
scheduler.CancelAll();
|
||||||
events2.ScheduleEvent(EVENT_FINISH_TALK, 6000);
|
_OOCScheduler.Schedule(6s, [this](TaskContext){
|
||||||
|
me->KillSelf();
|
||||||
|
});
|
||||||
Talk(SAY_DEATH);
|
Talk(SAY_DEATH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BossAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LapseAction(uint8 action)
|
void LapseAction(uint8 action)
|
||||||
{
|
{
|
||||||
uint8 counter = 0;
|
_gravityLapseCounter = 0;
|
||||||
Map::PlayerList const& playerList = me->GetMap()->GetPlayers();
|
me->GetMap()->DoForAllPlayers([&](Player* player)
|
||||||
for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr, ++counter)
|
{
|
||||||
if (Player* player = itr->GetSource())
|
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)
|
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);
|
||||||
me->CastSpell(player, SPELL_GRAVITY_LAPSE_PLAYER + counter, true);
|
player->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
++_gravityLapseCounter;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
void UpdateAI(uint32 diff) override
|
||||||
{
|
{
|
||||||
events2.Update(diff);
|
_OOCScheduler.Update(diff);
|
||||||
switch (events2.ExecuteEvent())
|
BossAI::UpdateAI(diff);
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
TaskScheduler _OOCScheduler;
|
||||||
|
bool _hasDoneIntro;
|
||||||
|
uint8 _gravityLapseCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
class spell_mt_phoenix_burn : public SpellScript
|
class spell_mt_phoenix_burn : public SpellScript
|
||||||
|
|||||||
Reference in New Issue
Block a user