Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-11-25 23:22:31 +08:00
365 changed files with 8563 additions and 201758 deletions
@@ -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
File diff suppressed because it is too large Load Diff
@@ -41,76 +41,76 @@ enum Spells
SPELL_DRAIN_MANA = 46153
};
enum Events
const Position crystalSummons[5] =
{
EVENT_SPELL_DRAIN_LIFE = 1,
EVENT_SPELL_FEL_EXPLOSION = 2,
EVENT_SPELL_DRAIN_MANA = 3,
EVENT_DRAIN_CRYSTAL = 4,
EVENT_EMPOWER = 5,
EVENT_RESTORE_COMBAT = 6
{248.053f, 14.592f, 3.74882f, 3.94444f},
{225.969f, -20.0775f, -2.9731f, 0.942478f},
{226.314f, 20.2183f, -2.98127f, 5.32325f},
{247.888f, -14.6252f, 3.80777f, 2.33874f},
{263.149f, 0.309245f, 1.32057f, 3.15905f}
};
struct boss_selin_fireheart : public ScriptedAI
struct boss_selin_fireheart : public BossAI
{
boss_selin_fireheart(Creature* creature) : ScriptedAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
EventMap events;
SummonList summons;
ObjectGuid CrystalGUID;
boss_selin_fireheart(Creature* creature) : BossAI(creature, DATA_SELIN_FIREHEART) { }
bool CanAIAttack(Unit const* who) const override
{
return who->GetPositionX() > 216.0f;
}
void SpawnCrystals()
{
me->SummonCreature(NPC_FEL_CRYSTAL, 248.053f, 14.592f, 3.74882f, 3.94444f, TEMPSUMMON_CORPSE_DESPAWN);
me->SummonCreature(NPC_FEL_CRYSTAL, 225.969f, -20.0775f, -2.9731f, 0.942478f, TEMPSUMMON_CORPSE_DESPAWN);
me->SummonCreature(NPC_FEL_CRYSTAL, 226.314f, 20.2183f, -2.98127f, 5.32325f, TEMPSUMMON_CORPSE_DESPAWN);
me->SummonCreature(NPC_FEL_CRYSTAL, 247.888f, -14.6252f, 3.80777f, 2.33874f, TEMPSUMMON_CORPSE_DESPAWN);
me->SummonCreature(NPC_FEL_CRYSTAL, 263.149f, 0.309245f, 1.32057f, 3.15905f, TEMPSUMMON_CORPSE_DESPAWN);
}
void JustSummoned(Creature* summon) override
{
summon->SetReactState(REACT_PASSIVE);
summons.Summon(summon);
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
if (events.GetPhaseMask() & 0x01)
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
}
void Reset() override
{
events.Reset();
summons.DespawnAll();
BossAI::Reset();
SpawnCrystals();
instance->SetBossState(DATA_SELIN_FIREHEART, NOT_STARTED);
CrystalGUID.Clear();
me->SetPower(POWER_MANA, 0);
}
void JustEngagedWith(Unit* /*who*/) override
void SpawnCrystals()
{
Talk(SAY_AGGRO);
instance->SetBossState(DATA_SELIN_FIREHEART, IN_PROGRESS);
for (Position pos : crystalSummons)
me->SummonCreature(NPC_FEL_CRYSTAL, pos, TEMPSUMMON_CORPSE_DESPAWN);
}
events.ScheduleEvent(EVENT_SPELL_DRAIN_LIFE, 2500, 1);
events.ScheduleEvent(EVENT_SPELL_FEL_EXPLOSION, 2000);
events.ScheduleEvent(EVENT_DRAIN_CRYSTAL, 14000);
void SummonedCreatureDies(Creature* summon, Unit* killer) override
{
BossAI::SummonedCreatureDies(summon, killer);
me->ResumeChasingVictim();
}
void OnPowerUpdate(Powers /*power*/, int32 /*gain*/, int32 /*updateVal*/, uint32 currentPower) override
{
if (currentPower == me->GetMaxPower(POWER_MANA))
{
Talk(SAY_EMPOWERED);
if (Creature* crystal = SelectNearestCrystal(false))
crystal->KillSelf();
scheduler.DelayAll(10s);
me->ResumeChasingVictim();
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
ScheduleTimedEvent(2500ms, [&]{
DoCastRandomTarget(SPELL_DRAIN_LIFE);
}, 10000ms);
ScheduleTimedEvent(2s, [&]{
me->RemoveAuraFromStack(SPELL_MANA_RAGE_TRIGGER);
DoCastAOE(SPELL_FEL_EXPLOSION);
}, 2s);
ScheduleTimedEvent(14s, [&]{
scheduler.DelayAll(10s);
SelectNearestCrystal(true);
}, 30s);
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 7500, 1);
{
ScheduleTimedEvent(7500ms, [&]{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, POWER_MANA, 40.0f, false)))
DoCast(target, SPELL_DRAIN_MANA);
}, 10s);
}
}
void KilledUnit(Unit* victim) override
@@ -119,106 +119,57 @@ struct boss_selin_fireheart : public ScriptedAI
Talk(SAY_KILL);
}
void JustDied(Unit* /*killer*/) override
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
instance->SetBossState(DATA_SELIN_FIREHEART, DONE); // Encounter complete!
summons.DespawnAll();
}
void SelectNearestCrystal()
Creature* SelectNearestCrystal(bool performMovement)
{
if (summons.empty())
return;
return nullptr;
CrystalGUID.Clear();
Unit* crystal = nullptr;
for (SummonList::const_iterator i = summons.begin(); i != summons.end(); )
if (Creature* summon = ObjectAccessor::GetCreature(*me, *i++))
if (!crystal || me->GetDistanceOrder(summon, crystal, false))
crystal = summon;
if (crystal)
float closestDistance = 1000.0f;
Creature* chosenCrystal = nullptr;
summons.DoForAllSummons([&](WorldObject* summon)
{
if (Creature* summonedCreature = summon->ToCreature())
{
float checkDistance = me->GetDistance2d(summonedCreature);
if (checkDistance < closestDistance)
{
closestDistance = checkDistance;
chosenCrystal = summonedCreature;
}
}
});
if (chosenCrystal && performMovement)
{
Talk(SAY_ENERGY);
float x, y, z;
crystal->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE);
CrystalGUID = crystal->GetGUID();
chosenCrystal->GetClosePoint(x, y, z, me->GetObjectSize(), CONTACT_DISTANCE);
me->GetMotionMaster()->MovePoint(2, x, y, z);
}
return chosenCrystal;
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == 2)
{
if (Unit* crystal = ObjectAccessor::GetUnit(*me, CrystalGUID))
if (Creature* crystal = SelectNearestCrystal(false))
{
Talk(EMOTE_CRYSTAL);
crystal->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
crystal->CastSpell(me, SPELL_MANA_RAGE, true);
me->CastSpell(crystal, SPELL_FEL_CRYSTAL_COSMETIC, true);
events.SetPhase(1);
events.ScheduleEvent(EVENT_EMPOWER, 0, 0, 1);
crystal->SetInCombatWithZone();
crystal->AI()->DoCast(me, SPELL_MANA_RAGE, true);
DoCast(crystal, SPELL_FEL_CRYSTAL_COSMETIC, true);
}
else
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
me->ResumeChasingVictim();
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_DRAIN_LIFE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_DRAIN_LIFE, false);
events.ScheduleEvent(EVENT_SPELL_DRAIN_LIFE, 10000, 1);
return;
case EVENT_SPELL_DRAIN_MANA:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, POWER_MANA, 40.0f, false)))
me->CastSpell(target, SPELL_DRAIN_MANA, false);
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 10000, 1);
return;
case EVENT_SPELL_FEL_EXPLOSION:
me->RemoveAuraFromStack(SPELL_MANA_RAGE_TRIGGER);
me->CastSpell(me, SPELL_FEL_EXPLOSION, false);
events.ScheduleEvent(EVENT_SPELL_FEL_EXPLOSION, 2000);
break;
case EVENT_DRAIN_CRYSTAL:
events.DelayEvents(10001);
events.ScheduleEvent(EVENT_EMPOWER, 10000);
events.ScheduleEvent(EVENT_DRAIN_CRYSTAL, 30000);
SelectNearestCrystal();
break;
case EVENT_EMPOWER:
if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA))
{
Talk(SAY_EMPOWERED);
if (Unit* crystal = ObjectAccessor::GetUnit(*me, CrystalGUID))
Unit::Kill(crystal, crystal);
events.DelayEvents(10000, 1);
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
}
else
events.ScheduleEvent(EVENT_EMPOWER, 0, 0, 1);
break;
case EVENT_RESTORE_COMBAT:
events.SetPhase(0);
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
}
DoMeleeAttackIfReady();
}
};
void AddSC_boss_selin_fireheart()
@@ -23,6 +23,7 @@
ObjectData const creatureData[] =
{
{ NPC_DELRISSA, DATA_DELRISSA },
{ NPC_KAEL_THAS, DATA_KAELTHAS },
{ NPC_KALECGOS, DATA_KALECGOS },
{ 0, 0 }
@@ -34,6 +35,13 @@ ObjectData const gameobjectData[] =
{ 0, 0, }
};
ObjectData const summonerData[] =
{
{ NPC_PHOENIX, DATA_KAELTHAS },
{ NPC_PHOENIX_EGG, DATA_KAELTHAS },
{ 0, 0 }
};
DoorData const doorData[] =
{
{ GO_SELIN_DOOR, DATA_SELIN_FIREHEART, DOOR_TYPE_PASSAGE },
@@ -58,10 +66,9 @@ public:
SetBossNumber(MAX_ENCOUNTER);
LoadObjectData(creatureData, gameobjectData);
LoadDoorData(doorData);
LoadSummonData(summonerData);
}
ObjectGuid DelrissaGUID;
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
{
if (eventId == EVENT_SPAWN_KALECGOS)
@@ -74,31 +81,6 @@ public:
});
}
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_DELRISSA:
DelrissaGUID = creature->GetGUID();
break;
case NPC_PHOENIX:
case NPC_PHOENIX_EGG:
if (Creature* kael = GetCreature(DATA_KAELTHAS))
kael->AI()->JustSummoned(creature);
break;
}
InstanceScript::OnCreatureCreate(creature);
}
ObjectGuid GetGuidData(uint32 identifier) const override
{
if (identifier == NPC_DELRISSA)
return DelrissaGUID;
return ObjectGuid::Empty;
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -1215,6 +1215,88 @@ class spell_death_knight_initiate_visual : public SpellScript
}
};
enum spells_lich_king_whisper
{
SPELL_LICH_KING_VO_BLOCKER = 58207,
SPELL_LICHKINGDK001 = 58208,
SPELL_LICHKINGDK002 = 58209,
SPELL_LICHKINGDK003 = 58210,
SPELL_LICHKINGDK004 = 58211,
SPELL_LICHKINGDK005 = 58212,
SPELL_LICHKINGDK006 = 58213,
SPELL_LICHKINGDK007 = 58214,
SPELL_LICHKINGDK008 = 58215,
SPELL_LICHKINGDK009 = 58216,
SPELL_LICHKINGDK010 = 58217,
SPELL_LICHKINGDK011 = 58218,
SPELL_LICHKINGDK012 = 58219,
SPELL_LICHKINGDK013 = 58220,
SPELL_LICHKINGDK014 = 58221,
SPELL_LICHKINGDK015 = 58222,
SPELL_LICHKINGDK016 = 58223
};
//spell 58207 rand Whisper
class spell_lich_king_vo_blocker : public AuraScript
{
PrepareAuraScript(spell_lich_king_vo_blocker);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo
({
SPELL_LICHKINGDK001, SPELL_LICHKINGDK002, SPELL_LICHKINGDK003, SPELL_LICHKINGDK004,
SPELL_LICHKINGDK005, SPELL_LICHKINGDK006, SPELL_LICHKINGDK007, SPELL_LICHKINGDK008,
SPELL_LICHKINGDK009, SPELL_LICHKINGDK010, SPELL_LICHKINGDK011, SPELL_LICHKINGDK012,
SPELL_LICHKINGDK013, SPELL_LICHKINGDK014, SPELL_LICHKINGDK015, SPELL_LICHKINGDK016
});
}
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Player* target = GetTarget()->ToPlayer())
{
//spell 58208-58223
GetCaster()->CastSpell(target, urand(SPELL_LICHKINGDK001, SPELL_LICHKINGDK016), true);
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_lich_king_vo_blocker::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 58208 - 58224 - Creature - The Lich King (28765) Whisper
class spell_lich_king_whisper : public SpellScript
{
PrepareSpellScript(spell_lich_king_whisper);
bool Validate(SpellInfo const* spellInfo) override
{
return sObjectMgr->GetBroadcastText(uint32(spellInfo->GetEffect(EFFECT_0).CalcValue())) &&
sSoundEntriesStore.LookupEntry(uint32(spellInfo->GetEffect(EFFECT_1).CalcValue()));
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Player* player = GetHitPlayer())
GetCaster()->Whisper(uint32(GetEffectValue()), player, false);
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Player* player = GetHitPlayer())
player->PlayDistanceSound(uint32(GetEffectValue()), player);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_lich_king_whisper::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
OnEffectHitTarget += SpellEffectFn(spell_lich_king_whisper::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
void AddSC_the_scarlet_enclave_c1()
{
// Ours
@@ -1237,4 +1319,6 @@ void AddSC_the_scarlet_enclave_c1()
new go_inconspicuous_mine_car();
RegisterSpellScript(spell_death_knight_initiate_visual);
RegisterSpellScript(spell_lich_king_whisper);
RegisterSpellScript(spell_lich_king_vo_blocker);
}
@@ -63,35 +63,6 @@ enum Spells
enum Misc
{
// Land
EVENT_SPELL_BERSERK = 1,
EVENT_SPELL_CLEAVE = 2,
EVENT_SPELL_CORROSION = 3,
EVENT_SPELL_GAS_NOVA = 4,
EVENT_SPELL_ENCAPSULATE = 5,
EVENT_FLIGHT = 6,
EVENT_LAND = 7,
EVENT_RESTORE_COMBAT = 8,
EVENT_RESTORE_COMBAT2 = 9,
// Air
EVENT_FLIGHT_SEQ = 100,
EVENT_FLIGHT_VAPOR = 101,
EVENT_FLIGHT_MOVE_UP = 102,
EVENT_LAND_FIGHT = 103,
EVENT_FLIGHT_EMOTE = 104,
EVENT_FLIGHT_BREATH1 = 105,
EVENT_FLIGHT_BREATH2 = 106,
EVENT_FLIGHT_FLYOVER1 = 107,
EVENT_FLIGHT_FLYOVER2 = 108,
EVENT_CORRUPT_TRIGGERS = 109,
// Intro
EVENT_INTRO_1 = 20,
EVENT_INTRO_2 = 21,
EVENT_INTRO_3 = 22,
EVENT_INTRO_4 = 23,
// Misc
ACTION_START_EVENT = 1,
POINT_GROUND = 1,
@@ -102,23 +73,24 @@ enum Misc
POINT_AIR_BREATH_END2 = 6,
POINT_MISC = 7,
GROUP_START_INTRO = 0,
GROUP_BREATH = 1,
NPC_FOG_TRIGGER = 23472
};
class CorruptTriggers : public BasicEvent
{
public:
CorruptTriggers(Unit* caster) : _caster(caster)
{
}
CorruptTriggers(Unit* caster) : _caster(caster) { }
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
{
std::list<Creature*> cList;
_caster->GetCreaturesWithEntryInRange(cList, 70.0f, NPC_FOG_TRIGGER);
for (std::list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); ++itr)
if (_caster->GetExactDist2d(*itr) <= 11.0f)
(*itr)->CastSpell(*itr, SPELL_FOG_OF_CORRUPTION, true);
std::list<Creature*> creatureList;
_caster->GetCreaturesWithEntryInRange(creatureList, 70.0f, NPC_FOG_TRIGGER);
for (auto const& creature : creatureList)
if (_caster->GetExactDist2d(creature) <= 11.0f)
creature->CastSpell(creature, SPELL_FOG_OF_CORRUPTION, true);
return true;
}
@@ -136,15 +108,13 @@ struct boss_felmyst : public BossAI
creature->SetReactState(REACT_PASSIVE);
}
EventMap events2;
void DoAction(int32 param) override
{
if (param == ACTION_START_EVENT)
{
me->SetVisible(true);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
events2.ScheduleEvent(EVENT_INTRO_1, 3000);
StartIntro();
}
}
@@ -154,7 +124,7 @@ struct boss_felmyst : public BossAI
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetReactState(REACT_PASSIVE);
me->SetDisableGravity(false);
events2.Reset();
me->m_Events.KillAllEvents(false);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FOG_OF_CORRUPTION_CHARM);
}
@@ -162,8 +132,9 @@ struct boss_felmyst : public BossAI
{
BossAI::JustEngagedWith(who);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (events.Empty() && events2.Empty())
events2.ScheduleEvent(EVENT_INTRO_2, 3000);
if (!scheduler.IsGroupScheduled(GROUP_START_INTRO))
StartIntro();
}
void KilledUnit(Unit* victim) override
@@ -193,36 +164,65 @@ struct boss_felmyst : public BossAI
me->SetDisableGravity(false);
me->SendMovementFlagUpdate();
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 0);
events.ScheduleEvent(EVENT_RESTORE_COMBAT2, 1);
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
events.ScheduleEvent(EVENT_SPELL_CORROSION, 12000, 1);
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 18000, 1);
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
events.ScheduleEvent(EVENT_FLIGHT, 60000, 1);
me->m_Events.AddEventAtOffset([&] {
me->SetReactState(REACT_AGGRESSIVE);
if (me->GetVictim())
me->SetTarget(me->GetVictim()->GetGUID());
me->ResumeChasingVictim();
}, 1s);
ScheduleTimedEvent(7500ms, [&] {
DoCastVictim(SPELL_CLEAVE);
}, 7500ms);
ScheduleTimedEvent(12s, [&] {
DoCastVictim(SPELL_CORROSION);
}, 20s);
ScheduleTimedEvent(18s, [&] {
DoCastSelf(SPELL_GAS_NOVA);
}, 20s);
ScheduleTimedEvent(25s, [&] {
DoCastRandomTarget(SPELL_ENCAPSULATE_CHANNEL, 0, 50.0f);
}, 25s);
me->m_Events.AddEventAtOffset([&] {
scheduler.CancelAll();
me->SetReactState(REACT_PASSIVE);
me->StopMoving();
me->GetMotionMaster()->Clear();
me->m_Events.AddEventAtOffset([&] {
ScheduleFlightSequence();
}, 1s);
}, 1min);
}
else if (point == POINT_AIR_BREATH_START1)
{
me->SetTarget();
me->SetFacingTo(4.71f);
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER1, 5000);
ScheduleFlightAbilities(point);
}
else if (point == POINT_AIR_BREATH_END1)
{
me->RemoveAurasDueToSpell(SPELL_FELMYST_SPEED_BURST);
me->SetFacingTo(1.57f);
if (events.GetNextEventTime(EVENT_FLIGHT_BREATH1) != 0)
events.ScheduleEvent(EVENT_FLIGHT_BREATH2, 2000);
if (!scheduler.IsGroupScheduled(GROUP_BREATH))
{
me->m_Events.AddEventAtOffset([&] {
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 515.0f, 50.0f, 1.57f };
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START2, pos, false, true);
}, 2s);
}
}
else if (point == POINT_AIR_BREATH_START2)
{
me->SetTarget();
me->SetFacingTo(1.57f);
events.ScheduleEvent(EVENT_FLIGHT_EMOTE, 2000);
events.ScheduleEvent(EVENT_CORRUPT_TRIGGERS, 5000);
events.ScheduleEvent(EVENT_FLIGHT_FLYOVER2, 5000);
ScheduleFlightAbilities(point);
}
else if (point == POINT_AIR_BREATH_END2)
{
@@ -231,127 +231,50 @@ struct boss_felmyst : public BossAI
}
}
void JustSummoned(Creature* summon) override
void ScheduleFlightSequence()
{
summons.Summon(summon);
}
Talk(YELL_TAKEOFF);
me->SetTarget();
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
me->SetDisableGravity(true);
me->SendMovementFlagUpdate();
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_INTRO_1:
me->SetStandState(UNIT_STAND_STATE_STAND);
events2.ScheduleEvent(EVENT_INTRO_2, 4000);
break;
case EVENT_INTRO_2:
Talk(YELL_BIRTH);
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
me->SendMovementFlagUpdate();
events2.ScheduleEvent(EVENT_INTRO_3, 1500);
break;
case EVENT_INTRO_3:
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, false, true);
events2.ScheduleEvent(EVENT_INTRO_4, 2000);
break;
case EVENT_INTRO_4:
events.ScheduleEvent(EVENT_LAND, 3000, 1);
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
me->SetInCombatWithZone();
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->CastSpell(me, SPELL_NOXIOUS_FUMES, true);
me->GetMotionMaster()->MovePoint(POINT_MISC, 1472.18f, 603.38f, 34.0f, false, true);
break;
}
if (!events2.Empty())
return;
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_RESTORE_COMBAT:
me->SetReactState(REACT_AGGRESSIVE);
break;
case EVENT_RESTORE_COMBAT2:
me->SetTarget(me->GetVictim()->GetGUID());
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
case EVENT_LAND:
me->GetMotionMaster()->MovePoint(POINT_GROUND, me->GetPositionX(), me->GetPositionY(), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), false, true);
break;
case EVENT_SPELL_BERSERK:
Talk(YELL_BERSERK);
me->CastSpell(me, SPELL_BERSERK, true);
break;
case EVENT_SPELL_CLEAVE:
me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
events.ScheduleEvent(EVENT_SPELL_CLEAVE, 7500, 1);
break;
case EVENT_SPELL_CORROSION:
me->CastSpell(me->GetVictim(), SPELL_CORROSION, false);
events.ScheduleEvent(EVENT_SPELL_CORROSION, 20000, 1);
break;
case EVENT_SPELL_GAS_NOVA:
DoCast(me, SPELL_GAS_NOVA, false);
events.ScheduleEvent(EVENT_SPELL_GAS_NOVA, 20000, 1);
break;
case EVENT_SPELL_ENCAPSULATE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_ENCAPSULATE_CHANNEL, false);
events.ScheduleEvent(EVENT_SPELL_ENCAPSULATE, 25000, 1);
break;
case EVENT_FLIGHT:
events.CancelEventGroup(1);
events.ScheduleEvent(EVENT_FLIGHT_SEQ, 1000);
me->SetReactState(REACT_PASSIVE);
me->StopMoving();
me->GetMotionMaster()->Clear();
break;
case EVENT_FLIGHT_SEQ:
Talk(YELL_TAKEOFF);
me->SetTarget();
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
me->SetDisableGravity(true);
me->SendMovementFlagUpdate();
events.ScheduleEvent(EVENT_FLIGHT_MOVE_UP, 2000);
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 8000);
events.ScheduleEvent(EVENT_FLIGHT_VAPOR, 21000);
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 35000);
events.ScheduleEvent(EVENT_FLIGHT_BREATH1, 72000);
events.ScheduleEvent(EVENT_LAND_FIGHT, 86000);
break;
case EVENT_FLIGHT_MOVE_UP:
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, false, true);
break;
case EVENT_FLIGHT_VAPOR:
}, 2s);
me->m_Events.AddEventAtOffset([&] {
me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true);
break;
case EVENT_FLIGHT_BREATH1:
}, 8s);
me->m_Events.AddEventAtOffset([&] {
me->CastCustomSpell(SPELL_SUMMON_DEMONIC_VAPOR, SPELLVALUE_MAX_TARGETS, 1, me, true);
}, 21s);
scheduler.Schedule(35s, GROUP_BREATH, [this](TaskContext)
{
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f };
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true);
break;
}
case EVENT_FLIGHT_BREATH2:
});
scheduler.Schedule(72s, GROUP_BREATH, [this](TaskContext)
{
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 515.0f, 50.0f, 1.57f };
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START2, pos, false, true);
break;
}
case EVENT_FLIGHT_EMOTE:
Position pos = { 1447.0f + urand(0, 2) * 25.0f, 705.0f, 50.0f, 4.71f };
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_START1, pos, false, true);
});
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePoint(POINT_GROUND, 1500.0f, 552.8f, 26.52f, false, true);
}, 86s);
}
void ScheduleFlightAbilities(uint8 point)
{
me->m_Events.AddEventAtOffset([&] {
Talk(EMOTE_BREATH);
break;
case EVENT_CORRUPT_TRIGGERS:
}, 2s);
me->m_Events.AddEventAtOffset([&] {
Talk(YELL_BREATH);
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(0));
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(500));
@@ -362,19 +285,58 @@ struct boss_felmyst : public BossAI
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3000));
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(3500));
me->m_Events.AddEvent(new CorruptTriggers(me), me->m_Events.CalculateTime(4000));
break;
case EVENT_FLIGHT_FLYOVER1:
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END1, me->GetPositionX(), me->GetPositionY() - 200.0f, me->GetPositionZ() + 5.0f, false, true);
break;
case EVENT_FLIGHT_FLYOVER2:
me->CastSpell(me, SPELL_FELMYST_SPEED_BURST, true);
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END2, me->GetPositionX(), me->GetPositionY() + 200.0f, me->GetPositionZ() + 5.0f, false, true);
break;
case EVENT_LAND_FIGHT:
me->GetMotionMaster()->MovePoint(POINT_GROUND, 1500.0f, 552.8f, 26.52f, false, true);
break;
}
}, 5s);
me->m_Events.AddEventAtOffset([this, point] {
DoCastSelf(SPELL_FELMYST_SPEED_BURST, true);
if (point == POINT_AIR_BREATH_START1)
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END1, me->GetPositionX(), me->GetPositionY() - 200.0f, me->GetPositionZ() + 5.0f, false, true);
else if (point == POINT_AIR_BREATH_START2)
me->GetMotionMaster()->MovePoint(POINT_AIR_BREATH_END2, me->GetPositionX(), me->GetPositionY() + 200.0f, me->GetPositionZ() + 5.0f, false, true);
}, 5s);
}
void StartIntro()
{
scheduler.Schedule(3s, GROUP_START_INTRO, [this](TaskContext /*context*/)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->m_Events.AddEventAtOffset([&] {
Talk(YELL_BIRTH);
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
me->SendMovementFlagUpdate();
}, 7s);
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, false, true);
}, 8500ms);
me->m_Events.AddEventAtOffset([&] {
me->SetInCombatWithZone();
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->CastSpell(me, SPELL_NOXIOUS_FUMES, true);
me->GetMotionMaster()->MovePoint(POINT_MISC, 1472.18f, 603.38f, 34.0f, false, true);
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePoint(POINT_GROUND, me->GetPositionX(), me->GetPositionY(), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), false, true);
}, 3s);
me->m_Events.AddEventAtOffset([&] {
Talk(YELL_BERSERK);
DoCastSelf(SPELL_BERSERK, true);
}, 10min);
}, 10500ms);
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (!me->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
DoMeleeAttackIfReady();
@@ -84,50 +84,28 @@ enum SWPActions
ACTION_ENRAGE_OTHER = 5,
};
enum kalEvents
{
EVENT_ARCANE_BUFFET = 1,
EVENT_FROST_BREATH = 2,
EVENT_WILD_MAGIC = 3,
EVENT_TAIL_LASH = 4,
EVENT_SPECTRAL_BLAST = 5,
EVENT_CHECK_HEALTH = 6,
EVENT_CHECK_HEALTH2 = 7,
EVENT_CHECK_POS = 8,
EVENT_SPAWN_SPECTRALS = 9,
EVENT_SPELL_REVITALIZE = 10,
EVENT_SPELL_HEROIC_STRIKE = 11,
EVENT_SHADOW_BOLT = 12,
EVENT_AGONY_CURSE = 13,
EVENT_CORRUPTION_STRIKE = 14,
EVENT_TALK_GOOD_1 = 20,
EVENT_TALK_GOOD_2 = 21,
EVENT_TALK_GOOD_3 = 22,
EVENT_TALK_GOOD_4 = 23,
EVENT_TALK_GOOD_5 = 24,
EVENT_TALK_BAD_1 = 25,
EVENT_TALK_BAD_2 = 26,
EVENT_TALK_BAD_3 = 27
};
#define DRAGON_REALM_Z 53.079f
struct boss_kalecgos : public BossAI
{
boss_kalecgos(Creature* creature) : BossAI(creature, DATA_KALECGOS)
{
SetInvincibility(true);
}
bool sathBanished;
EventMap events2;
bool CanAIAttack(Unit const* target) const override
{
return target->GetPositionZ() > 50.0f;
}
bool CheckInRoom() override
{
if (me->GetDistance(me->GetHomePosition()) > 50.0f)
return false;
return true;
}
void JustReachedHome() override
{
BossAI::JustReachedHome();
@@ -137,15 +115,24 @@ struct boss_kalecgos : public BossAI
void Reset() override
{
BossAI::Reset();
me->SetHealth(me->GetMaxHealth());
me->SetFullHealth();
me->SetStandState(UNIT_STAND_STATE_SLEEP);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
events2.Reset();
sathBanished = false;
_sathBanished = false;
ClearPlayerAuras();
ScheduleHealthCheckEvent(10, [&] {
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
Sath->AI()->DoAction(ACTION_ENRAGE_OTHER);
DoAction(ACTION_ENRAGE);
});
ScheduleHealthCheckEvent(1, [&] {
DoAction(ACTION_BANISH);
});
}
void ClearPlayerAuras() const
@@ -160,29 +147,75 @@ struct boss_kalecgos : public BossAI
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
{
Talk(param == ACTION_ENRAGE ? SAY_KALEC_ENRAGE_SATH : SAY_SATH_ENRAGE_ME);
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
events.CancelEvent(EVENT_CHECK_HEALTH);
DoCastSelf(SPELL_CRAZED_RAGE, true);
return;
}
else if (param == ACTION_BANISH)
{
me->CastSpell(me, SPELL_BANISH, true);
events.Reset();
DoCastSelf(SPELL_BANISH, true);
scheduler.CancelAll();
}
else if (param == ACTION_SATH_BANISH)
sathBanished = true;
_sathBanished = true;
else if (param == ACTION_KALEC_DIED)
{
events.Reset();
events2.ScheduleEvent(EVENT_TALK_BAD_1, 0);
scheduler.CancelAll();
me->m_Events.AddEventAtOffset([&] {
me->SetReactState(REACT_PASSIVE);
me->CombatStop();
me->RemoveAllAuras();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
Talk(SAY_EVIL_ENRAGE);
}, 1s);
me->m_Events.AddEventAtOffset([&] {
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
}, 4s);
me->m_Events.AddEventAtOffset([&] {
me->SetVisible(false);
EnterEvadeMode();
}, 9s);
ClearPlayerAuras();
return;
}
if (me->HasAura(SPELL_BANISH) && sathBanished)
if (me->HasAura(SPELL_BANISH) && _sathBanished)
{
events.Reset();
events2.ScheduleEvent(EVENT_TALK_GOOD_1, 1000);
scheduler.CancelAll();
me->m_Events.AddEventAtOffset([&] {
me->SetRegeneratingHealth(false);
me->RemoveAllAuras();
me->SetReactState(REACT_PASSIVE);
me->CombatStop();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetFaction(FACTION_FRIENDLY);
}, 1s);
me->m_Events.AddEventAtOffset([&] {
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
{
summons.Despawn(Sath);
Unit::Kill(me, Sath);
}
}, 2s);
Talk(SAY_GOOD_PLRWIN, 10s);
me->m_Events.AddEventAtOffset([&] {
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
}, 15s);
me->m_Events.AddEventAtOffset([&] {
me->SetVisible(false);
me->KillSelf();
}, 20s);
ClearPlayerAuras();
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
{
@@ -194,160 +227,47 @@ struct boss_kalecgos : public BossAI
}
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 6000);
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
events.ScheduleEvent(EVENT_WILD_MAGIC, 10000);
events.ScheduleEvent(EVENT_TAIL_LASH, 25000);
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, 20000);
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
events.ScheduleEvent(EVENT_SPAWN_SPECTRALS, 16000);
ScheduleTimedEvent(6s, [&] {
DoCastAOE(SPELL_ARCANE_BUFFET);
}, 8s);
ScheduleTimedEvent(15s, [&] {
DoCastVictim(SPELL_FROST_BREATH);
}, 15s);
ScheduleTimedEvent(10s, [&] {
me->CastCustomSpell(RAND(44978, 45001, 45002, 45004, 45006, 45010), SPELLVALUE_MAX_TARGETS, 1, me, false);
}, 20s);
ScheduleTimedEvent(25s, [&] {
DoCastVictim(SPELL_TAIL_LASH);
}, 15s);
ScheduleTimedEvent(20s, [&] {
DoCastAOE(SPELL_SPECTRAL_BLAST);
}, 15s, 25s);
me->m_Events.AddEventAtOffset([&] {
me->SummonCreature(NPC_KALEC, 1702.21f, 931.7f, -74.56f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN);
me->SummonCreature(NPC_SATHROVARR, 1704.62f, 927.78f, -73.9f, 2.0f, TEMPSUMMON_MANUAL_DESPAWN);
}, 16s);
me->SetStandState(UNIT_STAND_STATE_STAND);
Talk(SAY_EVIL_AGGRO);
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth() && attacker != me)
damage = 0;
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer() && roll_chance_i(50))
Talk(SAY_EVIL_SLAY);
}
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_TALK_GOOD_1:
me->SetRegeneratingHealth(false);
me->RemoveAllAuras();
me->SetReactState(REACT_PASSIVE);
me->CombatStop();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetFaction(FACTION_FRIENDLY);
events2.ScheduleEvent(EVENT_TALK_GOOD_2, 1000);
break;
case EVENT_TALK_GOOD_2:
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
{
summons.Despawn(Sath);
Unit::Kill(me, Sath);
}
events2.ScheduleEvent(EVENT_TALK_GOOD_3, 8000);
break;
case EVENT_TALK_GOOD_3:
Talk(SAY_GOOD_PLRWIN);
events2.ScheduleEvent(EVENT_TALK_GOOD_4, 10000);
break;
case EVENT_TALK_GOOD_4:
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
events2.ScheduleEvent(EVENT_TALK_GOOD_5, 10000);
break;
case EVENT_TALK_GOOD_5:
me->SetVisible(false);
me->KillSelf();
break;
case EVENT_TALK_BAD_1:
me->SetReactState(REACT_PASSIVE);
me->CombatStop();
me->RemoveAllAuras();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
Talk(SAY_EVIL_ENRAGE);
events2.ScheduleEvent(EVENT_TALK_BAD_2, 3000);
break;
case EVENT_TALK_BAD_2:
me->SetDisableGravity(true);
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
events2.ScheduleEvent(EVENT_TALK_BAD_3, 15000);
break;
case EVENT_TALK_BAD_3:
me->SetVisible(false);
EnterEvadeMode();
break;
}
if (!events2.Empty())
return;
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPAWN_SPECTRALS:
me->SummonCreature(NPC_KALEC, 1702.21f, 931.7f, -74.56f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN);
me->SummonCreature(NPC_SATHROVARR, 1704.62f, 927.78f, -73.9f, 2.0f, TEMPSUMMON_MANUAL_DESPAWN);
break;
case EVENT_ARCANE_BUFFET:
me->CastSpell(me, SPELL_ARCANE_BUFFET, false);
events.ScheduleEvent(EVENT_ARCANE_BUFFET, 8000);
break;
case EVENT_FROST_BREATH:
me->CastSpell(me->GetVictim(), SPELL_FROST_BREATH, false);
events.ScheduleEvent(EVENT_FROST_BREATH, 15000);
break;
case EVENT_TAIL_LASH:
me->CastSpell(me->GetVictim(), SPELL_TAIL_LASH, false);
events.ScheduleEvent(EVENT_TAIL_LASH, 15000);
break;
case EVENT_WILD_MAGIC:
me->CastCustomSpell(RAND(44978, 45001, 45002, 45004, 45006, 45010), SPELLVALUE_MAX_TARGETS, 1, me, false);
events.ScheduleEvent(EVENT_WILD_MAGIC, 20000);
break;
case EVENT_SPECTRAL_BLAST:
me->CastSpell(me, SPELL_SPECTRAL_BLAST, false);
events.ScheduleEvent(EVENT_SPECTRAL_BLAST, urand(15000, 25000));
break;
case EVENT_CHECK_POS:
if (me->GetDistance(me->GetHomePosition()) > 50.0f)
{
EnterEvadeMode();
return;
}
events.ScheduleEvent(EVENT_CHECK_POS, 5000);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(10))
{
if (Creature* Sath = instance->GetCreature(DATA_SATHROVARR))
Sath->AI()->DoAction(ACTION_ENRAGE_OTHER);
DoAction(ACTION_ENRAGE);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
break;
case EVENT_CHECK_HEALTH2:
if (me->HealthBelowPct(1))
{
DoAction(ACTION_BANISH);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
break;
}
DoMeleeAttackIfReady();
}
private:
bool _sathBanished;
};
enum Kalec
@@ -362,41 +282,66 @@ enum Kalec
struct boss_kalec : public ScriptedAI
{
boss_kalec(Creature* creature) : ScriptedAI(creature) { }
EventMap events;
EventMap events2;
boss_kalec(Creature* creature) : ScriptedAI(creature)
{
SetInvincibility(true);
}
void Reset() override
{
events.Reset();
events2.Reset();
if (me->GetPositionY() < 750.0f)
{
me->SetSpeed(MOVE_RUN, 2.4f);
me->SetDisplayId(MODEL_KALECGOS_DRAGON);
me->SetDisableGravity(true);
me->GetMotionMaster()->MovePoint(0, 1483.30f, 657.99f, 28.0f, false, true);
events2.ScheduleEvent(EVENT_KALEC_SCENE_1, 9000);
events2.ScheduleEvent(EVENT_KALEC_SCENE_2, 16000);
events2.ScheduleEvent(EVENT_KALEC_SCENE_3, 22000);
me->m_Events.AddEventAtOffset([&] {
Talk(SAY_GOOD_MADRIGOSA);
me->GetMotionMaster()->MovePoint(0, 1509.0f, 560.0f, 30.0f, false, true);
}, 9s);
me->m_Events.AddEventAtOffset([&] {
DoCastAOE(SPELL_OPEN_BRUTALLUS_BACK_DOOR, true);
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, NOT_STARTED);
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, DONE);
}, 16s);
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePoint(0, 1400.0f, 630.0f, 90.0f, false, true);
me->DespawnOrUnsummon(6000);
}, 22s);
}
else
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!who || who->GetEntry() != NPC_SATHROVARR)
damage = 0;
DoCastSelf(SPELL_SPECTRAL_INVISIBILITY, true);
}
void JustEngagedWith(Unit*) override
{
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 5000);
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 3000);
ScheduleTimedEvent(5s, [&] {
DoCastSelf(SPELL_REVITALIZE);
}, 10s);
ScheduleTimedEvent(3s, [&] {
DoCastVictim(SPELL_HEROIC_STRIKE);
}, 5s);
scheduler.Schedule(1s, [this](TaskContext context)
{
if (me->HealthBelowPct(50))
Talk(SAY_GOOD_NEAR_DEATH);
else
context.Repeat();
});
scheduler.Schedule(1s, [this](TaskContext context)
{
if (me->HealthBelowPct(10))
Talk(SAY_GOOD_NEAR_DEATH2);
else
context.Repeat();
});
Talk(SAY_GOOD_AGGRO);
}
@@ -409,60 +354,11 @@ struct boss_kalec : public ScriptedAI
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_KALEC_SCENE_1:
Talk(SAY_GOOD_MADRIGOSA);
me->GetMotionMaster()->MovePoint(0, 1509.0f, 560.0f, 30.0f, false, true);
break;
case EVENT_KALEC_SCENE_2:
me->CastSpell(me, SPELL_OPEN_BRUTALLUS_BACK_DOOR, true);
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, NOT_STARTED);
me->GetInstanceScript()->SetBossState(DATA_FELMYST_DOORS, DONE);
break;
case EVENT_KALEC_SCENE_3:
me->GetMotionMaster()->MovePoint(0, 1400.0f, 630.0f, 90.0f, false, true);
me->DespawnOrUnsummon(6000);
break;
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(50))
{
Talk(SAY_GOOD_NEAR_DEATH);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
break;
case EVENT_CHECK_HEALTH2:
if (me->HealthBelowPct(10))
{
Talk(SAY_GOOD_NEAR_DEATH2);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
break;
case EVENT_SPELL_REVITALIZE:
me->CastSpell(me, SPELL_REVITALIZE, false);
events.ScheduleEvent(EVENT_SPELL_REVITALIZE, 10000);
break;
case EVENT_SPELL_HEROIC_STRIKE:
me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false);
events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, 5000);
break;
}
DoMeleeAttackIfReady();
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
};
@@ -470,12 +366,10 @@ struct boss_sathrovarr : public ScriptedAI
{
boss_sathrovarr(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
_instance = creature->GetInstanceScript();
SetInvincibility(true);
}
InstanceScript* instance;
EventMap events;
bool CanAIAttack(Unit const* target) const override
{
return target->GetPositionZ() < 50.0f;
@@ -483,26 +377,53 @@ struct boss_sathrovarr : public ScriptedAI
void Reset() override
{
events.Reset();
me->CastSpell(me, SPELL_DEMONIC_VISUAL, true);
me->CastSpell(me, SPELL_SPECTRAL_INVISIBILITY, true);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 7000);
events.ScheduleEvent(EVENT_AGONY_CURSE, 20000);
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 13000);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
DoCastSelf(SPELL_DEMONIC_VISUAL, true);
DoCastSelf(SPELL_SPECTRAL_INVISIBILITY, true);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_SATH_AGGRO);
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth() && who != me)
damage = 0;
ScheduleTimedEvent(7s, [&] {
if (roll_chance_i(20))
Talk(SAY_SATH_SPELL1);
DoCastVictim(SPELL_SHADOW_BOLT);
}, 9s);
ScheduleTimedEvent(20s, [&] {
me->CastCustomSpell(SPELL_CURSE_OF_BOUNDLESS_AGONY, SPELLVALUE_MAX_TARGETS, 1, me, false);
}, 30s);
ScheduleTimedEvent(20s, [&] {
if (roll_chance_i(20))
Talk(SAY_SATH_SPELL2);
DoCastVictim(SPELL_CORRUPTION_STRIKE);
}, 9s);
scheduler.Schedule(1s, [this](TaskContext context)
{
if (me->HealthBelowPct(10))
{
if (Creature* kalecgos = _instance->GetCreature(DATA_KALECGOS))
kalecgos->AI()->DoAction(ACTION_ENRAGE_OTHER);
DoAction(ACTION_ENRAGE);
}
else
context.Repeat();
});
scheduler.Schedule(1s, [this](TaskContext context)
{
if (me->HealthBelowPct(1))
{
if (Creature* kalecgos = _instance->GetCreature(DATA_KALECGOS))
kalecgos->AI()->DoAction(ACTION_SATH_BANISH);
DoAction(ACTION_BANISH);
}
else
context.Repeat();
});
}
void KilledUnit(Unit* target) override
@@ -519,15 +440,9 @@ struct boss_sathrovarr : public ScriptedAI
void DoAction(int32 param) override
{
if (param == ACTION_ENRAGE || param == ACTION_ENRAGE_OTHER)
{
me->CastSpell(me, SPELL_CRAZED_RAGE, true);
events.CancelEvent(EVENT_CHECK_HEALTH);
}
DoCastSelf(SPELL_CRAZED_RAGE, true);
else if (param == ACTION_BANISH)
{
me->CastSpell(me, SPELL_BANISH, true);
events.Reset();
}
DoCastSelf(SPELL_BANISH, true);
}
void UpdateAI(uint32 diff) override
@@ -535,58 +450,12 @@ struct boss_sathrovarr : public ScriptedAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SHADOW_BOLT:
if (roll_chance_i(20))
Talk(SAY_SATH_SPELL1);
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
events.ScheduleEvent(EVENT_SHADOW_BOLT, 9000);
break;
case EVENT_AGONY_CURSE:
me->CastCustomSpell(SPELL_CURSE_OF_BOUNDLESS_AGONY, SPELLVALUE_MAX_TARGETS, 1, me, false);
events.ScheduleEvent(EVENT_AGONY_CURSE, 30000);
break;
case EVENT_CORRUPTION_STRIKE:
if (roll_chance_i(20))
Talk(SAY_SATH_SPELL2);
me->CastSpell(me->GetVictim(), SPELL_CORRUPTION_STRIKE, false);
events.ScheduleEvent(EVENT_CORRUPTION_STRIKE, 9000);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(10))
{
if (InstanceScript* instanceScript = me->GetInstanceScript())
{
if (Creature* kalecgos = ObjectAccessor::GetCreature(*me, instanceScript->GetGuidData(
NPC_KALECGOS)))
{
kalecgos->AI()->DoAction(ACTION_ENRAGE_OTHER);
}
}
DoAction(ACTION_ENRAGE);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
break;
case EVENT_CHECK_HEALTH2:
if (me->HealthBelowPct(1))
{
if (Creature* kalecgos = instance->GetCreature(DATA_KALECGOS))
kalecgos->AI()->DoAction(ACTION_SATH_BANISH);
DoAction(ACTION_BANISH);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH2, 1000);
break;
}
DoMeleeAttackIfReady();
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
private:
InstanceScript* _instance;
};
class SpectralBlastCheck
@@ -97,60 +97,14 @@ enum Misc
PHASE_ARMAGEDDON = 4,
PHASE_SACRIFICE = 5,
EVENT_GROUP_SPEACH = 1,
ACTION_START_POST_EVENT = 1,
ACTION_NO_KILL_TALK = 2,
// Text events
EVENT_TEXT_SPEACH11 = 1,
EVENT_TEXT_SPEACH21 = 2,
EVENT_TEXT_SPEACH22 = 3,
EVENT_TEXT_SPEACH23 = 4,
EVENT_TEXT_SPEACH31 = 5,
EVENT_TEXT_SPEACH32 = 6,
EVENT_TEXT_SPEACH33 = 7,
EVENT_TEXT_SPEACH41 = 8,
EVENT_TEXT_SPEACH42 = 9,
EVENT_TEXT_SPEACH43 = 10,
EVENT_TEXT_SPEACH44 = 11,
EVENT_TEXT_SPEACH45 = 12,
EVENT_TEXT_SPEACH46 = 13,
// Controller events
EVENT_RANDOM_TALK = 40,
EVENT_CHECK_PLAYERS = 41,
// Misc fight events
EVENT_REBIRTH = 50,
EVENT_INIT_FIGHT = 51,
EVENT_CHECK_HEALTH85 = 52,
EVENT_CHECK_HEALTH55 = 53,
EVENT_CHECK_HEALTH25 = 54,
EVENT_EMPOWER_ORBS1 = 55,
EVENT_EMPOWER_ORBS2 = 56,
EVENT_EMPOWER_ORBS3 = 57,
EVENT_RESTORE_MELEE = 58,
EVENT_KILL_SELF = 59,
EVENT_NO_KILL_TALK = 60,
// Abilities events
EVENT_SPELL_SOUL_FLAY = 100,
EVENT_SPELL_LEGION_LIGHTNING = 101,
EVENT_SPELL_FIRE_BLOOM = 102,
EVENT_SUMMON_ORBS = 103,
EVENT_SPELL_SHADOW_SPIKE = 104,
EVENT_SPELL_SINISTER_REFLECTION = 105,
EVENT_SPELL_FLAME_DART = 106,
EVENT_SPELL_DARKNESS = 107,
EVENT_SPELL_ARMAGEDDON = 108,
ACTION_NO_KILL_TALK = 2
};
class CastArmageddon : public BasicEvent
{
public:
CastArmageddon(Creature* caster) : _caster(caster)
{
}
CastArmageddon(Creature* caster) : _caster(caster) { }
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
{
@@ -168,12 +122,12 @@ struct npc_kiljaeden_controller : public NullCreatureAI
npc_kiljaeden_controller(Creature* creature) : NullCreatureAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
EventMap events;
InstanceScript* instance;
SummonList summons;
void ResetOrbs()
{
for (uint8 i = DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1; i < DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 + 1; ++i)
@@ -184,7 +138,6 @@ struct npc_kiljaeden_controller : public NullCreatureAI
void Reset() override
{
instance->SetBossState(DATA_KILJAEDEN, NOT_STARTED);
events.Reset();
summons.DespawnAll();
ResetOrbs();
@@ -193,9 +146,15 @@ struct npc_kiljaeden_controller : public NullCreatureAI
me->SummonCreature(NPC_HAND_OF_THE_DECEIVER, 1688.38f, 641.10f, 27.50f, 5.43f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
me->SummonCreature(NPC_ANVEENA, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40.0f, 0.0f);
me->CastSpell(me, SPELL_DESTROY_ALL_DRAKES, true);
me->CastSpell(me, SPELL_ANVEENA_ENERGY_DRAIN, true);
events.ScheduleEvent(EVENT_RANDOM_TALK, 60000);
DoCastAOE(SPELL_DESTROY_ALL_DRAKES, true);
DoCastSelf(SPELL_ANVEENA_ENERGY_DRAIN, true);
scheduler.Schedule(1min, [this](TaskContext context) {
if (instance->GetBossState(DATA_KILJAEDEN) == NOT_STARTED)
Talk(SAY_KJ_OFFCOMBAT);
context.Repeat(90s, 3min);
});
}
void JustDied(Unit*) override
@@ -206,7 +165,7 @@ struct npc_kiljaeden_controller : public NullCreatureAI
summons.DoAction(ACTION_START_POST_EVENT, kalCheck);
summons.DespawnIf(kalCheck);
me->CastSpell(me, SPELL_DESTROY_ALL_DRAKES, true);
DoCastAOE(SPELL_DESTROY_ALL_DRAKES, true);
summons.DespawnAll();
}
@@ -226,7 +185,19 @@ struct npc_kiljaeden_controller : public NullCreatureAI
if (summon->GetEntry() == NPC_HAND_OF_THE_DECEIVER)
{
instance->SetBossState(DATA_KILJAEDEN, IN_PROGRESS);
events.ScheduleEvent(EVENT_CHECK_PLAYERS, 1000);
scheduler.Schedule(1s, [this](TaskContext context) {
auto const& playerList = me->GetMap()->GetPlayers();
for (auto const& playerRef : playerList)
if (Player* player = playerRef.GetSource())
if (!player->IsGameMaster() && me->GetDistance2d(player) < 60.0f && player->IsAlive())
{
context.Repeat();
return;
}
CreatureAI::EnterEvadeMode();
});
if (!summons.HasEntry(NPC_HAND_OF_THE_DECEIVER))
{
@@ -239,61 +210,239 @@ struct npc_kiljaeden_controller : public NullCreatureAI
void UpdateAI(uint32 diff) override
{
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_RANDOM_TALK:
if (instance->GetBossState(DATA_KILJAEDEN) == NOT_STARTED)
Talk(SAY_KJ_OFFCOMBAT);
events.ScheduleEvent(EVENT_RANDOM_TALK, urand(90000, 180000));
break;
case EVENT_CHECK_PLAYERS:
{
Map::PlayerList const& players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource())
if (!player->IsGameMaster() && me->GetDistance2d(player) < 60.0f && player->IsAlive())
{
events.ScheduleEvent(EVENT_CHECK_PLAYERS, 1000);
return;
}
CreatureAI::EnterEvadeMode();
break;
}
}
scheduler.Update(diff);
}
private:
InstanceScript* instance;
SummonList summons;
};
struct boss_kiljaeden : public ScriptedAI
struct boss_kiljaeden : public BossAI
{
boss_kiljaeden(Creature* creature) : ScriptedAI(creature)
boss_kiljaeden(Creature* creature) : BossAI(creature, DATA_KILJAEDEN)
{
instance = creature->GetInstanceScript();
me->SetReactState(REACT_PASSIVE);
}
InstanceScript* instance;
EventMap events;
EventMap events2;
uint8 phase;
void InitializeAI() override
{
ScriptedAI::InitializeAI();
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
phase = PHASE_NORMAL;
events.Reset();
events2.Reset();
events2.ScheduleEvent(EVENT_INIT_FIGHT, 11000);
events2.ScheduleEvent(EVENT_REBIRTH, 0);
me->SetVisible(false);
me->m_Events.AddEventAtOffset([&] {
me->SetVisible(true);
DoCastSelf(SPELL_REBIRTH);
}, 1s);
me->m_Events.AddEventAtOffset([&] {
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetInCombatWithZone();
}, 11s);
}
void Reset() override
{
events.Reset();
_phase = PHASE_NORMAL;
ScheduleHealthCheckEvent(85, [&]{
_phase = PHASE_DARKNESS;
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_AWAKEN, 16s);
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
anveena->AI()->Talk(SAY_ANVEENA_IMPRISONED, 22s);
Talk(SAY_KJ_PHASE3, 28s);
scheduler.CancelAll();
ScheduleBasicAbilities();
me->m_Events.AddEventAtOffset([&] {
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY1);
EmpowerOrb(false);
}, 35s);
me->m_Events.AddEventAtOffset([&] {
Talk(SAY_KJ_REFLECTION);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
}, 1s);
scheduler.Schedule(1s+200ms, [this](TaskContext)
{
DoCastSelf(SPELL_SHADOW_SPIKE);
});
ScheduleTimedEvent(3s, [&] {
DoCastSelf(SPELL_FLAME_DART);
}, 10s);
ScheduleTimedEvent(16s, [&] {
Talk(EMOTE_KJ_DARKNESS);
DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS);
}, 45s);
});
ScheduleHealthCheckEvent(55, [&] {
_phase = PHASE_ARMAGEDDON;
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_LETGO, 16s);
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
anveena->AI()->Talk(SAY_ANVEENA_LOST, 22s);
Talk(SAY_KJ_PHASE4, 28s);
scheduler.CancelAll();
ScheduleBasicAbilities();
me->m_Events.AddEventAtOffset([&] {
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY2);
EmpowerOrb(false);
}, 35s);
me->m_Events.AddEventAtOffset([&] {
Talk(SAY_KJ_REFLECTION);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
}, 1s);
scheduler.Schedule(1s + 200ms, [this](TaskContext)
{
DoCastSelf(SPELL_SHADOW_SPIKE);
});
ScheduleTimedEvent(15s, [&] {
Talk(EMOTE_KJ_DARKNESS);
DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS);
}, 45s);
ScheduleTimedEvent(10s, [&] {
DoCastSelf(SPELL_ARMAGEDDON_PERIODIC, true);
}, 40s);
});
ScheduleHealthCheckEvent(25, [&] {
_phase = PHASE_SACRIFICE;
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
{
kalec->AI()->Talk(SAY_KALECGOS_FOCUS, 8s);
kalec->AI()->Talk(SAY_KALECGOS_FATE, 20s + 200ms);
}
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->AI()->Talk(SAY_ANVEENA_KALEC, 18s);
anveena->AI()->Talk(SAY_ANVEENA_GOODBYE, 25s);
}
scheduler.CancelAll();
me->m_Events.AddEventAtOffset([&] {
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->RemoveAllAuras();
anveena->DespawnOrUnsummon(3500);
}
}, 28s);
me->m_Events.AddEventAtOffset([&] {
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
DoCastSelf(SPELL_CUSTOM_08_STATE, true);
me->SetUnitFlag(UNIT_FLAG_PACIFIED);
scheduler.DelayAll(7100ms);
me->m_Events.AddEventAtOffset([&] {
me->RemoveAurasDueToSpell(SPELL_CUSTOM_08_STATE);
me->RemoveUnitFlag(UNIT_FLAG_PACIFIED);
ScheduleBasicAbilities();
me->m_Events.AddEventAtOffset([&] {
Talk(SAY_KJ_REFLECTION);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
}, 1s);
ScheduleTimedEvent(15s, [&] {
Talk(EMOTE_KJ_DARKNESS);
DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS);
}, 25s);
ScheduleTimedEvent(1500ms, [&] {
DoCastSelf(SPELL_ARMAGEDDON_PERIODIC, true);
}, 20s);
}, 7s);
}
Talk(SAY_KJ_PHASE5);
}, 30s);
me->m_Events.AddEventAtOffset([&] {
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY_ALL);
EmpowerOrb(true);
}, 61s);
});
}
void ScheduleBasicAbilities()
{
ScheduleTimedEvent(1s, [&] {
DoCastVictim(SPELL_SOUL_FLAY);
}, 4s, 5s);
ScheduleTimedEvent(7s, [&] {
DoCastRandomTarget(SPELL_LEGION_LIGHTNING, 0, 40.0f);
}, _phase == PHASE_SACRIFICE ? 15s : 30s);
ScheduleTimedEvent(9s, [&] {
me->CastCustomSpell(SPELL_FIRE_BLOOM, SPELLVALUE_MAX_TARGETS, 5, me, TRIGGERED_NONE);
me->SetTarget(me->GetVictim()->GetGUID());
}, _phase == PHASE_SACRIFICE ? 20s : 40s);
if (_phase != PHASE_SACRIFICE)
{
ScheduleTimedEvent(10s, [&] {
for (uint8 i = 1; i < _phase; ++i)
{
float x = me->GetPositionX() + 18.0f * cos((i * 2.0f - 1.0f) * M_PI / 3.0f);
float y = me->GetPositionY() + 18.0f * std::sin((i * 2.0f - 1.0f) * M_PI / 3.0f);
if (Creature* orb = me->SummonCreature(NPC_SHIELD_ORB, x, y, 40.0f, 0, TEMPSUMMON_CORPSE_DESPAWN))
{
Movement::PointsArray movementArray;
movementArray.push_back(G3D::Vector3(x, y, 40.0f));
// generate movement array
for (uint8 j = 1; j < 20; ++j)
{
x = me->GetPositionX() + 18.0f * cos(((i * 2.0f - 1.0f) * M_PI / 3.0f) + (j / 20.0f * 2 * M_PI));
y = me->GetPositionY() + 18.0f * std::sin(((i * 2.0f - 1.0f) * M_PI / 3.0f) + (j / 20.0f * 2 * M_PI));
movementArray.push_back(G3D::Vector3(x, y, 40.0f));
}
Movement::MoveSplineInit init(orb);
init.MovebyPath(movementArray);
init.SetCyclic();
init.Launch();
}
}
}, 40s);
}
}
void EnterEvadeMode(EvadeReason why) override
@@ -310,8 +459,10 @@ struct boss_kiljaeden : public ScriptedAI
ScriptedAI::AttackStart(who);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
void DamageTaken(Unit* unit, uint32& damage, DamageEffectType damageType, SpellSchoolMask schoolMask) override
{
BossAI::DamageTaken(unit, damage, damageType, schoolMask);
if (damage >= me->GetHealth())
{
me->SetTarget();
@@ -323,9 +474,10 @@ struct boss_kiljaeden : public ScriptedAI
me->HandleEmoteCommand(EMOTE_ONESHOT_DROWN);
me->resetAttackTimer();
events.Reset();
events2.Reset();
events2.ScheduleEvent(EVENT_KILL_SELF, 500);
damage = 0;
me->m_Events.AddEventAtOffset([&] {
me->KillSelf();
}, 1s);
}
}
@@ -334,37 +486,28 @@ struct boss_kiljaeden : public ScriptedAI
Talk(SAY_KJ_DEATH);
instance->SetBossState(DATA_KILJAEDEN, DONE);
if (Creature* controller = instance->GetCreature(DATA_KJ_CONTROLLER))
Unit::Kill(controller, controller);
controller->KillSelf();
}
void DoAction(int32 param) override
{
if (param == ACTION_NO_KILL_TALK)
{
events.ScheduleEvent(EVENT_NO_KILL_TALK, 0);
Talk(SAY_KJ_DARKNESS);
}
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer() && events.GetNextEventTime(EVENT_NO_KILL_TALK) == 0)
if (victim->IsPlayer())
Talk(SAY_KJ_SLAY);
}
void JustEngagedWith(Unit* /*who*/) override
{
events2.ScheduleEvent(EVENT_TEXT_SPEACH11, 26000, EVENT_GROUP_SPEACH);
Talk(SAY_KJ_EMERGE);
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_JOIN, 26s);
events.SetTimer(200000);
events.ScheduleEvent(EVENT_CHECK_HEALTH85, 1000);
events.ScheduleEvent(EVENT_CHECK_HEALTH55, 1000);
events.ScheduleEvent(EVENT_CHECK_HEALTH25, 1000);
events.ScheduleEvent(EVENT_SPELL_SOUL_FLAY, 0);
events.ScheduleEvent(EVENT_SPELL_LEGION_LIGHTNING, 7000);
events.ScheduleEvent(EVENT_SPELL_FIRE_BLOOM, 9000);
events.ScheduleEvent(EVENT_SUMMON_ORBS, 10000);
Talk(SAY_KJ_EMERGE);
ScheduleBasicAbilities();
}
void JustSummoned(Creature* summon) override
@@ -382,247 +525,14 @@ struct boss_kiljaeden : public ScriptedAI
void UpdateAI(uint32 diff) override
{
events2.Update(diff);
switch (events2.ExecuteEvent())
{
case EVENT_KILL_SELF:
me->KillSelf();
break;
case EVENT_REBIRTH:
me->SetVisible(true);
me->CastSpell(me, SPELL_REBIRTH, false);
break;
case EVENT_EMPOWER_ORBS1:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY1);
EmpowerOrb(false);
break;
case EVENT_EMPOWER_ORBS2:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY2);
EmpowerOrb(false);
break;
case EVENT_EMPOWER_ORBS3:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_READY_ALL);
EmpowerOrb(true);
break;
case EVENT_INIT_FIGHT:
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetInCombatWithZone();
return;
case EVENT_TEXT_SPEACH11:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_JOIN);
break;
case EVENT_TEXT_SPEACH21:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_AWAKEN);
break;
case EVENT_TEXT_SPEACH22:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_IMPRISONED, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
break;
case EVENT_TEXT_SPEACH23:
Talk(SAY_KJ_PHASE3);
break;
case EVENT_TEXT_SPEACH31:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_LETGO);
break;
case EVENT_TEXT_SPEACH32:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_LOST, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
break;
case EVENT_TEXT_SPEACH33:
Talk(SAY_KJ_PHASE4);
break;
case EVENT_TEXT_SPEACH41:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_FOCUS);
break;
case EVENT_TEXT_SPEACH42:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_KALEC, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
break;
case EVENT_TEXT_SPEACH43:
if (Creature* kalec = instance->GetCreature(DATA_KALECGOS_KJ))
kalec->AI()->Talk(SAY_KALECGOS_FATE);
break;
case EVENT_TEXT_SPEACH44:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_GOODBYE, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
break;
case EVENT_TEXT_SPEACH45:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->RemoveAllAuras();
anveena->DespawnOrUnsummon(3500);
}
break;
case EVENT_TEXT_SPEACH46:
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
me->CastSpell(me, SPELL_CUSTOM_08_STATE, true);
me->SetUnitFlag(UNIT_FLAG_PACIFIED);
events.DelayEvents(7001);
events2.ScheduleEvent(EVENT_RESTORE_MELEE, 7000);
}
Talk(SAY_KJ_PHASE5);
break;
case EVENT_RESTORE_MELEE:
me->RemoveAurasDueToSpell(SPELL_CUSTOM_08_STATE);
me->RemoveUnitFlag(UNIT_FLAG_PACIFIED);
break;
}
if (me->GetReactState() != REACT_AGGRESSIVE)
return;
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_CHECK_HEALTH85:
if (me->HealthBelowPct(85))
{
phase = PHASE_DARKNESS;
events2.CancelEvent(EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH21, 16000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH22, 22000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH23, 28000, EVENT_GROUP_SPEACH);
events2.RescheduleEvent(EVENT_EMPOWER_ORBS1, 35000);
events.DelayEvents(2000);
events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
events.ScheduleEvent(EVENT_SPELL_FLAME_DART, 3000);
events.RescheduleEvent(EVENT_SPELL_DARKNESS, 16000); // will be delayed by 29 secs
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH85, 0);
break;
case EVENT_CHECK_HEALTH55:
if (me->HealthBelowPct(55))
{
phase = PHASE_ARMAGEDDON;
events2.CancelEventGroup(EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH31, 16000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH32, 22000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH33, 28000, EVENT_GROUP_SPEACH);
events2.RescheduleEvent(EVENT_EMPOWER_ORBS2, 35000);
events.DelayEvents(2000);
events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
events.RescheduleEvent(EVENT_SPELL_DARKNESS, 15000); // will be delayed by 29 secs
events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, 10000);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH55, 0);
break;
case EVENT_CHECK_HEALTH25:
if (me->HealthBelowPct(25))
{
phase = PHASE_SACRIFICE;
events2.CancelEventGroup(EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH41, 8000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH42, 18000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH43, 20200, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH44, 25000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH45, 28000, EVENT_GROUP_SPEACH);
events2.ScheduleEvent(EVENT_TEXT_SPEACH46, 30000, EVENT_GROUP_SPEACH);
events2.RescheduleEvent(EVENT_EMPOWER_ORBS3, 61000);
events.CancelEvent(EVENT_SUMMON_ORBS);
events.DelayEvents(4000);
events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
events.RescheduleEvent(EVENT_SPELL_DARKNESS, 15000); // will be delayed by 29 secs
events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, 1500);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH25, 0);
break;
case EVENT_SPELL_SOUL_FLAY:
me->CastSpell(me->GetVictim(), SPELL_SOUL_FLAY, false);
events.ScheduleEvent(EVENT_SPELL_SOUL_FLAY, urand(4000, 5000));
break;
case EVENT_SPELL_LEGION_LIGHTNING:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
me->CastSpell(target, SPELL_LEGION_LIGHTNING, false);
events.ScheduleEvent(EVENT_SPELL_LEGION_LIGHTNING, phase == PHASE_SACRIFICE ? 15000 : 30000);
events.RescheduleEvent(EVENT_SPELL_SOUL_FLAY, 2000);
break;
case EVENT_SPELL_FIRE_BLOOM:
me->CastCustomSpell(SPELL_FIRE_BLOOM, SPELLVALUE_MAX_TARGETS, 5, me, TRIGGERED_NONE);
me->SetTarget(me->GetVictim()->GetGUID());
events.ScheduleEvent(EVENT_SPELL_FIRE_BLOOM, phase == PHASE_SACRIFICE ? 20000 : 40000);
events.RescheduleEvent(EVENT_SPELL_SOUL_FLAY, 1500);
break;
case EVENT_SUMMON_ORBS:
for (uint8 i = 1; i < phase; ++i)
{
float x = me->GetPositionX() + 18.0f * cos((i * 2.0f - 1.0f) * M_PI / 3.0f);
float y = me->GetPositionY() + 18.0f * std::sin((i * 2.0f - 1.0f) * M_PI / 3.0f);
if (Creature* orb = me->SummonCreature(NPC_SHIELD_ORB, x, y, 40.0f, 0, TEMPSUMMON_CORPSE_DESPAWN))
{
Movement::PointsArray movementArray;
movementArray.push_back(G3D::Vector3(x, y, 40.0f));
// generate movement array
for (uint8 j = 1; j < 20; ++j)
{
x = me->GetPositionX() + 18.0f * cos(((i * 2.0f - 1.0f) * M_PI / 3.0f) + (j / 20.0f * 2 * M_PI));
y = me->GetPositionY() + 18.0f * std::sin(((i * 2.0f - 1.0f) * M_PI / 3.0f) + (j / 20.0f * 2 * M_PI));
movementArray.push_back(G3D::Vector3(x, y, 40.0f));
}
Movement::MoveSplineInit init(orb);
init.MovebyPath(movementArray);
init.SetCyclic();
init.Launch();
}
}
events.ScheduleEvent(EVENT_SUMMON_ORBS, 40000);
break;
case EVENT_SPELL_SHADOW_SPIKE:
events.DelayEvents(27000);
me->CastSpell(me, SPELL_SHADOW_SPIKE, false);
break;
case EVENT_SPELL_SINISTER_REFLECTION:
Talk(SAY_KJ_REFLECTION);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
break;
case EVENT_SPELL_FLAME_DART:
me->CastSpell(me, SPELL_FLAME_DART, false);
events.ScheduleEvent(EVENT_SPELL_FLAME_DART, 10000);
break;
case EVENT_SPELL_DARKNESS:
Talk(EMOTE_KJ_DARKNESS);
me->CastSpell(me, SPELL_DARKNESS_OF_A_THOUSAND_SOULS, false);
events.ScheduleEvent(EVENT_SPELL_DARKNESS, phase == PHASE_SACRIFICE ? 20000 : 45000);
events.DelayEvents(8000);
break;
case EVENT_SPELL_ARMAGEDDON:
me->CastSpell(me, SPELL_ARMAGEDDON_PERIODIC, true);
events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, phase == PHASE_SACRIFICE ? 20000 : 40000);
break;
}
DoMeleeAttackIfReady();
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void EmpowerOrb(bool empowerAll)
@@ -647,6 +557,9 @@ struct boss_kiljaeden : public ScriptedAI
}
}
}
private:
uint8 _phase;
};
enum postEvent
@@ -712,9 +625,7 @@ enum postEvent
class MoveDelayed : public BasicEvent
{
public:
MoveDelayed(Creature* owner, float x, float y, float z, float o) : _owner(owner), _x(x), _y(y), _z(z), _o(o)
{
}
MoveDelayed(Creature* owner, float x, float y, float z, float o) : _owner(owner), _x(x), _y(y), _z(z), _o(o) { }
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
{
@@ -733,9 +644,7 @@ private:
class FixOrientation : public BasicEvent
{
public:
FixOrientation(Creature* owner) : _owner(owner)
{
}
FixOrientation(Creature* owner) : _owner(owner) { }
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
{
@@ -46,7 +46,7 @@ ObjectData const creatureData[] =
{ NPC_KILJAEDEN_CONTROLLER, DATA_KJ_CONTROLLER },
{ NPC_ANVEENA, DATA_ANVEENA },
{ NPC_KALECGOS_KJ, DATA_KALECGOS_KJ },
{ 0, 0, }
{ 0, 0 }
};
ObjectData const gameObjectData[] =
@@ -59,6 +59,20 @@ ObjectData const gameObjectData[] =
{ 0, 0 }
};
ObjectData const summonData[] =
{
{ NPC_DEMONIC_VAPOR_TRAIL, DATA_FELMYST },
{ NPC_UNYIELDING_DEAD, DATA_FELMYST },
{ NPC_DARKNESS, DATA_MURU },
{ NPC_VOID_SENTINEL, DATA_MURU },
{ NPC_VOID_SPAWN, DATA_MURU },
{ NPC_FELFIRE_PORTAL, DATA_KJ_CONTROLLER },
{ NPC_VOLATILE_FELFIRE_FIEND, DATA_KJ_CONTROLLER },
{ NPC_SHIELD_ORB, DATA_KJ_CONTROLLER },
{ NPC_SINISTER_REFLECTION, DATA_KJ_CONTROLLER },
{ 0, 0 }
};
class instance_sunwell_plateau : public InstanceMapScript
{
public:
@@ -72,6 +86,7 @@ public:
SetBossNumber(MAX_ENCOUNTERS);
LoadDoorData(doorData);
LoadObjectData(creatureData, gameObjectData);
LoadSummonData(summonData);
}
void OnPlayerEnter(Player* player) override
@@ -87,32 +102,6 @@ public:
if (creature->GetSpawnId() > 0 || !creature->GetOwnerGUID().IsPlayer())
creature->CastSpell(creature, SPELL_SUNWELL_RADIANCE, true);
switch (creature->GetEntry())
{
case NPC_DEMONIC_VAPOR_TRAIL:
case NPC_UNYIELDING_DEAD:
if (Creature* felmyst = GetCreature(DATA_FELMYST))
felmyst->AI()->JustSummoned(creature);
break;
case NPC_DARKNESS:
case NPC_VOID_SENTINEL:
case NPC_VOID_SPAWN:
if (Creature* muru = GetCreature(DATA_MURU))
muru->AI()->JustSummoned(creature);
break;
case NPC_FELFIRE_PORTAL:
case NPC_VOLATILE_FELFIRE_FIEND:
case NPC_SHIELD_ORB:
case NPC_SINISTER_REFLECTION:
if (Creature* kiljaedenC = GetCreature(DATA_KJ_CONTROLLER))
kiljaedenC->AI()->JustSummoned(creature);
break;
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
};
@@ -52,24 +52,22 @@ enum Says
enum Misc
{
ACTION_INCREASE_STORM_COUNT = 1
ACTION_STORM_EXPIRE = 1,
GROUP_ELECTRICAL_STORM = 1
};
constexpr auto NPC_SOARING_EAGLE = 24858;
struct boss_akilzon : public BossAI
{
boss_akilzon(Creature* creature) : BossAI(creature, DATA_AKILZON), _stormCount(0), _isRaining(false) { }
boss_akilzon(Creature* creature) : BossAI(creature, DATA_AKILZON), _isRaining(false) { }
void Reset() override
{
_Reset();
_targetGUID.Clear();
_cloudGUID.Clear();
_cycloneGUID.Clear();
_stormCount = 0;
_isRaining = false;
SetWeather(WEATHER_STATE_FINE, 0.0f);
@@ -94,18 +92,16 @@ struct boss_akilzon : public BossAI
}, 10s, 18s);
ScheduleTimedEvent(20s, 30s, [&] {
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
if (!target)
target = me->GetVictim();
if (target)
DoCast(target, SPELL_GUST_OF_WIND);
if (scheduler.GetNextGroupOcurrence(GROUP_ELECTRICAL_STORM) > 5s)
DoCastRandomTarget(SPELL_GUST_OF_WIND, 1);
}, 20s, 30s);
ScheduleTimedEvent(10s, 20s, [&] {
DoCastVictim(SPELL_CALL_LIGHTNING);
}, 12s, 17s);
ScheduleTimedEvent(1min, [&] {
scheduler.Schedule(1min, GROUP_ELECTRICAL_STORM, [this](TaskContext context)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50, true);
if (!target)
{
@@ -114,29 +110,14 @@ struct boss_akilzon : public BossAI
}
target->CastSpell(target, SPELL_ELECTRICAL_STORM_AREA, true); // cloud visual
DoCast(target, SPELL_ELECTRICAL_STORM); // storm cyclon + visual
float x, y, z;
target->GetPosition(x, y, z);
target->GetMotionMaster()->MoveJump(x, y, target->GetPositionZ() + 16.0f, 1.0f, 1.0f);
Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ() + 16, 0, 15000);
if (Cloud)
{
target->GetMotionMaster()->MoveJump(Cloud->GetPosition(), 1.0f, 1.0f);
_cloudGUID = Cloud->GetGUID();
Cloud->SetDisableGravity(true);
Cloud->StopMoving();
Cloud->SetObjectScale(1.0f);
Cloud->SetFaction(FACTION_FRIENDLY);
Cloud->SetMaxHealth(9999999);
Cloud->SetHealth(9999999);
Cloud->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->m_Events.AddEventAtOffset([&] {
HandleStormSequence();
}, 3s);
}
_stormCount = 1;
me->m_Events.AddEventAtOffset([&] {
HandleStormSequence();
}, 3s);
me->m_Events.AddEventAtOffset([&] {
if (!_isRaining)
@@ -145,7 +126,9 @@ struct boss_akilzon : public BossAI
_isRaining = true;
}
}, Seconds(urand(47, 52)));
}, 1min);
context.Repeat();
});
ScheduleTimedEvent(47s, 52s, [&] {
if (!_isRaining)
@@ -181,42 +164,26 @@ struct boss_akilzon : public BossAI
me->GetMap()->SetZoneWeather(me->GetZoneId(), WeatherState(weather), grade);
}
void HandleStormSequence() // 1: begin, 2-9: tick, 10: end
void HandleStormSequence()
{
Creature* Cloud = ObjectAccessor::GetCreature(*me, _cloudGUID);
if (!Cloud)
return;
if (_stormCount > 10)
{
_stormCount = 0; // finish
me->m_Events.AddEventAtOffset([&] {
SummonEagles();
}, 5s);
me->InterruptNonMeleeSpells(false);
_cloudGUID.Clear();
if (Cloud)
Cloud->KillSelf();
SetWeather(WEATHER_STATE_FINE, 0.0f);
_isRaining = false;
}
me->m_Events.AddEventAtOffset([&] {
Unit* target = ObjectAccessor::GetUnit(*me, _cloudGUID);
if (!target || !target->IsAlive())
return;
else if (Unit* Cyclone = ObjectAccessor::GetUnit(*me, _cycloneGUID))
Cyclone->CastSpell(target, SPELL_SAND_STORM, true); // keep casting or...
HandleStormSequence();
}, 1s);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_INCREASE_STORM_COUNT)
++_stormCount;
if (actionId == ACTION_STORM_EXPIRE)
{
me->m_Events.AddEventAtOffset([&] {
SummonEagles();
}, 5s);
me->InterruptNonMeleeSpells(false);
SetWeather(WEATHER_STATE_FINE, 0.0f);
_isRaining = false;
}
}
void SummonEagles()
@@ -254,8 +221,6 @@ private:
ObjectGuid _birdGUIDs[8];
ObjectGuid _targetGUID;
ObjectGuid _cycloneGUID;
ObjectGuid _cloudGUID;
uint8 _stormCount;
bool _isRaining;
};
@@ -339,15 +304,15 @@ class spell_electrial_storm : public AuraScript
return GetCaster() && GetCaster()->IsCreature();
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetCaster())
GetCaster()->ToCreature()->AI()->DoAction(ACTION_INCREASE_STORM_COUNT);
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
GetCaster()->ToCreature()->AI()->DoAction(ACTION_STORM_EXPIRE);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_electrial_storm::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
AfterEffectRemove += AuraEffectRemoveFn(spell_electrial_storm::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
}
};
@@ -27,56 +27,61 @@ enum Spells
SPELL_FRENZY = 43139,
SPELL_FLAMESHOCK = 43303,
SPELL_EARTHSHOCK = 43305,
SPELL_TRANSFORM_SPLIT = 43142,
SPELL_TRANSFORM_SPLIT2 = 43573,
SPELL_TRANSFORM_MERGE = 43271,
SPELL_SUMMON_LYNX = 43143,
SPELL_SUMMON_TOTEM = 43302,
SPELL_BERSERK = 45078,
SPELL_LYNX_FRENZY = 43290, // Used by Spirit Lynx
SPELL_SHRED_ARMOR = 43243 // Used by Spirit Lynx
SPELL_SHRED_ARMOR = 43243, // Used by Spirit Lynx
SPELL_TRANSFORM_DUMMY = 43615, // Used by Spirit Lynx
SPELL_TRANSFIGURE = 44054,
SPELL_TRANSFORM_TO_LYNX_75 = 43145,
SPELL_TRANSFORM_TO_LYNX_50 = 43271,
SPELL_TRANSFORM_TO_LYNX_25 = 43272
};
enum UniqueEvents
{
EVENT_BERSERK = 0
EVENT_BERSERK = 1
};
enum Hal_CreatureIds
{
NPC_TOTEM = 24224
NPC_HALAZZI_TROLL = 24144, // dummy creature - used to update model, stats
NPC_TOTEM = 24224
};
enum PhaseHalazzi
{
PHASE_NONE = 0,
PHASE_LYNX = 1,
PHASE_SPLIT = 2,
PHASE_HUMAN = 3,
PHASE_MERGE = 4,
PHASE_ENRAGE = 5
PHASE_NONE = 0,
PHASE_LYNX = 1,
PHASE_SPLIT = 2,
PHASE_HUMAN = 3,
PHASE_MERGE = 4,
PHASE_ENRAGE = 5
};
enum Yells
{
SAY_AGGRO = 0,
SAY_KILL = 1,
SAY_SABER = 2,
SAY_SPLIT = 3,
SAY_MERGE = 4,
SAY_DEATH = 5
SAY_AGGRO = 0,
SAY_KILL = 1,
SAY_SABER = 2,
SAY_SPLIT = 3,
SAY_MERGE = 4,
SAY_DEATH = 5
};
enum Groups
{
GROUP_LYNX = 0,
GROUP_HUMAN = 1,
GROUP_MERGE = 2
GROUP_LYNX = 0,
GROUP_HUMAN = 1,
GROUP_MERGE = 3,
GROUP_SPLIT = 4
};
enum Actions
{
ACTION_MERGE = 0
ACTION_MERGE = 0
};
struct boss_halazzi : public BossAI
@@ -91,22 +96,11 @@ struct boss_halazzi : public BossAI
void Reset() override
{
me->UpdateEntry(NPC_HALAZZI);
BossAI::Reset();
_transformCount = 0;
_healthCheckPercentage = 0;
_phase = PHASE_NONE;
_lynxFormHealth = me->GetMaxHealth();
_healthPortion = _lynxFormHealth/4;
_humanFormHealth = (me->GetMaxHealth())/0.66666666;
EnterPhase(PHASE_LYNX);
DoCastSelf(SPELL_DUAL_WIELD, true);
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
summon->Attack(me->GetVictim(), false);
summon->SetInCombatWithZone();
SetInvincibility(true);
}
void JustEngagedWith(Unit* who) override
@@ -120,30 +114,35 @@ struct boss_halazzi : public BossAI
EnterPhase(PHASE_LYNX);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override
{
if (damage >= me->GetHealth() && _phase != PHASE_ENRAGE)
damage = 0;
else
BossAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask);
if (_phase == PHASE_LYNX || _phase == PHASE_ENRAGE)
{
if (_phase == PHASE_LYNX || _phase == PHASE_ENRAGE)
{
_healthCheckPercentage = 25 * (3 - _transformCount);
if (!HealthAbovePct(_healthCheckPercentage))
EnterPhase(PHASE_SPLIT);
}
else if (_phase == PHASE_HUMAN)
{
if (!HealthAbovePct(20))
EnterPhase(PHASE_MERGE);
}
uint32 _healthCheckPercentage = 25 * (3 - _transformCount);
if (!HealthAbovePct(_healthCheckPercentage))
EnterPhase(PHASE_SPLIT);
}
else if (_phase == PHASE_HUMAN)
{
if (!HealthAbovePct(20))
EnterPhase(PHASE_MERGE);
}
}
void SpellHit(Unit*, SpellInfo const* spell) override
{
if (spell->Id == SPELL_TRANSFORM_SPLIT2)
EnterPhase(PHASE_HUMAN);
if (spell->Id == SPELL_TRANSFORM_DUMMY)
me->UpdateEntry(NPC_HALAZZI_TROLL);
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
if (summon->GetEntry() == NPC_TOTEM)
summon->Attack(me->GetVictim(), false);
}
void AttackStart(Unit* who) override
@@ -156,17 +155,39 @@ struct boss_halazzi : public BossAI
{
switch (nextPhase)
{
case PHASE_LYNX:
case PHASE_ENRAGE:
if (_phase == PHASE_MERGE)
SetInvincibility(false);
scheduler.Schedule(12s, GROUP_LYNX, [this](TaskContext context)
{
DoCastSelf(SPELL_TRANSFORM_MERGE, true);
me->RemoveAurasDueToSpell(SPELL_TRANSFORM_SPLIT2);
DoCastSelf(SPELL_SUMMON_TOTEM);
context.Repeat(20s);
});
[[fallthrough]];
case PHASE_LYNX:
{
if (_phase == PHASE_MERGE)
me->ResumeChasingVictim();
}
summons.DespawnAll();
me->SetMaxHealth(_lynxFormHealth);
me->SetHealth(_lynxFormHealth - _healthPortion * _transformCount);
if (_transformCount)
{
me->UpdateEntry(NPC_HALAZZI);
switch (_transformCount)
{
case 1:
DoCastSelf(SPELL_TRANSFORM_TO_LYNX_75, true);
break;
case 2:
DoCastSelf(SPELL_TRANSFORM_TO_LYNX_50, true);
break;
case 3:
DoCastSelf(SPELL_TRANSFORM_TO_LYNX_25, true);
break;
default:
break;
}
}
scheduler.CancelGroup(GROUP_MERGE);
scheduler.Schedule(16s, GROUP_LYNX, [this](TaskContext context)
{
@@ -179,15 +200,18 @@ struct boss_halazzi : public BossAI
context.Repeat(30s);
});
break;
}
case PHASE_SPLIT:
Talk(SAY_SPLIT);
DoCastSelf(SPELL_TRANSFORM_SPLIT, true);
break;
DoCastSelf(SPELL_TRANSFIGURE, true);
scheduler.Schedule(3s, GROUP_SPLIT, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_SUMMON_LYNX, true);
});
nextPhase = PHASE_HUMAN;
[[fallthrough]];
case PHASE_HUMAN:
scheduler.CancelGroup(GROUP_MERGE);
DoCastSelf(SPELL_SUMMON_LYNX, true);
me->SetMaxHealth(_humanFormHealth);
me->SetHealth(_humanFormHealth);
scheduler.CancelGroup(GROUP_LYNX);
scheduler.Schedule(10s, GROUP_HUMAN, [this](TaskContext context)
{
@@ -255,11 +279,7 @@ struct boss_halazzi : public BossAI
Talk(SAY_DEATH);
}
private:
uint32 _lynxFormHealth;
uint32 _humanFormHealth;
uint32 _healthPortion;
uint8 _transformCount;
uint32 _healthCheckPercentage;
PhaseHalazzi _phase;
};
@@ -89,7 +89,7 @@ enum Spells
// Rogue
SPELL_RO_BLIND = 43433,
SPELL_RO_SLICE_DICE = 43457,
SPELL_RO_SLICE_DICE = 43547,
SPELL_RO_WOUND_POISON = 43461,
// Shaman
@@ -154,8 +154,14 @@ struct PlayerAbilityStruct
std::chrono::milliseconds cooldown;
};
static PlayerAbilityStruct PlayerAbility[12][3] =
static PlayerAbilityStruct PlayerAbility[13][3] =
{
// 0 UNK class (should never be set)
{
{ 0, ABILITY_TARGET_SELF, 0ms},
{ 0, ABILITY_TARGET_SELF, 0ms},
{ 0, ABILITY_TARGET_SELF, 0ms}
},
// 1 warrior
{ { SPELL_WR_SPELL_REFLECT, ABILITY_TARGET_SELF, 10000ms },
{ SPELL_WR_WHIRLWIND, ABILITY_TARGET_SELF, 10000ms },
@@ -268,7 +274,7 @@ struct boss_hexlord_malacrass : public BossAI
siphonTrigger->AI()->DoCast(target, SPELL_SIPHON_SOUL, true);
siphonTrigger->GetMotionMaster()->MoveChase(me);
if (Player* player = target->ToPlayer())
_currentClass = player->HasAura(AURA_SHADOW_FORM) ? ADDITIONAL_CLASS_SPRIEST : player->getClass() - 1;
_currentClass = player->HasAura(AURA_SHADOW_FORM) ? uint8(ADDITIONAL_CLASS_SPRIEST) : player->getClass();
}
}
});
@@ -65,7 +65,6 @@ enum Spells
enum Creatures
{
NPC_AMANI_HATCHER = 23818,
NPC_HATCHLING = 23598, // 42493
NPC_EGG = 23817,
NPC_FIRE_BOMB = 23920
};
@@ -110,10 +109,9 @@ enum HatchActions
enum Misc
{
MAX_BOMB_COUNT = 40,
SCHEDULER_GROUP_HATCHING = 1,
EVENT_BERSERK = 0
GROUP_ENRAGE = 1,
GROUP_HATCHING = 2,
DATA_ALL_EGGS_HATCHED = 0
};
struct boss_janalai : public BossAI
@@ -142,9 +140,15 @@ struct boss_janalai : public BossAI
DoCastAOE(SPELL_HATCH_ALL);
});
ScheduleHealthCheckEvent(25, [&] {
DoCastSelf(SPELL_ENRAGE, true);
ScheduleHealthCheckEvent(20, [&] {
if (!me->HasAura(SPELL_ENRAGE))
DoCastSelf(SPELL_ENRAGE, true);
me->m_Events.CancelEventGroup(GROUP_ENRAGE);
});
me->m_Events.KillAllEvents(false);
_sideHatched[0] = false;
_sideHatched[1] = false;
}
void JustDied(Unit* killer) override
@@ -153,6 +157,19 @@ struct boss_janalai : public BossAI
BossAI::JustDied(killer);
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_AMANI_HATCHLING)
{
if (summon->GetPositionY() > 1150)
summon->GetMotionMaster()->MovePoint(0, hatcherway[0][3].GetPositionX() + rand() % 4 - 2, 1150.0f + rand() % 4 - 2, hatcherway[0][3].GetPositionY());
else
summon->GetMotionMaster()->MovePoint(0, hatcherway[1][3].GetPositionX() + rand() % 4 - 2, 1150.0f + rand() % 4 - 2, hatcherway[1][3].GetPositionY());
}
BossAI::JustSummoned(summon);
}
void DamageDealt(Unit* target, uint32& damage, DamageEffectType /*damagetype*/) override
{
if (_isFlameBreathing)
@@ -170,14 +187,33 @@ struct boss_janalai : public BossAI
ScheduleTimedEvent(30s, [&]{
StartBombing();
}, 20s, 40s);
ScheduleTimedEvent(10s, [&]{
if (HatchAllEggs(HATCH_RESET))
scheduler.Schedule(10s, GROUP_HATCHING, [this](TaskContext context)
{
if (_sideHatched[0] && _sideHatched[1])
return;
Talk(SAY_SUMMON_HATCHER);
if (_sideHatched[0] && !_sideHatched[1])
{
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[1][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[1][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
}
else if (!_sideHatched[0] && _sideHatched[1])
{
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[0][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[0][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
}
else
{
Talk(SAY_SUMMON_HATCHER);
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[0][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
me->SummonCreature(NPC_AMANI_HATCHER, hatcherway[1][0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000);
}
}, 90s);
context.Repeat(90s);
});
ScheduleTimedEvent(8s, [&]{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
@@ -193,10 +229,21 @@ struct boss_janalai : public BossAI
});
}
}, 8s);
ScheduleUniqueTimedEvent(5min, [&]{
me->m_Events.AddEventAtOffset([&] {
DoCastSelf(SPELL_ENRAGE, true);
}, 5min, 5min, GROUP_ENRAGE);
me->m_Events.AddEventAtOffset([&] {
Talk(SAY_BERSERK);
DoCastSelf(SPELL_BERSERK);
}, EVENT_BERSERK);
}, 10min);
}
void SetData(uint32 index, uint32 data) override
{
if (index == DATA_ALL_EGGS_HATCHED)
_sideHatched[data] = true;
}
bool HatchAllEggs(uint32 hatchAction)
@@ -211,11 +258,7 @@ struct boss_janalai : public BossAI
for (Creature* egg : eggList)
egg->Respawn();
std::list<Creature* > hatchlingList;
me->GetCreaturesWithEntryInRange(hatchlingList, 100.0f, NPC_HATCHLING);
for (Creature* hatchling : hatchlingList)
hatchling->DespawnOrUnsummon();
hatchlingList.clear();
summons.DespawnEntry(NPC_AMANI_HATCHLING);
}
else if (hatchAction == HATCH_ALL)
DoCastSelf(SPELL_HATCH_EGG_ALL);
@@ -325,6 +368,7 @@ struct boss_janalai : public BossAI
private:
bool _isBombing;
bool _isFlameBreathing;
bool _sideHatched[2];
};
struct npc_janalai_hatcher : public ScriptedAI
@@ -337,6 +381,7 @@ struct npc_janalai_hatcher : public ScriptedAI
scheduler.CancelAll();
_side = (me->GetPositionY() < 1150);
_waypoint = 0;
_repeatCount = 1;
_isHatching = false;
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MovePoint(0, hatcherway[_side][0]);
@@ -348,12 +393,25 @@ struct npc_janalai_hatcher : public ScriptedAI
{
_isHatching = true;
scheduler.Schedule(1500ms, SCHEDULER_GROUP_HATCHING, [this](TaskContext context)
scheduler.Schedule(1500ms, [this](TaskContext context)
{
me->CastCustomSpell(SPELL_HATCH_EGG_ALL, SPELLVALUE_MAX_TARGETS, context.GetRepeatCounter() + 1);
me->CastCustomSpell(SPELL_HATCH_EGG_ALL, SPELLVALUE_MAX_TARGETS, _repeatCount);
++_repeatCount;
if (me->FindNearestCreature(NPC_EGG, 100.0f))
context.Repeat(4s);
else
{
if (WorldObject* summoner = GetSummoner())
if (Creature* janalai = summoner->ToCreature())
janalai->AI()->SetData(DATA_ALL_EGGS_HATCHED, _side);
_side = _side ? 0 : 1;
_isHatching = false;
_waypoint = 3;
MoveToNewWaypoint(_waypoint);
}
});
}
else
@@ -387,46 +445,12 @@ struct npc_janalai_hatcher : public ScriptedAI
private:
uint8 _side;
uint8 _waypoint;
uint32 _repeatCount;
bool _isHatching;
};
struct npc_janalai_hatchling : public ScriptedAI
{
npc_janalai_hatchling(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
scheduler.CancelAll();
if (me->GetPositionY() > 1150)
me->GetMotionMaster()->MovePoint(0, hatcherway[0][3].GetPositionX() + rand() % 4 - 2, 1150.0f + rand() % 4 - 2, hatcherway[0][3].GetPositionY());
else
me->GetMotionMaster()->MovePoint(0, hatcherway[1][3].GetPositionX() + rand() % 4 - 2, 1150.0f + rand() % 4 - 2, hatcherway[1][3].GetPositionY());
me->SetInCombatWithZone();
}
void JustEngagedWith(Unit* who) override
{
ScriptedAI::JustEngagedWith(who);
ScheduleTimedEvent(7s, [&]{
DoCastVictim(SPELL_FLAMEBUFFET);
}, 10s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
DoMeleeAttackIfReady();
}
};
void AddSC_boss_janalai()
{
RegisterZulAmanCreatureAI(boss_janalai);
RegisterZulAmanCreatureAI(npc_janalai_hatcher);
RegisterZulAmanCreatureAI(npc_janalai_hatchling);
}
@@ -15,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Nalorakk
SD%Complete: 100
SDComment:
SDCategory: Zul'Aman
EndScriptData */
#include "CellImpl.h"
#include "CreatureScript.h"
#include "GridNotifiers.h"
@@ -111,7 +104,6 @@ struct boss_nalorakk : public BossAI
_phase = PHASE_START_COMBAT;
me->SetReactState(REACT_AGGRESSIVE);
_active = false;
}
}
@@ -199,22 +191,12 @@ struct boss_nalorakk : public BossAI
me->GetCreaturesWithEntryInRange(_waveList, 25.0f, NPC_AMANISHI_MEDICINE_MAN);
GroupedAttack(_waveList);
Talk(SAY_WAVE4);
_introScheduler.Schedule(5s, GROUP_CHECK_DEAD, [this](TaskContext context)
{
if (CheckFullyDeadGroup(_waveList))
if (_phase == PHASE_SEND_GUARDS_4)
{
_introScheduler.CancelGroup(GROUP_CHECK_DEAD);
me->SetHomePosition(me->GetPosition());
me->SetImmuneToAll(false);
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
_waveList.clear();
_phase = PHASE_START_COMBAT;
_ranIntro = true;
}
context.Repeat(5s);
});
_waveList.clear();
_phase = PHASE_START_COMBAT;
_ranIntro = true;
me->SetImmuneToAll(false);
me->SetReactState(REACT_AGGRESSIVE);
me->SetHomePosition(me->GetPosition());
break;
}
}
@@ -236,7 +218,7 @@ struct boss_nalorakk : public BossAI
context.Repeat();
}).Schedule(10s, 15s, GROUP_HUMAN, [this](TaskContext context)
{
if (me->GetVictim() && !me->GetVictim()->HasAura(SPELL_MANGLEEFFECT))
if (me->GetVictim() && !me->GetVictim()->HasAura(SPELL_MANGLE))
{
DoCastVictim(SPELL_MANGLE);
context.Repeat(1s);
@@ -258,9 +240,11 @@ struct boss_nalorakk : public BossAI
if (currentlyInBearForm)
{
Talk(SAY_SHIFTEDTOTROLL);
me->RemoveAurasDueToSpell(SPELL_BEARFORM);
scheduler.CancelGroup(GROUP_BEAR);
_bearForm = false;
me->SetCanDualWield(true);
scheduler.Schedule(15s, 20s, GROUP_HUMAN, [this](TaskContext context)
{
Talk(SAY_SURGE);
@@ -290,6 +274,9 @@ struct boss_nalorakk : public BossAI
DoCastSelf(SPELL_BEARFORM, true);
scheduler.CancelGroup(GROUP_HUMAN);
_bearForm = true;
me->SetCanDualWield(false);
scheduler.Schedule(2s, GROUP_BEAR, [this](TaskContext context)
{
DoCastVictim(SPELL_LACERATINGSLASH);
@@ -302,10 +289,9 @@ struct boss_nalorakk : public BossAI
{
DoCastSelf(SPELL_DEAFENINGROAR);
context.Repeat(15s, 20s);
}).Schedule(25s, 30s, GROUP_BEAR, [this](TaskContext context)
}).Schedule(30s, GROUP_BEAR, [this](TaskContext)
{
ShapeShift(_bearForm);
context.Repeat();
});
}
}
@@ -201,7 +201,7 @@ struct boss_zuljin : public BossAI
ScheduleHealthCheckEvent({ 40 }, [&] {
EnterPhase(PHASE_LYNX);
me->RemoveAurasDueToSpell(SPELL_ENERGY_STORM);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ENERGY_STORM);
me->RemoveOwnedAura(SPELL_ENERGY_STORM);
summons.DespawnEntry(CREATURE_FEATHER_VORTEX);
me->ResumeChasingVictim();
@@ -268,6 +268,10 @@ struct boss_zuljin : public BossAI
instance->SetBossState(DATA_ZULJIN, DONE);
Talk(SAY_DEATH);
summons.DespawnEntry(CREATURE_COLUMN_OF_FIRE);
me->m_Events.AddEventAtOffset( [this] {
summons.DespawnAll();
}, 3s);
}
void SpawnAdds()
@@ -49,15 +49,17 @@ Position const HarrisonJonesLoc = {120.687f, 1674.0f, 42.0217f, 1.59044f};
DoorData const doorData[] =
{
{ GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM },
{ GO_DOOR_HALAZZI, DATA_HALAZZI, DOOR_TYPE_ROOM },
{ GO_DOOR_AKILZON, DATA_AKILZON, DOOR_TYPE_ROOM },
{ GO_GATE_ZULJIN, DATA_HEXLORD, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
{ GO_ZULJIN_FIREWALL, DATA_ZULJIN, DOOR_TYPE_ROOM },
{ GO_DOOR_HALAZZI, DATA_HALAZZI, DOOR_TYPE_PASSAGE },
{ GO_LYNX_TEMPLE_ENTRANCE, DATA_HALAZZI, DOOR_TYPE_ROOM },
{ GO_DOOR_AKILZON, DATA_AKILZON, DOOR_TYPE_ROOM },
{ GO_GATE_ZULJIN, DATA_HEXLORD, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
ObjectData const creatureData[] =
{
{ NPC_JANALAI, DATA_JANALAI },
{ NPC_SPIRIT_LYNX, DATA_SPIRIT_LYNX },
{ NPC_HARRISON_JONES, DATA_HARRISON_JONES },
{ 0, 0 }
@@ -71,6 +73,12 @@ ObjectData const gameObjectData[] =
{ 0, 0 }
};
ObjectData const summonData[] =
{
{ NPC_AMANI_HATCHLING, DATA_JANALAI },
{ 0, 0 }
};
BossBoundaryData const boundaries =
{
{ DATA_HEXLORD, new RectangleBoundary(80.50557f, 920.9858f, 155.88986f, 1015.27563f)}
@@ -93,6 +101,7 @@ public:
LoadObjectData(creatureData, gameObjectData);
LoadBossBoundaries(boundaries);
LoadDoorData(doorData);
LoadSummonData(summonData);
for (uint8 i = 0; i < RAND_VENDOR; ++i)
RandVendor[i] = NOT_STARTED;
@@ -323,31 +323,23 @@ enum Spells
SPELL_COSMETIC_SPEAR_THROW = 43647
};
enum Events
enum Phases
{
GONG_EVENT_1 = 1,
GONG_EVENT_2 = 2,
GONG_EVENT_3 = 3,
GONG_EVENT_4 = 4,
GONG_EVENT_5 = 5,
GONG_EVENT_6 = 6,
GONG_EVENT_7 = 7,
GONG_EVENT_8 = 8,
GONG_EVENT_9 = 9,
GONG_EVENT_10 = 10,
GONG_EVENT_11 = 11
PHASE_GONG = 0,
PHASE_GATE_CLOSED = 1,
PHASE_GATE_OPENED = 2
};
enum Actions
{
ACTION_COMPLETE_EVENT_3 = 0,
ACTION_COMPLETE_GONG_RITUAL = 0
};
enum Waypoints
{
HARRISON_MOVE_1 = 860440,
HARRISON_MOVE_2 = 860441,
HARRISON_MOVE_3 = 860442
HARRISON_MOVE_1 = 2435800,
HARRISON_MOVE_2 = 2435801,
HARRISON_MOVE_3 = 2435802
};
enum DisplayIds
@@ -379,9 +371,8 @@ struct npc_harrison_jones : public ScriptedAI
void Reset() override
{
_gongEvent = 0;
_gongTimer = 0;
uiTargetGUID.Clear();
_phase = PHASE_GONG;
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void JustEngagedWith(Unit* /*who*/) override { }
@@ -394,8 +385,10 @@ struct npc_harrison_jones : public ScriptedAI
me->SetFacingToObject(player);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
Talk(SAY_HARRISON_0);
_gongEvent = GONG_EVENT_1;
_gongTimer = 4000;
scheduler.Schedule(2s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(HARRISON_MOVE_1, false);
});
}
}
@@ -403,12 +396,16 @@ struct npc_harrison_jones : public ScriptedAI
{
if (spell->Id == SPELL_COSMETIC_SPEAR_THROW)
{
me->RemoveAllAuras();
me->RemoveAllAuras(); // remove stealth
me->SetEntry(NPC_HARRISON_JONES_2);
me->SetDisplayId(MODEL_HARRISON_JONES_2);
me->SetTarget();
me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_DEAD);
me->SetDynamicFlag(UNIT_DYNFLAG_DEAD);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->PlayDistanceSound(1332); // human male death
me->HandleEmoteCommand(EMOTE_ONESHOT_WOUND_CRITICAL);
me->StopMoving();
scheduler.Schedule(1s, [this](TaskContext /*task*/)
{
me->SetStandState(UNIT_STAND_STATE_DEAD);
});
_instance->StorePersistentData(DATA_TIMED_RUN, 21);
_instance->DoAction(ACTION_START_TIMED_RUN);
me->DespawnOrUnsummon(3min+30s, 0s);
@@ -417,132 +414,103 @@ struct npc_harrison_jones : public ScriptedAI
void DoAction(int32 action) override
{
if (action == ACTION_COMPLETE_EVENT_3)
if (action == ACTION_COMPLETE_GONG_RITUAL)
{
me->GetMap()->ToInstanceMap()->PermBindAllPlayers();
_gongEvent = GONG_EVENT_4;
_gongTimer = 0;
_phase = PHASE_GATE_CLOSED;
me->RemoveAura(SPELL_BANGING_THE_GONG);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0));
if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG))
gong->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
// Players are Now Saved to instance at SPECIAL (Player should be notified?)
scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(HARRISON_MOVE_2, false);
});
}
}
void OpenMassiveGateAndCallGuards()
{
if (GameObject* gate = _instance->GetGameObject(DATA_MASSIVE_GATE))
{
gate->AllowSaveToDB(true);
gate->SetGoState(GO_STATE_ACTIVE);
}
std::list<Creature*> targetList;
GetCreatureListWithEntryInGrid(targetList, me, NPC_AMANISHI_GUARDIAN, 26.0f);
if (!targetList.empty())
{
for (auto const& creature : targetList)
{
if (creature)
{
creature->SetImmuneToPC(true);
creature->SetReactState(REACT_PASSIVE);
if (creature->GetPositionX() > 120)
{
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR));
creature->AI()->SetData(0, 1);
}
else
creature->AI()->SetData(0, 2);
}
}
}
}
void MovementInform(uint32 type, uint32 id) override
{
// at gong
if (type == WAYPOINT_MOTION_TYPE && id == 2 && _phase == PHASE_GONG)
{
if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG))
me->SetFacingToObject(gong);
scheduler.Schedule(2s, [this](TaskContext /*task*/)
{
Talk(SAY_HARRISON_1);
}).Schedule(7s, [this](TaskContext /*task*/)
{
DoCastSelf(SPELL_BANGING_THE_GONG);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_MACE));
me->SetFacingTo(5.9696f);
if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG))
gong->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
});
}
// to the massive gate
else if (type == WAYPOINT_MOTION_TYPE && id == 1 && _phase == PHASE_GATE_CLOSED)
{
me->SetEntry(NPC_HARRISON_JONES_1);
Talk(SAY_HARRISON_2);
}
// at massive gate
else if (type == WAYPOINT_MOTION_TYPE && id == 2 && _phase == PHASE_GATE_CLOSED)
{
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING);
Talk(SAY_HARRISON_3);
scheduler.Schedule(8s, [this](TaskContext /*task*/)
{
OpenMassiveGateAndCallGuards();
_phase = PHASE_GATE_OPENED;
}).Schedule(10s, [this](TaskContext /*task*/)
{
DoCastSelf(SPELL_STEALTH);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
me->GetMotionMaster()->MovePath(HARRISON_MOVE_3, false);
});
}
}
void UpdateAI(uint32 diff) override
{
if (_gongEvent)
{
if (_gongTimer <= diff)
{
switch (_gongEvent)
{
case GONG_EVENT_1:
me->GetMotionMaster()->MovePath(HARRISON_MOVE_1, false);
_gongEvent = GONG_EVENT_2;
_gongTimer = 12000;
break;
case GONG_EVENT_2:
me->SetFacingTo(6.235659f);
Talk(SAY_HARRISON_1);
DoCastSelf(SPELL_BANGING_THE_GONG);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_MACE));
me->SetSheath(SHEATH_STATE_MELEE);
_gongEvent = GONG_EVENT_3;
_gongTimer = 4000;
break;
case GONG_EVENT_3:
if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG))
gong->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
break;
case GONG_EVENT_4:
me->RemoveAura(SPELL_BANGING_THE_GONG);
if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG))
gong->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
// Players are Now Saved to instance at SPECIAL (Player should be notified?)
me->GetMotionMaster()->MovePath(HARRISON_MOVE_2, false);
_gongEvent = GONG_EVENT_5;
_gongTimer = 5000;
break;
case GONG_EVENT_5:
me->SetEntry(NPC_HARRISON_JONES_1);
me->SetDisplayId(MODEL_HARRISON_JONES_1);
Talk(SAY_HARRISON_2);
_gongTimer = 12000;
_gongEvent = GONG_EVENT_6;
break;
case GONG_EVENT_6:
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING);
Talk(SAY_HARRISON_3);
_gongTimer = 7000;
_gongEvent = GONG_EVENT_7;
break;
case GONG_EVENT_7:
if (!uiTargetGUID)
{
std::list<Creature*> targetList;
GetCreatureListWithEntryInGrid(targetList, me, NPC_AMANISHI_GUARDIAN, 26.0f);
if (!targetList.empty())
{
for (auto const& creature : targetList)
{
if (creature)
{
creature->SetImmuneToPC(true);
creature->SetReactState(REACT_PASSIVE);
if (creature->GetPositionX() > 120)
{
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR));
creature->AI()->SetData(0, 1);
}
else
creature->AI()->SetData(0, 2);
}
}
}
}
if (GameObject* gate = _instance->GetGameObject(DATA_MASSIVE_GATE))
{
gate->AllowSaveToDB(true);
gate->SetGoState(GO_STATE_ACTIVE);
}
_gongTimer = 2000;
_gongEvent = GONG_EVENT_8;
break;
case GONG_EVENT_8:
DoCastSelf(SPELL_STEALTH);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0));
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
me->GetMotionMaster()->MovePath(HARRISON_MOVE_3, false);
_gongTimer = 1000;
_gongEvent = 0;
break;
case GONG_EVENT_9:
me->GetMotionMaster()->MovePoint(0, 120.687f, 1674.0f, 42.0217f);
_gongTimer = 12000;
_gongEvent = GONG_EVENT_10;
break;
case GONG_EVENT_10:
me->SetFacingTo(1.59044f);
_gongEvent = 11;
_gongTimer = 6000;
break;
case GONG_EVENT_11:
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
_gongEvent = 0;
_gongTimer = 1000;
break;
}
}
else
_gongTimer -= diff;
}
scheduler.Update(diff);
}
private:
InstanceScript* _instance;
uint8 _gongEvent;
uint32 _gongTimer;
ObjectGuid uiTargetGUID;
uint32 _phase;
};
class spell_ritual_of_power : public SpellScript
@@ -553,7 +521,7 @@ class spell_ritual_of_power : public SpellScript
{
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* creature = instance->GetCreature(DATA_HARRISON_JONES))
creature->AI()->DoAction(ACTION_COMPLETE_EVENT_3);
creature->AI()->DoAction(ACTION_COMPLETE_GONG_RITUAL);
}
void Register() override
@@ -53,14 +53,16 @@ enum CreatureIds
NPC_AMANISHI_WARBRINGER = 23580,
NPC_AMANISHI_TRIBESMAN = 23582,
NPC_AMANISHI_MEDICINE_MAN = 23581,
NPC_AMANISHI_AXE_THROWER = 23542
NPC_AMANISHI_AXE_THROWER = 23542,
NPC_AMANI_HATCHLING = 23598 // 42493
};
enum GameobjectIds
{
GO_DOOR_HALAZZI = 186303,
GO_GATE_ZULJIN = 186304,
GO_LYNX_TEMPLE_ENTRANCE = 186304,
GO_GATE_HEXLORD = 186305,
GO_GATE_ZULJIN = 186306,
GO_MASSIVE_GATE = 186728,
GO_DOOR_AKILZON = 186858,
GO_ZULJIN_FIREWALL = 186859,
@@ -20,12 +20,6 @@
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "zulgurub.h"
/* ScriptData
SDName: Boss_Gahz'ranka
SD%Complete: 85
SDComment: Massive Geyser with knockback not working. Spell buggy.
SDCategory: Zul'Gurub
EndScriptData */
enum Spells
{
@@ -36,89 +30,39 @@ enum Spells
SPELL_SPLASH = 24593
};
enum Events
{
EVENT_FROSTBREATH = 1,
EVENT_MASSIVEGEYSER = 2,
EVENT_SLAM = 3
};
enum Misc
{
GAMEOBJECT_MUDSKUNK_LURE = 180346
};
class boss_gahzranka : public CreatureScript
struct boss_gahzranka : public BossAI
{
public:
boss_gahzranka() : CreatureScript("boss_gahzranka") { }
boss_gahzranka(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) {}
struct boss_gahzrankaAI : public BossAI
void IsSummonedBy(WorldObject* /*summoner*/) override
{
boss_gahzrankaAI(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) { }
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
void Reset() override
{
_Reset();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
me->AddAura(SPELL_THRASH, me);
events.ScheduleEvent(EVENT_FROSTBREATH, 8s);
events.ScheduleEvent(EVENT_MASSIVEGEYSER, 25s);
events.ScheduleEvent(EVENT_SLAM, 15s);
}
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)
{
case EVENT_FROSTBREATH:
DoCastVictim(SPELL_FROSTBREATH);
events.ScheduleEvent(EVENT_FROSTBREATH, 8s, 20s);
break;
case EVENT_MASSIVEGEYSER:
DoCastVictim(SPELL_MASSIVEGEYSER);
events.ScheduleEvent(EVENT_MASSIVEGEYSER, 22s, 32s);
break;
case EVENT_SLAM:
DoCastVictim(SPELL_SLAM, true);
events.ScheduleEvent(EVENT_SLAM, 12s, 20s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
void JustEngagedWith(Unit* /*who*/) override
{
return GetZulGurubAI<boss_gahzrankaAI>(creature);
_JustEngagedWith();
me->AddAura(SPELL_THRASH, me);
ScheduleTimedEvent(8s, [&]
{
DoCastVictim(SPELL_FROSTBREATH);
}, 8s, 20s);
ScheduleTimedEvent(25s, [&]
{
DoCastVictim(SPELL_MASSIVEGEYSER);
}, 22s, 32s);
ScheduleTimedEvent(15s, [&]
{
DoCastVictim(SPELL_SLAM, true);
}, 12s, 20s);
}
};
@@ -129,23 +73,15 @@ class spell_gahzranka_slam : public SpellScript
void FilterTargets(std::list<WorldObject*>& targets)
{
if (Unit* caster = GetCaster())
{
_wipeThreat = targets.size() < caster->GetThreatMgr().GetThreatListSize();
}
}
void HandleWipeThreat(SpellEffIndex /*effIndex*/)
{
if (_wipeThreat)
{
if (Unit* caster = GetCaster())
{
if (Unit* target = GetHitUnit())
{
caster->GetThreatMgr().ModifyThreatByPercent(target, -100);
}
}
}
}
void Register() override
@@ -198,7 +134,7 @@ class spell_pagles_point_cast : public SpellScript
void AddSC_boss_gahzranka()
{
new boss_gahzranka();
RegisterZulGurubCreatureAI(boss_gahzranka);
RegisterSpellScript(spell_gahzranka_slam);
RegisterSpellScript(spell_pagles_point_cast);
}
@@ -501,7 +501,14 @@ class spell_pilgrims_bounty_feast_on_generic : public SpellScript
// Cast spirit of sharing
if (count >= 5)
{
player->RemoveAurasDueToSpell(SPELL_PLAYER_TURKEY);
player->RemoveAurasDueToSpell(SPELL_PLAYER_STUFFING);
player->RemoveAurasDueToSpell(SPELL_PLAYER_PIE);
player->RemoveAurasDueToSpell(SPELL_PLAYER_CRANBERRY);
player->RemoveAurasDueToSpell(SPELL_PLAYER_SWEET_POTATOES);
player->CastSpell(player, SPELL_SPIRIT_OF_SHARING, true);
}
}
}
}
@@ -33,14 +33,6 @@ enum Spells
SPELL_BERSERK = 26662
};
enum Events
{
EVENT_IMPALE = 1,
EVENT_LOCUST_SWARM = 2,
EVENT_BERSERK = 3,
EVENT_SPAWN_GUARD = 4
};
enum Misc
{
NPC_CORPSE_SCARAB = 16698,
@@ -61,17 +53,11 @@ public:
struct boss_anubrekhanAI : public BossAI
{
explicit boss_anubrekhanAI(Creature* c) : BossAI(c, BOSS_ANUB), summons(me)
boss_anubrekhanAI(Creature* c) : BossAI(c, BOSS_ANUB)
{
pInstance = c->GetInstanceScript();
sayGreet = false;
}
InstanceScript* pInstance;
EventMap events;
SummonList summons;
bool sayGreet;
void SummonCryptGuards()
{
if (Is25ManRaid())
@@ -84,16 +70,8 @@ public:
void Reset() override
{
BossAI::Reset();
events.Reset();
summons.DespawnAll();
SummonCryptGuards();
if (pInstance)
{
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_ANUB_GATE)))
{
go->SetGoState(GO_STATE_ACTIVE);
}
}
me->m_Events.KillAllEvents(false);
}
void JustSummoned(Creature* cr) override
@@ -102,9 +80,7 @@ public:
{
cr->SetInCombatWithZone();
if (cr->GetEntry() == NPC_CRYPT_GUARD)
{
cr->AI()->Talk(EMOTE_SPAWN, me);
}
}
summons.Summon(cr);
}
@@ -118,19 +94,10 @@ public:
}
}
void SummonedCreatureDespawn(Creature* cr) override
{
summons.Despawn(cr);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
summons.DespawnAll();
if (pInstance)
{
pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
void KilledUnit(Unit* victim) override
@@ -140,10 +107,7 @@ public:
Talk(SAY_SLAY);
victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID());
if (pInstance)
{
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
instance->SetData(DATA_IMMORTAL_FAIL, 0);
}
void JustEngagedWith(Unit* who) override
@@ -151,24 +115,36 @@ public:
BossAI::JustEngagedWith(who);
me->CallForHelp(30.0f);
Talk(SAY_AGGRO);
if (pInstance)
{
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_ANUB_GATE)))
{
go->SetGoState(GO_STATE_READY);
}
}
events.ScheduleEvent(EVENT_IMPALE, 15s);
events.ScheduleEvent(EVENT_LOCUST_SWARM, 70s, 120s);
events.ScheduleEvent(EVENT_BERSERK, 10min);
if (!summons.HasEntry(NPC_CRYPT_GUARD))
{
SummonCryptGuards();
}
if (!Is25ManRaid())
{
events.ScheduleEvent(EVENT_SPAWN_GUARD, 15s, 20s);
me->m_Events.AddEventAtOffset([&]
{
me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
}, Milliseconds(urand(15000, 20000)));
}
ScheduleTimedEvent(15s, [&] {
DoCastRandomTarget(RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25));
}, 20s);
ScheduleTimedEvent(70s, 2min, [&] {
Talk(EMOTE_LOCUST);
DoCastSelf(RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25));
me->m_Events.AddEventAtOffset([&]
{
me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
}, 3s);
}, 90s);
me->m_Events.AddEventAtOffset([&]
{
DoCastSelf(SPELL_BERSERK, true);
}, 10min);
}
void MoveInLineOfSight(Unit* who) override
@@ -181,54 +157,8 @@ public:
ScriptedAI::MoveInLineOfSight(who);
}
void UpdateAI(uint32 diff) override
{
if (!me->IsInCombat() && sayGreet)
{
for (SummonList::iterator itr = summons.begin(); itr != summons.end(); ++itr)
{
if (pInstance)
{
if (Creature* cr = pInstance->instance->GetCreature(*itr))
{
if (cr->IsInCombat())
DoZoneInCombat();
}
}
}
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_IMPALE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
me->CastSpell(target, RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25), false);
}
events.Repeat(20s);
break;
case EVENT_LOCUST_SWARM:
Talk(EMOTE_LOCUST);
me->CastSpell(me, RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25), false);
events.ScheduleEvent(EVENT_SPAWN_GUARD, 3s);
events.Repeat(90s);
break;
case EVENT_SPAWN_GUARD:
me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
break;
case EVENT_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
break;
}
DoMeleeAttackIfReady();
}
private:
bool sayGreet;
};
};
@@ -52,6 +52,12 @@ inline uint8 GetEruptionSection(float x, float y)
return 3;
}
DoorData const doorData[] =
{
{ GO_ANUB_GATE, BOSS_ANUB, DOOR_TYPE_ROOM },
{ 0, 0, DOOR_TYPE_ROOM },
};
ObjectData const creatureData[] =
{
{ NPC_RAZUVIOUS, DATA_RAZUVIOUS },
@@ -79,6 +85,7 @@ public:
{
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTERS);
LoadDoorData(doorData);
LoadObjectData(creatureData, gameObjectData);
for (auto& i : HeiganEruption)
i.clear();
@@ -115,7 +122,6 @@ public:
ObjectGuid _heiganGateGUID;
ObjectGuid _heiganGateExitGUID;
ObjectGuid _loathebGateGUID;
ObjectGuid _anubGateGUID;
ObjectGuid _anubNextGateGUID;
ObjectGuid _faerlinaWebGUID;
ObjectGuid _faerlinaGateGUID;
@@ -328,13 +334,6 @@ public:
pGo->SetGoState(GO_STATE_ACTIVE);
}
break;
case GO_ANUB_GATE:
_anubGateGUID = pGo->GetGUID();
if (GetBossState(BOSS_ANUB) == DONE)
{
pGo->SetGoState(GO_STATE_ACTIVE);
}
break;
case GO_ANUB_NEXT_GATE:
_anubNextGateGUID = pGo->GetGUID();
if (GetBossState(BOSS_ANUB) == DONE)
@@ -880,10 +879,6 @@ public:
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s);
break;
case BOSS_ANUB:
if (GameObject* go = instance->GetGameObject(_anubGateGUID))
{
go->SetGoState(GO_STATE_ACTIVE);
}
if (GameObject* go = instance->GetGameObject(_anubNextGateGUID))
{
go->SetGoState(GO_STATE_ACTIVE);
@@ -1074,8 +1069,6 @@ public:
return _heiganGateGUID;
case DATA_LOATHEB_GATE:
return _loathebGateGUID;
case DATA_ANUB_GATE:
return _anubGateGUID;
case DATA_FAERLINA_WEB:
return _faerlinaWebGUID;
case DATA_MAEXXNA_GATE:
@@ -50,7 +50,6 @@ enum NXData
DATA_HEIGAN_ERUPTION = 101,
DATA_HEIGAN_ENTER_GATE = 102,
DATA_LOATHEB_GATE = 103,
DATA_ANUB_GATE = 104,
DATA_FAERLINA_WEB = 105,
DATA_MAEXXNA_GATE = 106,
DATA_THADDIUS_BOSS = 107,
@@ -67,146 +67,131 @@ private:
Creature* _caster;
};
class boss_anomalus : public CreatureScript
struct boss_anomalus : public BossAI
{
public:
boss_anomalus() : CreatureScript("boss_anomalus") { }
boss_anomalus(Creature* creature) : BossAI(creature, DATA_ANOMALUS_EVENT) { }
CreatureAI* GetAI(Creature* creature) const override
bool achievement;
uint16 activeRifts;
void Reset() override
{
return GetNexusAI<boss_anomalusAI>(creature);
BossAI::Reset();
achievement = true;
me->CastSpell(me, SPELL_CLOSE_RIFTS, true);
}
struct boss_anomalusAI : public BossAI
uint32 GetData(uint32 data) const override
{
boss_anomalusAI(Creature* creature) : BossAI(creature, DATA_ANOMALUS_EVENT)
{
}
if (data == me->GetEntry())
return achievement;
return 0;
}
bool achievement;
uint16 activeRifts;
void Reset() override
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry())
{
BossAI::Reset();
achievement = true;
me->CastSpell(me, SPELL_CLOSE_RIFTS, true);
}
uint32 GetData(uint32 data) const override
{
if (data == me->GetEntry())
return achievement;
return 0;
}
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry())
if (activeRifts > 0 && --activeRifts == 0 && me->HasAura(SPELL_RIFT_SHIELD))
{
if (activeRifts > 0 && --activeRifts == 0 && me->HasAura(SPELL_RIFT_SHIELD))
{
events.DelayEvents(me->GetAura(SPELL_RIFT_SHIELD)->GetDuration() - 46000);
me->RemoveAura(SPELL_RIFT_SHIELD);
me->InterruptNonMeleeSpells(false);
}
achievement = false;
events.DelayEvents(me->GetAura(SPELL_RIFT_SHIELD)->GetDuration() - 46000);
me->RemoveAura(SPELL_RIFT_SHIELD);
me->InterruptNonMeleeSpells(false);
}
achievement = false;
}
}
void JustSummoned(Creature* summon) override
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
activeRifts++;
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
activeRifts = 0;
events.SetTimer(45000);
events.ScheduleEvent(EVENT_ANOMALUS_SPARK, 5s);
events.ScheduleEvent(EVENT_ANOMALUS_HEALTH, 1s);
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15s : 25s);
if (IsHeroic())
events.ScheduleEvent(EVENT_ANOMALUS_ARCANE_ATTRACTION, 8s);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
me->CastSpell(me, SPELL_CLOSE_RIFTS, true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
summons.Summon(summon);
activeRifts++;
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
activeRifts = 0;
events.SetTimer(45000);
case EVENT_ANOMALUS_SPARK:
me->CastSpell(me->GetVictim(), SPELL_SPARK, false);
events.ScheduleEvent(EVENT_ANOMALUS_SPARK, 5s);
events.ScheduleEvent(EVENT_ANOMALUS_HEALTH, 1s);
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15s : 25s);
if (IsHeroic())
events.ScheduleEvent(EVENT_ANOMALUS_ARCANE_ATTRACTION, 8s);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
me->CastSpell(me, SPELL_CLOSE_RIFTS, true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
break;
case EVENT_ANOMALUS_HEALTH:
if (me->HealthBelowPct(51))
{
case EVENT_ANOMALUS_SPARK:
me->CastSpell(me->GetVictim(), SPELL_SPARK, false);
events.ScheduleEvent(EVENT_ANOMALUS_SPARK, 5s);
break;
case EVENT_ANOMALUS_HEALTH:
if (me->HealthBelowPct(51))
{
//First time we reach 51%, the next rift going to be empowered following timings.
events.CancelEvent(EVENT_ANOMALUS_SPAWN_RIFT);
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED, 1s);
break;
}
events.ScheduleEvent(EVENT_ANOMALUS_HEALTH, 1s);
break;
case EVENT_ANOMALUS_ARCANE_ATTRACTION:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_ARCANE_ATTRACTION, false);
events.ScheduleEvent(EVENT_ANOMALUS_ARCANE_ATTRACTION, 15s);
break;
case EVENT_ANOMALUS_SPAWN_RIFT:
Talk(SAY_RIFT);
Talk(EMOTE_RIFT);
me->CastSpell(me, SPELL_CREATE_RIFT, false);
//Once we hit 51% hp mark, after each rift we spawn an empowered
events.ScheduleEvent(me->HealthBelowPct(51) ? EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED : EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15000 : 25000);
break;
case EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED:
Talk(SAY_RIFT);
Talk(EMOTE_RIFT);
me->CastSpell(me, SPELL_CREATE_RIFT, false);
me->CastSpell(me, SPELL_RIFT_SHIELD, true);
me->m_Events.AddEvent(new ChargeRifts(me), me->m_Events.CalculateTime(1000));
events.DelayEvents(46s);
//As we just spawned an empowered spawn a normal one
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15s : 25s);
break;
//First time we reach 51%, the next rift going to be empowered following timings.
events.CancelEvent(EVENT_ANOMALUS_SPAWN_RIFT);
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED, 1s);
break;
}
events.ScheduleEvent(EVENT_ANOMALUS_HEALTH, 1s);
break;
case EVENT_ANOMALUS_ARCANE_ATTRACTION:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_ARCANE_ATTRACTION, false);
events.ScheduleEvent(EVENT_ANOMALUS_ARCANE_ATTRACTION, 15s);
break;
case EVENT_ANOMALUS_SPAWN_RIFT:
Talk(SAY_RIFT);
Talk(EMOTE_RIFT);
me->CastSpell(me, SPELL_CREATE_RIFT, false);
//Once we hit 51% hp mark, after each rift we spawn an empowered
events.ScheduleEvent(me->HealthBelowPct(51) ? EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED : EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15000 : 25000);
break;
case EVENT_ANOMALUS_SPAWN_RIFT_EMPOWERED:
Talk(SAY_RIFT);
Talk(EMOTE_RIFT);
DoMeleeAttackIfReady();
me->CastSpell(me, SPELL_CREATE_RIFT, false);
me->CastSpell(me, SPELL_RIFT_SHIELD, true);
me->m_Events.AddEvent(new ChargeRifts(me), me->m_Events.CalculateTime(1000));
events.DelayEvents(46s);
//As we just spawned an empowered spawn a normal one
events.ScheduleEvent(EVENT_ANOMALUS_SPAWN_RIFT, IsHeroic() ? 15s : 25s);
break;
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return me->GetHomePosition().GetExactDist2d(me) > 60.0f;
}
};
DoMeleeAttackIfReady();
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return me->GetHomePosition().GetExactDist2d(me) > 60.0f;
}
};
class achievement_chaos_theory : public AchievementCriteriaScript
{
public:
achievement_chaos_theory() : AchievementCriteriaScript("achievement_chaos_theory")
{
}
achievement_chaos_theory() : AchievementCriteriaScript("achievement_chaos_theory") { }
bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
{
@@ -219,6 +204,6 @@ public:
void AddSC_boss_anomalus()
{
new boss_anomalus();
RegisterNexusCreatureAI(boss_anomalus);
new achievement_chaos_theory();
}
@@ -43,90 +43,77 @@ enum Says
SAY_KILL = 2
};
class boss_commander_stoutbeard : public CreatureScript
struct boss_commander_stoutbeard : public BossAI
{
public:
boss_commander_stoutbeard() : CreatureScript("boss_commander_stoutbeard") { }
boss_commander_stoutbeard(Creature* creature) : BossAI(creature, DATA_COMMANDER_EVENT) {}
CreatureAI* GetAI(Creature* creature) const override
void Reset() override
{
return GetNexusAI<boss_commander_stoutbeardAI>(creature);
BossAI::Reset();
}
struct boss_commander_stoutbeardAI : public BossAI
void JustEngagedWith(Unit* who) override
{
boss_commander_stoutbeardAI(Creature* creature) : BossAI(creature, DATA_COMMANDER_EVENT)
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_BATTLE_SHOUT, 0ms);
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 10s);
events.ScheduleEvent(EVENT_WHIRLWIND, 15s);
events.ScheduleEvent(EVENT_COMMANDER_CHARGE, 1s);
me->RemoveAllAuras();
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_BATTLE_SHOUT:
me->CastSpell(me, SPELL_BATTLE_SHOUT, true);
events.ScheduleEvent(EVENT_BATTLE_SHOUT, 2min);
break;
case EVENT_FRIGHTENING_SHOUT:
me->CastSpell(me->GetVictim(), SPELL_FRIGHTENING_SHOUT, false);
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 15s, 20s);
break;
case EVENT_WHIRLWIND:
me->CastSpell(me, SPELL_WHIRLWIND, false);
events.ScheduleEvent(EVENT_WHIRLWIND, 16s);
break;
case EVENT_COMMANDER_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 25.0f))
me->CastSpell(target, SPELL_CHARGE, false);
events.ScheduleEvent(EVENT_COMMANDER_CHARGE, 20s);
break;
}
void Reset() override
{
BossAI::Reset();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_BATTLE_SHOUT, 0ms);
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 10s);
events.ScheduleEvent(EVENT_WHIRLWIND, 15s);
events.ScheduleEvent(EVENT_COMMANDER_CHARGE, 1s);
me->RemoveAllAuras();
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_BATTLE_SHOUT:
me->CastSpell(me, SPELL_BATTLE_SHOUT, true);
events.ScheduleEvent(EVENT_BATTLE_SHOUT, 2min);
break;
case EVENT_FRIGHTENING_SHOUT:
me->CastSpell(me->GetVictim(), SPELL_FRIGHTENING_SHOUT, false);
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 15s, 20s);
break;
case EVENT_WHIRLWIND:
me->CastSpell(me, SPELL_WHIRLWIND, false);
events.ScheduleEvent(EVENT_WHIRLWIND, 16s);
break;
case EVENT_COMMANDER_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 25.0f))
me->CastSpell(target, SPELL_CHARGE, false);
events.ScheduleEvent(EVENT_COMMANDER_CHARGE, 20s);
break;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
void AddSC_boss_commander_stoutbeard()
{
new boss_commander_stoutbeard();
RegisterNexusCreatureAI(boss_commander_stoutbeard);
}
@@ -55,152 +55,137 @@ enum Events
EVENT_KILL_TALK = 6
};
class boss_keristrasza : public CreatureScript
struct boss_keristrasza : public BossAI
{
public:
boss_keristrasza() : CreatureScript("boss_keristrasza") { }
boss_keristrasza(Creature* creature) : BossAI(creature, DATA_KERISTRASZA_EVENT) {}
CreatureAI* GetAI(Creature* creature) const override
std::set<uint32> aGuids;
void Reset() override
{
return GetNexusAI<boss_keristraszaAI>(creature);
BossAI::Reset();
RemovePrison(CanRemovePrison());
aGuids.clear();
}
struct boss_keristraszaAI : public BossAI
void JustEngagedWith(Unit* who) override
{
boss_keristraszaAI(Creature* creature) : BossAI(creature, DATA_KERISTRASZA_EVENT)
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
me->CastSpell(me, SPELL_INTENSE_COLD, true);
events.ScheduleEvent(EVENT_CRYSTALFIRE_BREATH, 14s);
events.ScheduleEvent(EVENT_CRYSTAL_CHAINS, DUNGEON_MODE(20000, 11000));
events.ScheduleEvent(EVENT_TAIL_SWEEP, 5s);
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
events.ScheduleEvent(EVENT_ACHIEVEMENT_CHECK, 1s);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_SLAY);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
std::set<uint32> aGuids;
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry() && CanRemovePrison())
RemovePrison(true);
}
void Reset() override
bool CanRemovePrison()
{
for (uint8 i = DATA_TELESTRA_ORB; i <= DATA_ORMOROK_ORB; ++i)
if (instance->GetBossState(i) != DONE)
return false;
return true;
}
void RemovePrison(bool remove)
{
if (remove)
{
BossAI::Reset();
RemovePrison(CanRemovePrison());
aGuids.clear();
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON);
}
void JustEngagedWith(Unit* who) override
else
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->CastSpell(me, SPELL_FROZEN_PRISON, true);
}
}
me->CastSpell(me, SPELL_INTENSE_COLD, true);
events.ScheduleEvent(EVENT_CRYSTALFIRE_BREATH, 14s);
events.ScheduleEvent(EVENT_CRYSTAL_CHAINS, DUNGEON_MODE(20000, 11000));
events.ScheduleEvent(EVENT_TAIL_SWEEP, 5s);
uint32 GetData(uint32 guid) const override
{
return aGuids.find(guid) == aGuids.end();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_HEALTH_CHECK:
if (me->HealthBelowPct(26))
{
Talk(SAY_ENRAGE);
Talk(EMOTE_FRENZY);
me->CastSpell(me, SPELL_ENRAGE, true);
break;
}
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
events.ScheduleEvent(EVENT_ACHIEVEMENT_CHECK, 1s);
}
void JustDied(Unit* killer) override
break;
case EVENT_ACHIEVEMENT_CHECK:
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (Aura* aur = itr->GetSource()->GetAura(SPELL_INTENSE_COLD_TRIGGER))
if (aur->GetStackAmount() > 2)
aGuids.insert(itr->GetSource()->GetGUID().GetCounter());
events.ScheduleEvent(EVENT_ACHIEVEMENT_CHECK, 500ms);
break;
}
case EVENT_CRYSTALFIRE_BREATH:
me->CastSpell(me->GetVictim(), SPELL_CRYSTALFIRE_BREATH, false);
events.ScheduleEvent(EVENT_CRYSTALFIRE_BREATH, 14s);
break;
case EVENT_TAIL_SWEEP:
me->CastSpell(me, SPELL_TAIL_SWEEP, false);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 5s);
break;
case EVENT_CRYSTAL_CHAINS:
Talk(SAY_CRYSTAL_NOVA);
if (IsHeroic())
me->CastSpell(me, SPELL_CRYSTALIZE, false);
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
me->CastSpell(target, SPELL_CRYSTAL_CHAINS, false);
events.ScheduleEvent(EVENT_CRYSTAL_CHAINS, DUNGEON_MODE(20000, 11000));
break;
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_SLAY);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry() && CanRemovePrison())
RemovePrison(true);
}
bool CanRemovePrison()
{
for (uint8 i = DATA_TELESTRA_ORB; i <= DATA_ORMOROK_ORB; ++i)
if (instance->GetBossState(i) != DONE)
return false;
return true;
}
void RemovePrison(bool remove)
{
if (remove)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveAurasDueToSpell(SPELL_FROZEN_PRISON);
}
else
{
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->CastSpell(me, SPELL_FROZEN_PRISON, true);
}
}
uint32 GetData(uint32 guid) const override
{
return aGuids.find(guid) == aGuids.end();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_HEALTH_CHECK:
if (me->HealthBelowPct(26))
{
Talk(SAY_ENRAGE);
Talk(EMOTE_FRENZY);
me->CastSpell(me, SPELL_ENRAGE, true);
break;
}
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
break;
case EVENT_ACHIEVEMENT_CHECK:
{
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (Aura* aur = itr->GetSource()->GetAura(SPELL_INTENSE_COLD_TRIGGER))
if (aur->GetStackAmount() > 2)
aGuids.insert(itr->GetSource()->GetGUID().GetCounter());
events.ScheduleEvent(EVENT_ACHIEVEMENT_CHECK, 500ms);
break;
}
case EVENT_CRYSTALFIRE_BREATH:
me->CastSpell(me->GetVictim(), SPELL_CRYSTALFIRE_BREATH, false);
events.ScheduleEvent(EVENT_CRYSTALFIRE_BREATH, 14s);
break;
case EVENT_TAIL_SWEEP:
me->CastSpell(me, SPELL_TAIL_SWEEP, false);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 5s);
break;
case EVENT_CRYSTAL_CHAINS:
Talk(SAY_CRYSTAL_NOVA);
if (IsHeroic())
me->CastSpell(me, SPELL_CRYSTALIZE, false);
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
me->CastSpell(target, SPELL_CRYSTAL_CHAINS, false);
events.ScheduleEvent(EVENT_CRYSTAL_CHAINS, DUNGEON_MODE(20000, 11000));
break;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
class achievement_intense_cold : public AchievementCriteriaScript
{
public:
achievement_intense_cold() : AchievementCriteriaScript("achievement_intense_cold")
{
}
achievement_intense_cold() : AchievementCriteriaScript("achievement_intense_cold") { }
bool OnCheck(Player* player, Unit* target, uint32 /*criteria_id*/) override
{
@@ -213,6 +198,6 @@ public:
void AddSC_boss_keristrasza()
{
new boss_keristrasza();
RegisterNexusCreatureAI(boss_keristrasza);
new achievement_intense_cold();
}
@@ -79,159 +79,146 @@ enum Events
EVENT_KILL_TALK = 9
};
class boss_magus_telestra : public CreatureScript
struct boss_magus_telestra : public BossAI
{
public:
boss_magus_telestra() : CreatureScript("boss_magus_telestra") { }
boss_magus_telestra(Creature* creature) : BossAI(creature, DATA_MAGUS_TELESTRA_EVENT) { }
CreatureAI* GetAI(Creature* creature) const override
uint8 copiesDied;
bool achievement;
void Reset() override
{
return GetNexusAI<boss_magus_telestraAI>(creature);
BossAI::Reset();
copiesDied = 0;
achievement = true;
if (IsHeroic() && sGameEventMgr->IsActiveEvent(GAME_EVENT_WINTER_VEIL) && !me->HasAura(SPELL_WEAR_CHRISTMAS_HAT))
me->AddAura(SPELL_WEAR_CHRISTMAS_HAT, me);
}
struct boss_magus_telestraAI : public BossAI
uint32 GetData(uint32 data) const override
{
boss_magus_telestraAI(Creature* creature) : BossAI(creature, DATA_MAGUS_TELESTRA_EVENT)
if (data == me->GetEntry())
return achievement;
return 0;
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_MAGUS_ICE_NOVA, 10s);
events.ScheduleEvent(EVENT_MAGUS_FIREBOMB, 0ms);
events.ScheduleEvent(EVENT_MAGUS_GRAVITY_WELL, 20s);
events.ScheduleEvent(EVENT_MAGUS_HEALTH1, 1s);
if (IsHeroic())
events.ScheduleEvent(EVENT_MAGUS_HEALTH2, 1s);
}
void AttackStart(Unit* who) override
{
if (who && me->Attack(who, true))
me->GetMotionMaster()->MoveChase(who, 20.0f);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
uint8 copiesDied;
bool achievement;
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void Reset() override
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
if (spellInfo->Id >= SPELL_FIRE_MAGUS_DEATH && spellInfo->Id <= SPELL_ARCANE_MAGUS_DEATH && caster->ToCreature())
{
BossAI::Reset();
copiesDied = 0;
achievement = true;
events.ScheduleEvent(EVENT_MAGUS_FAIL_ACHIEVEMENT, 5s);
caster->ToCreature()->DespawnOrUnsummon(1000);
if (IsHeroic() && sGameEventMgr->IsActiveEvent(GAME_EVENT_WINTER_VEIL) && !me->HasAura(SPELL_WEAR_CHRISTMAS_HAT))
me->AddAura(SPELL_WEAR_CHRISTMAS_HAT, me);
if (++copiesDied >= 3)
{
copiesDied = 0;
events.CancelEvent(EVENT_MAGUS_FAIL_ACHIEVEMENT);
events.ScheduleEvent(EVENT_MAGUS_MERGED, 5s);
me->CastSpell(me, SPELL_BURNING_WINDS, true);
}
}
}
uint32 GetData(uint32 data) const override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
if (data == me->GetEntry())
return achievement;
return 0;
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_MAGUS_ICE_NOVA, 10s);
events.ScheduleEvent(EVENT_MAGUS_FIREBOMB, 0ms);
events.ScheduleEvent(EVENT_MAGUS_GRAVITY_WELL, 20s);
case EVENT_MAGUS_HEALTH1:
if (me->HealthBelowPct(51))
{
me->CastSpell(me, SPELL_START_SUMMON_CLONES, false);
events.ScheduleEvent(EVENT_MAGUS_RELOCATE, 3500ms);
Talk(SAY_SPLIT);
break;
}
events.ScheduleEvent(EVENT_MAGUS_HEALTH1, 1s);
if (IsHeroic())
events.ScheduleEvent(EVENT_MAGUS_HEALTH2, 1s);
}
void AttackStart(Unit* who) override
{
if (who && me->Attack(who, true))
me->GetMotionMaster()->MoveChase(who, 20.0f);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void KilledUnit(Unit*) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
break;
case EVENT_MAGUS_HEALTH2:
if (me->HealthBelowPct(11))
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
me->CastSpell(me, SPELL_START_SUMMON_CLONES, false);
events.ScheduleEvent(EVENT_MAGUS_RELOCATE, 3500ms);
Talk(SAY_SPLIT);
break;
}
events.ScheduleEvent(EVENT_MAGUS_HEALTH2, 1s);
break;
case EVENT_MAGUS_FIREBOMB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_FIREBOMB, false);
events.ScheduleEvent(EVENT_MAGUS_FIREBOMB, 3s);
break;
case EVENT_MAGUS_ICE_NOVA:
me->CastSpell(me, SPELL_ICE_NOVA, false);
events.ScheduleEvent(EVENT_MAGUS_ICE_NOVA, 15s);
break;
case EVENT_MAGUS_GRAVITY_WELL:
me->CastSpell(me, SPELL_GRAVITY_WELL, false);
events.ScheduleEvent(EVENT_MAGUS_GRAVITY_WELL, 15s);
break;
case EVENT_MAGUS_FAIL_ACHIEVEMENT:
achievement = false;
break;
case EVENT_MAGUS_RELOCATE:
me->NearTeleportTo(505.04f, 88.915f, -16.13f, 2.98f);
break;
case EVENT_MAGUS_MERGED:
me->CastSpell(me, SPELL_TELESTRA_BACK, true);
me->RemoveAllAuras();
Talk(SAY_MERGE);
break;
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
if (spellInfo->Id >= SPELL_FIRE_MAGUS_DEATH && spellInfo->Id <= SPELL_ARCANE_MAGUS_DEATH && caster->ToCreature())
{
events.ScheduleEvent(EVENT_MAGUS_FAIL_ACHIEVEMENT, 5s);
caster->ToCreature()->DespawnOrUnsummon(1000);
if (++copiesDied >= 3)
{
copiesDied = 0;
events.CancelEvent(EVENT_MAGUS_FAIL_ACHIEVEMENT);
events.ScheduleEvent(EVENT_MAGUS_MERGED, 5s);
me->CastSpell(me, SPELL_BURNING_WINDS, true);
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_MAGUS_HEALTH1:
if (me->HealthBelowPct(51))
{
me->CastSpell(me, SPELL_START_SUMMON_CLONES, false);
events.ScheduleEvent(EVENT_MAGUS_RELOCATE, 3500ms);
Talk(SAY_SPLIT);
break;
}
events.ScheduleEvent(EVENT_MAGUS_HEALTH1, 1s);
break;
case EVENT_MAGUS_HEALTH2:
if (me->HealthBelowPct(11))
{
me->CastSpell(me, SPELL_START_SUMMON_CLONES, false);
events.ScheduleEvent(EVENT_MAGUS_RELOCATE, 3500ms);
Talk(SAY_SPLIT);
break;
}
events.ScheduleEvent(EVENT_MAGUS_HEALTH2, 1s);
break;
case EVENT_MAGUS_FIREBOMB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_FIREBOMB, false);
events.ScheduleEvent(EVENT_MAGUS_FIREBOMB, 3s);
break;
case EVENT_MAGUS_ICE_NOVA:
me->CastSpell(me, SPELL_ICE_NOVA, false);
events.ScheduleEvent(EVENT_MAGUS_ICE_NOVA, 15s);
break;
case EVENT_MAGUS_GRAVITY_WELL:
me->CastSpell(me, SPELL_GRAVITY_WELL, false);
events.ScheduleEvent(EVENT_MAGUS_GRAVITY_WELL, 15s);
break;
case EVENT_MAGUS_FAIL_ACHIEVEMENT:
achievement = false;
break;
case EVENT_MAGUS_RELOCATE:
me->NearTeleportTo(505.04f, 88.915f, -16.13f, 2.98f);
break;
case EVENT_MAGUS_MERGED:
me->CastSpell(me, SPELL_TELESTRA_BACK, true);
me->RemoveAllAuras();
Talk(SAY_MERGE);
break;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
class spell_boss_magus_telestra_summon_telestra_clones_aura : public AuraScript
@@ -331,7 +318,7 @@ public:
void AddSC_boss_magus_telestra()
{
new boss_magus_telestra();
RegisterNexusCreatureAI(boss_magus_telestra);
RegisterSpellScript(spell_boss_magus_telestra_summon_telestra_clones_aura);
RegisterSpellScript(spell_boss_magus_telestra_gravity_well);
new achievement_split_personality();
@@ -60,173 +60,147 @@ enum Misc
GO_CRYSTAL_SPIKE = 188537
};
class boss_ormorok : public CreatureScript
struct boss_ormorok : public BossAI
{
public:
boss_ormorok() : CreatureScript("boss_ormorok") { }
boss_ormorok(Creature* creature) : BossAI(creature, DATA_ORMOROK_EVENT) {}
CreatureAI* GetAI(Creature* creature) const override
uint8 _spikesCount;
void Reset() override
{
return GetNexusAI<boss_ormorokAI>(creature);
_spikesCount = 0;
BossAI::Reset();
}
struct boss_ormorokAI : public BossAI
void JustEngagedWith(Unit* who) override
{
boss_ormorokAI(Creature* creature) : BossAI(creature, DATA_ORMOROK_EVENT)
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_ORMOROK_CRYSTAL_SPIKES, 12s);
events.ScheduleEvent(EVENT_ORMOROK_TRAMPLE, 10s);
events.ScheduleEvent(EVENT_ORMOROK_SPELL_REFLECTION, 30s);
events.ScheduleEvent(EVENT_ORMOROK_HEALTH, 1s);
if (IsHeroic())
events.ScheduleEvent(EVENT_ORMOROK_SUMMON, 17s);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void KilledUnit(Unit* /*victim*/) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
uint8 _spikesCount;
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void Reset() override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
_spikesCount = 0;
BossAI::Reset();
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_ORMOROK_CRYSTAL_SPIKES, 12s);
events.ScheduleEvent(EVENT_ORMOROK_TRAMPLE, 10s);
events.ScheduleEvent(EVENT_ORMOROK_SPELL_REFLECTION, 30s);
case EVENT_ORMOROK_HEALTH:
if (me->HealthBelowPct(26))
{
me->CastSpell(me, SPELL_FRENZY, true);
Talk(EMOTE_FRENZY);
break;
}
events.ScheduleEvent(EVENT_ORMOROK_HEALTH, 1s);
if (IsHeroic())
events.ScheduleEvent(EVENT_ORMOROK_SUMMON, 17s);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void KilledUnit(Unit* /*victim*/) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
break;
case EVENT_ORMOROK_TRAMPLE:
me->CastSpell(me, SPELL_TRAMPLE, false);
events.ScheduleEvent(EVENT_ORMOROK_TRAMPLE, 10s);
break;
case EVENT_ORMOROK_SPELL_REFLECTION:
Talk(SAY_REFLECT);
me->CastSpell(me, SPELL_SPELL_REFLECTION, false);
events.ScheduleEvent(EVENT_ORMOROK_SPELL_REFLECTION, 30s);
break;
case EVENT_ORMOROK_SUMMON:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 50.0f, true))
me->CastSpell(target, SPELL_SUMMON_CRYSTALLINE_TANGLER, true);
events.ScheduleEvent(EVENT_ORMOROK_SUMMON, 17s);
break;
case EVENT_ORMOROK_CRYSTAL_SPIKES:
Talk(SAY_CRYSTAL_SPIKES);
me->CastSpell(me, SPELL_CRYSTAL_SPIKES, false);
_spikesCount = 0;
events.ScheduleEvent(EVENT_ORMOROK_SUMMON_SPIKES, 300ms);
events.ScheduleEvent(EVENT_ORMOROK_CRYSTAL_SPIKES, 20s);
break;
case EVENT_ORMOROK_SUMMON_SPIKES:
if (++_spikesCount > 9)
break;
for (uint8 i = 0; i < 4; ++i)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
float o = rand_norm() * 2.0f * M_PI;
float x = me->GetPositionX() + 5.0f * _spikesCount * cos(o);
float y = me->GetPositionY() + 5.0f * _spikesCount * std::sin(o);
float h = me->GetMapHeight(x, y, me->GetPositionZ());
if (h != INVALID_HEIGHT)
me->SummonCreature(NPC_CRYSTAL_SPIKE, x, y, h, 0, TEMPSUMMON_TIMED_DESPAWN, 7000);
}
events.ScheduleEvent(EVENT_ORMOROK_SUMMON_SPIKES, 200ms);
break;
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ORMOROK_HEALTH:
if (me->HealthBelowPct(26))
{
me->CastSpell(me, SPELL_FRENZY, true);
Talk(EMOTE_FRENZY);
break;
}
events.ScheduleEvent(EVENT_ORMOROK_HEALTH, 1s);
break;
case EVENT_ORMOROK_TRAMPLE:
me->CastSpell(me, SPELL_TRAMPLE, false);
events.ScheduleEvent(EVENT_ORMOROK_TRAMPLE, 10s);
break;
case EVENT_ORMOROK_SPELL_REFLECTION:
Talk(SAY_REFLECT);
me->CastSpell(me, SPELL_SPELL_REFLECTION, false);
events.ScheduleEvent(EVENT_ORMOROK_SPELL_REFLECTION, 30s);
break;
case EVENT_ORMOROK_SUMMON:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 50.0f, true))
me->CastSpell(target, SPELL_SUMMON_CRYSTALLINE_TANGLER, true);
events.ScheduleEvent(EVENT_ORMOROK_SUMMON, 17s);
break;
case EVENT_ORMOROK_CRYSTAL_SPIKES:
Talk(SAY_CRYSTAL_SPIKES);
me->CastSpell(me, SPELL_CRYSTAL_SPIKES, false);
_spikesCount = 0;
events.ScheduleEvent(EVENT_ORMOROK_SUMMON_SPIKES, 300ms);
events.ScheduleEvent(EVENT_ORMOROK_CRYSTAL_SPIKES, 20s);
break;
case EVENT_ORMOROK_SUMMON_SPIKES:
if (++_spikesCount > 9)
break;
for (uint8 i = 0; i < 4; ++i)
{
float o = rand_norm() * 2.0f * M_PI;
float x = me->GetPositionX() + 5.0f * _spikesCount * cos(o);
float y = me->GetPositionY() + 5.0f * _spikesCount * std::sin(o);
float h = me->GetMapHeight(x, y, me->GetPositionZ());
if (h != INVALID_HEIGHT)
me->SummonCreature(NPC_CRYSTAL_SPIKE, x, y, h, 0, TEMPSUMMON_TIMED_DESPAWN, 7000);
}
events.ScheduleEvent(EVENT_ORMOROK_SUMMON_SPIKES, 200ms);
break;
}
DoMeleeAttackIfReady();
}
};
DoMeleeAttackIfReady();
}
};
class npc_crystal_spike : public CreatureScript
struct npc_crystal_spike : public NullCreatureAI
{
public:
npc_crystal_spike() : CreatureScript("npc_crystal_spike") { }
npc_crystal_spike(Creature* c) : NullCreatureAI(c) { }
CreatureAI* GetAI(Creature* pCreature) const override
int32 _damageTimer;
ObjectGuid _gameObjectGUID;
void Reset() override
{
return GetNexusAI<npc_crystal_spikeAI>(pCreature);
if (GameObject* gameobject = me->SummonGameObject(GO_CRYSTAL_SPIKE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 3500))
_gameObjectGUID = gameobject->GetGUID();
_damageTimer = 1;
}
struct npc_crystal_spikeAI : public NullCreatureAI
void UpdateAI(uint32 diff) override
{
npc_crystal_spikeAI(Creature* c) : NullCreatureAI(c)
if (_damageTimer)
{
}
int32 _damageTimer;
ObjectGuid _gameObjectGUID;
void Reset() override
{
if (GameObject* gameobject = me->SummonGameObject(GO_CRYSTAL_SPIKE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 3500))
_gameObjectGUID = gameobject->GetGUID();
_damageTimer = 1;
}
void UpdateAI(uint32 diff) override
{
if (_damageTimer)
_damageTimer += diff;
if (_damageTimer >= 2000)
{
_damageTimer += diff;
if (_damageTimer >= 2000)
{
if (GameObject* gameobject = ObjectAccessor::GetGameObject(*me, _gameObjectGUID))
gameobject->SetGoState(GO_STATE_ACTIVE);
if (GameObject* gameobject = ObjectAccessor::GetGameObject(*me, _gameObjectGUID))
gameobject->SetGoState(GO_STATE_ACTIVE);
me->CastSpell(me, SPELL_CRYSTAL_SPIKE_DAMAGE, false);
_damageTimer = 0;
}
me->CastSpell(me, SPELL_CRYSTAL_SPIKE_DAMAGE, false);
_damageTimer = 0;
}
}
};
}
};
void AddSC_boss_ormorok()
{
new boss_ormorok();
new npc_crystal_spike();
RegisterNexusCreatureAI(boss_ormorok);
RegisterNexusCreatureAI(npc_crystal_spike);
}
@@ -166,110 +166,97 @@ enum eFrayer
SPELL_ENSNARE = 48053
};
class npc_crystalline_frayer : public CreatureScript
struct npc_crystalline_frayer : public ScriptedAI
{
public:
npc_crystalline_frayer() : CreatureScript("npc_crystalline_frayer") { }
npc_crystalline_frayer(Creature* creature) : ScriptedAI(creature) { }
CreatureAI* GetAI(Creature* creature) const override
bool _allowDeath;
uint32 restoreTimer;
uint32 abilityTimer1;
uint32 abilityTimer2;
void Reset() override
{
return GetNexusAI<npc_crystalline_frayerAI>(creature);
restoreTimer = 0;
abilityTimer1 = 0;
abilityTimer2 = 30000;
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
struct npc_crystalline_frayerAI : public ScriptedAI
void JustEngagedWith(Unit*) override
{
npc_crystalline_frayerAI(Creature* creature) : ScriptedAI(creature)
_allowDeath = me->GetInstanceScript()->GetBossState(DATA_ORMOROK_EVENT) == DONE;
}
void EnterEvadeMode(EvadeReason why) override
{
if (me->isRegeneratingHealth())
ScriptedAI::EnterEvadeMode(why);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth())
{
if (!_allowDeath)
{
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
damage = 0;
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetRegeneratingHealth(false);
me->CastSpell(me, SPELL_SUMMON_SEED_POD, true);
me->CastSpell(me, SPELL_SEED_POD, true);
me->CastSpell(me, SPELL_AURA_OF_REGENERATION, false);
restoreTimer = 1;
}
}
}
void UpdateAI(uint32 diff) override
{
if (restoreTimer)
{
restoreTimer += diff;
if (restoreTimer >= 90 * IN_MILLISECONDS)
{
Talk(0);
me->SetRegeneratingHealth(true);
restoreTimer = 0;
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
return;
}
bool _allowDeath;
uint32 restoreTimer;
uint32 abilityTimer1;
uint32 abilityTimer2;
if (!UpdateVictim())
return;
void Reset() override
abilityTimer1 += diff;
abilityTimer2 += diff;
if (abilityTimer1 >= 5000)
{
restoreTimer = 0;
me->CastSpell(me->GetVictim(), SPELL_ENSNARE, false);
abilityTimer1 = 0;
abilityTimer2 = 30000;
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void JustEngagedWith(Unit*) override
if (abilityTimer2 >= 30000)
{
_allowDeath = me->GetInstanceScript()->GetBossState(DATA_ORMOROK_EVENT) == DONE;
me->CastSpell(me->GetVictim(), SPELL_CRYSTAL_BLOOM, false);
abilityTimer2 = 0;
}
void EnterEvadeMode(EvadeReason why) override
{
if (me->isRegeneratingHealth())
ScriptedAI::EnterEvadeMode(why);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (damage >= me->GetHealth())
{
if (!_allowDeath)
{
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
damage = 0;
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetRegeneratingHealth(false);
me->CastSpell(me, SPELL_SUMMON_SEED_POD, true);
me->CastSpell(me, SPELL_SEED_POD, true);
me->CastSpell(me, SPELL_AURA_OF_REGENERATION, false);
restoreTimer = 1;
}
}
}
void UpdateAI(uint32 diff) override
{
if (restoreTimer)
{
restoreTimer += diff;
if (restoreTimer >= 90 * IN_MILLISECONDS)
{
Talk(0);
me->SetRegeneratingHealth(true);
restoreTimer = 0;
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
return;
}
if (!UpdateVictim())
return;
abilityTimer1 += diff;
abilityTimer2 += diff;
if (abilityTimer1 >= 5000)
{
me->CastSpell(me->GetVictim(), SPELL_ENSNARE, false);
abilityTimer1 = 0;
}
if (abilityTimer2 >= 30000)
{
me->CastSpell(me->GetVictim(), SPELL_CRYSTAL_BLOOM, false);
abilityTimer2 = 0;
}
}
};
}
};
void AddSC_instance_nexus()
{
new instance_nexus();
new npc_crystalline_frayer();
RegisterNexusCreatureAI(npc_crystalline_frayer);
}
@@ -62,4 +62,6 @@ inline AI* GetNexusAI(T* obj)
return GetInstanceAI<AI>(obj, NexusScriptName);
}
#define RegisterNexusCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetNexusAI)
#endif
@@ -817,7 +817,12 @@ struct npc_lord_sanguinar : public advisor_baseAI
{
npc_lord_sanguinar(Creature* creature) : advisor_baseAI(creature) { };
void ScheduleEvents() override {}
void ScheduleEvents() override
{
ScheduleTimedEvent(0s, 2s, [&]{
DoCastSelf(SPELL_BELLOWING_ROAR);
}, 30s, 40s);
}
};
struct npc_capernian : public advisor_baseAI
@@ -5298,6 +5298,28 @@ class spell_gen_steal_weapon : public AuraScript
}
};
// 43536 - Serverside - SetHealth (75%)
// 43537 - Serverside - SetHealth (50%)
// 43538 - Serverside - SetHealth (25%)
class spell_gen_set_health : public SpellScript
{
PrepareSpellScript(spell_gen_set_health);
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
uint32 value = GetSpellInfo()->Effects[EFFECT_0].CalcValue();
target->SetHealth(target->CountPctFromMaxHealth(value));
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gen_set_health::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5455,4 +5477,5 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_consumption);
RegisterSpellScript(spell_gen_sober_up);
RegisterSpellScript(spell_gen_steal_weapon);
RegisterSpellScript(spell_gen_set_health);
}
+25
View File
@@ -4162,6 +4162,30 @@ class spell_item_spell_reflectors: public AuraScript
}
};
// 46273 - Multiphase Goggles
class spell_item_multiphase_goggles : public AuraScript
{
PrepareAuraScript(spell_item_multiphase_goggles);
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetTarget()->ToPlayer())
player->SetFlag(PLAYER_TRACK_CREATURES, uint32(1) << (CREATURE_TYPE_GAS_CLOUD - 1));
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetTarget()->ToPlayer())
player->RemoveFlag(PLAYER_TRACK_CREATURES, uint32(1) << (CREATURE_TYPE_GAS_CLOUD - 1));
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_item_multiphase_goggles::OnApply, EFFECT_0, SPELL_AURA_MOD_INVISIBILITY_DETECT , AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_item_multiphase_goggles::OnRemove, EFFECT_0, SPELL_AURA_MOD_INVISIBILITY_DETECT , AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_item_spell_scripts()
{
RegisterSpellScript(spell_item_massive_seaforium_charge);
@@ -4289,4 +4313,5 @@ void AddSC_item_spell_scripts()
RegisterSpellScript(spell_item_skyguard_blasting_charges);
RegisterSpellScript(spell_item_luffa);
RegisterSpellScript(spell_item_spell_reflectors);
RegisterSpellScript(spell_item_multiphase_goggles);
}