aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGustavo <sirikfoll@hotmail.com>2016-07-05 10:54:31 +0200
committerjoschiwald <joschiwald.trinity@gmail.com>2017-02-04 23:33:26 +0100
commite55420af8653cd52697a94c85badc91c9a1774a7 (patch)
treef7fcff37c4a55487e27ebc3012c4e19c5bb4402d /src
parent752c789aaf3be7afaf76dc1464296d553f35528a (diff)
Core/Scripts Corrections on Halion's Encounter (#16725)
Core/Scripts: Updates to Halion * Fixed Combustion and Consumption. * Fixed Living Embers and Blazing Auras. * Timer changes. (cherry picked from commit dfe278459d79ade500a66356a98b4065c0722572) # Conflicts: # src/server/game/Spells/SpellMgr.cpp # src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp Fix sql for merged PR (cherry picked from commit 7f944695ddad14cec021ff5a0527a5a92fb4cf81) Derp. github editor is bad. (cherry picked from commit 182904946174cd635b7478bd38507235d0d45aa2)
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp580
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp14
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h1
3 files changed, 332 insertions, 263 deletions
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
index be0db42ab81..2138cac8bf8 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -136,7 +136,8 @@ enum Events
EVENT_CHECK_CORPOREALITY = 13,
EVENT_SHADOW_PULSARS_SHOOT = 14,
EVENT_TRIGGER_BERSERK = 15,
- EVENT_TWILIGHT_MENDING = 16
+ EVENT_TWILIGHT_MENDING = 16,
+ EVENT_ACTIVATE_EMBERS = 17
};
enum Actions
@@ -149,7 +150,9 @@ enum Actions
ACTION_MONITOR_CORPOREALITY = 3,
// Orb Carrier
- ACTION_SHOOT = 4
+ ACTION_WARNING_SHOOT = 4,
+ ACTION_SHOOT = 5,
+ ACTION_ACTIVATE_EMBERS = 6
};
enum Phases
@@ -167,8 +170,7 @@ enum Misc
DATA_MATERIAL_DAMAGE_TAKEN = 2,
DATA_STACKS_DISPELLED = 3,
DATA_FIGHT_PHASE = 4,
- DATA_EVADE_METHOD = 5,
- DATA_SPAWNED_FLAMES = 6,
+ DATA_SPAWNED_FLAMES = 5,
};
enum OrbCarrierSeats
@@ -188,6 +190,7 @@ enum CorporealityEvent
};
Position const HalionSpawnPos = {3156.67f, 533.8108f, 72.98822f, 3.159046f};
+Position const HalionRespawnPos = {3156.625f, 533.2674f, 72.97205f, 0.0f};
uint8 const MAX_CORPOREALITY_STATE = 11;
@@ -211,132 +214,39 @@ CorporealityEntry const _corporealityReference[MAX_CORPOREALITY_STATE] = {
{74831, 74836}
};
-struct generic_halionAI : public BossAI
-{
- generic_halionAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _canEvade(false) { }
-
- void EnterCombat(Unit* /*who*/) override
- {
- _EnterCombat();
- me->AddAura(SPELL_TWILIGHT_PRECISION, me);
- _canEvade = false;
- events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
- events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
- events.ScheduleEvent(EVENT_BREATH, urand(10000, 15000));
- }
-
- void Reset() override
- {
- _canEvade = false;
- _Reset();
- }
-
- void JustReachedHome() override
- {
- instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
- _JustReachedHome();
- }
-
- void ExecuteEvent(uint32 eventId) override
- {
- switch (eventId)
- {
- case EVENT_CLEAVE:
- DoCastVictim(SPELL_CLEAVE);
- events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
- break;
- case EVENT_TAIL_LASH:
- DoCastAOE(SPELL_TAIL_LASH);
- events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
- break;
- case EVENT_BREATH:
- DoCast(me, me->GetEntry() == NPC_HALION ? SPELL_FLAME_BREATH : SPELL_DARK_BREATH);
- events.ScheduleEvent(EVENT_BREATH, urand(10000, 12000));
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
- ExecuteEvent(eventId);
-
- DoMeleeAttackIfReady();
- }
-
- void SetData(uint32 index, uint32 dataValue) override
- {
- switch (index)
- {
- case DATA_EVADE_METHOD:
- _canEvade = (dataValue == 1);
- break;
- default:
- break;
- }
- }
-
- void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_TWILIGHT_MENDING)
- Talk(SAY_REGENERATE);
- }
-
-protected:
- bool _canEvade;
-};
-
class boss_halion : public CreatureScript
{
public:
boss_halion() : CreatureScript("boss_halion") { }
- struct boss_halionAI : public generic_halionAI
+ struct boss_halionAI : public BossAI
{
- boss_halionAI(Creature* creature) : generic_halionAI(creature, DATA_HALION)
- {
- me->SetHomePosition(HalionSpawnPos);
- }
-
- void Reset() override
- {
- generic_halionAI::Reset();
- me->SetReactState(REACT_DEFENSIVE);
- me->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- }
+ boss_halionAI(Creature* creature) : BossAI(creature, DATA_HALION) { }
void EnterEvadeMode(EvadeReason why) override
{
- if (why == EVADE_REASON_BOUNDARY)
+ if (why == EVADE_REASON_BOUNDARY || events.IsInPhase(PHASE_ONE))
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
- controller->AI()->EnterEvadeMode();
-
- // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to.
- if (events.IsInPhase(PHASE_ONE) || _canEvade)
- generic_halionAI::EnterEvadeMode(why);
+ controller->AI()->EnterEvadeMode(why);
}
- void EnterCombat(Unit* who) override
+ void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
events.Reset();
events.SetPhase(PHASE_ONE);
- generic_halionAI::EnterCombat(who);
+ _EnterCombat();
+ me->AddAura(SPELL_TWILIGHT_PRECISION, me);
+ events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, Seconds(5));
+ events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(5), Seconds(15)));
+ events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(6), Seconds(10)));
+ events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(7), Seconds(12)));
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, randtime(Seconds(15), Seconds(18)));
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, Seconds(18));
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
- instance->SetBossState(DATA_HALION, IN_PROGRESS);
-
- events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 5000);
- events.ScheduleEvent(EVENT_METEOR_STRIKE, urand(20000, 25000));
- events.ScheduleEvent(EVENT_FIERY_COMBUSTION, urand(15000, 18000));
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE);
@@ -387,58 +297,76 @@ class boss_halion : public CreatureScript
}
}
+ void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_TWILIGHT_MENDING)
+ Talk(SAY_REGENERATE);
+ }
+
void UpdateAI(uint32 diff) override
{
if (events.IsInPhase(PHASE_TWO))
return;
- generic_halionAI::UpdateAI(diff);
- }
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- void ExecuteEvent(uint32 eventId) override
- {
- switch (eventId)
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- case EVENT_ACTIVATE_FIREWALL:
- // Flame ring is activated 5 seconds after starting encounter, DOOR_TYPE_ROOM is only instant.
- for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i)
- if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(i)))
- instance->HandleGameObject(instance->GetGuidData(DATA_FLAME_RING), false, flameRing);
- break;
- case EVENT_METEOR_STRIKE:
+ switch (eventId)
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(8), Seconds(10)));
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(11), Seconds(16)));
+ break;
+ case EVENT_BREATH:
+ DoCast(me, SPELL_FLAME_BREATH);
+ events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(16), Seconds(25)));
+ break;
+ case EVENT_ACTIVATE_FIREWALL:
+ // Flame ring is activated 5 seconds after starting encounter, DOOR_TYPE_ROOM is only instant.
+ for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i)
+ if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(i)))
+ instance->HandleGameObject(instance->GetGuidData(DATA_FLAME_RING), false, flameRing);
+ break;
+ case EVENT_METEOR_STRIKE:
{
- _meteorStrikePos = target->GetPosition();
- me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, NULL, NULL, me->GetGUID());
- Talk(SAY_METEOR_STRIKE);
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ {
+ _meteorStrikePos = target->GetPosition();
+ me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, nullptr, nullptr, me->GetGUID());
+ Talk(SAY_METEOR_STRIKE);
+ }
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, Seconds(38));
+ break;
}
- events.ScheduleEvent(EVENT_METEOR_STRIKE, 40000);
- break;
- }
- case EVENT_FIERY_COMBUSTION:
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM))
- DoCast(target, SPELL_FIERY_COMBUSTION);
- events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25000);
- break;
+ case EVENT_FIERY_COMBUSTION:
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ me->CastSpell(target, SPELL_FIERY_COMBUSTION, TRIGGERED_IGNORE_SET_FACING);
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, Seconds(25));
+ break;
+ }
+ default:
+ break;
}
- default:
- generic_halionAI::ExecuteEvent(eventId);
- break;
}
+
+ DoMeleeAttackIfReady();
}
void SetData(uint32 index, uint32 value) override
{
- switch (index)
- {
- case DATA_FIGHT_PHASE:
- events.SetPhase(value);
- break;
- default:
- generic_halionAI::SetData(index, value);
- }
+ if (index != DATA_FIGHT_PHASE)
+ return;
+
+ events.SetPhase(value);
}
private:
@@ -458,9 +386,9 @@ class boss_twilight_halion : public CreatureScript
public:
boss_twilight_halion() : CreatureScript("boss_twilight_halion") { }
- struct boss_twilight_halionAI : public generic_halionAI
+ struct boss_twilight_halionAI : public BossAI
{
- boss_twilight_halionAI(Creature* creature) : generic_halionAI(creature, DATA_TWILIGHT_HALION)
+ boss_twilight_halionAI(Creature* creature) : BossAI(creature, DATA_TWILIGHT_HALION)
{
Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION));
if (!halion)
@@ -469,26 +397,29 @@ class boss_twilight_halion : public CreatureScript
// Using AddAura because no spell cast packet in sniffs.
halion->AddAura(SPELL_COPY_DAMAGE, me); // We use explicit targeting here to avoid conditions + SPELL_ATTR6_CANT_TARGET_SELF.
me->AddAura(SPELL_COPY_DAMAGE, halion);
- me->AddAura(SPELL_DUSK_SHROUD, me);
+ DoCast(me, SPELL_DUSK_SHROUD, true);
me->SetHealth(halion->GetHealth());
me->SetPhaseMask(0x20, true);
- me->SetReactState(REACT_AGGRESSIVE);
+ me->SetReactState(REACT_DEFENSIVE);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
+ events.ScheduleEvent(EVENT_TAIL_LASH, Seconds(12));
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, Seconds(15));
}
- void EnterCombat(Unit* who) override
+ void EnterCombat(Unit* /*who*/) override
{
- events.Reset();
events.SetPhase(PHASE_TWO);
- generic_halionAI::EnterCombat(who);
-
- events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
+ _EnterCombat();
+ me->AddAura(SPELL_TWILIGHT_PRECISION, me);
+ events.ScheduleEvent(EVENT_CLEAVE, Seconds(3));
+ events.ScheduleEvent(EVENT_BREATH, Seconds(12));
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
}
- // Never evade
+ void Reset() override { }
void EnterEvadeMode(EvadeReason /*why*/) override { }
void KilledUnit(Unit* victim) override
@@ -521,6 +452,10 @@ class boss_twilight_halion : public CreatureScript
void DamageTaken(Unit* attacker, uint32& damage) override
{
+ //Needed because we already have UNIT_FLAG_IN_COMBAT, otherwise EnterCombat won't ever be called
+ if (!events.IsInPhase(PHASE_TWO) && !events.IsInPhase(PHASE_THREE))
+ EnterCombat(attacker);
+
if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO))
{
events.SetPhase(PHASE_THREE);
@@ -541,7 +476,7 @@ class boss_twilight_halion : public CreatureScript
}
}
- void SpellHit(Unit* who, SpellInfo const* spell) override
+ void SpellHit(Unit* /*who*/, SpellInfo const* spell) override
{
switch (spell->Id)
{
@@ -549,25 +484,51 @@ class boss_twilight_halion : public CreatureScript
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
controller->AI()->DoAction(ACTION_MONITOR_CORPOREALITY);
break;
+ case SPELL_TWILIGHT_MENDING:
+ Talk(SAY_REGENERATE);
+ break;
default:
- generic_halionAI::SpellHit(who, spell);
break;
}
}
- void ExecuteEvent(uint32 eventId) override
+ void UpdateAI(uint32 diff) override
{
- switch (eventId)
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- case EVENT_SOUL_CONSUMPTION:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM))
- DoCast(target, SPELL_SOUL_CONSUMPTION);
- events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
- break;
- default:
- generic_halionAI::ExecuteEvent(eventId);
- break;
+ switch (eventId)
+ {
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(7), Seconds(10)));
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, randtime(Seconds(12), Seconds(16)));
+ break;
+ case EVENT_BREATH:
+ DoCast(me, SPELL_DARK_BREATH);
+ events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(10), Seconds(14)));
+ break;
+ case EVENT_SOUL_CONSUMPTION:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM))
+ me->CastSpell(target, SPELL_SOUL_CONSUMPTION, TRIGGERED_IGNORE_SET_FACING);
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, Seconds(20));
+ break;
+ default:
+ break;
+ }
}
+
+ DoMeleeAttackIfReady();
}
};
@@ -588,7 +549,6 @@ class npc_halion_controller : public CreatureScript
_instance(creature->GetInstanceScript()), _summons(me)
{
Initialize();
- me->SetPhaseMask(me->GetPhaseMask() | 0x20, true);
}
void Initialize()
@@ -598,6 +558,15 @@ class npc_halion_controller : public CreatureScript
_twilightDamageTaken = 0;
}
+ void JustRespawned() override
+ {
+ if (_instance->GetGuidData(DATA_HALION))
+ return;
+
+ Reset();
+ me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos);
+ }
+
void Reset() override
{
_summons.DespawnAll();
@@ -625,21 +594,36 @@ class npc_halion_controller : public CreatureScript
_twilightDamageTaken = 0;
_materialDamageTaken = 0;
- _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8 * MINUTE * IN_MILLISECONDS);
+ _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, Minutes(8));
}
- void JustReachedHome() override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION)))
+ {
twilightHalion->DespawnOrUnsummon();
+ _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, twilightHalion);
+ }
if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION)))
{
- halion->AI()->SetData(DATA_EVADE_METHOD, 1);
- halion->AI()->EnterEvadeMode();
+ halion->DespawnOrUnsummon();
+ _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, halion);
}
_instance->SetBossState(DATA_HALION, FAIL);
+ _summons.DespawnAll();
+
+ uint32 corpseDelay = me->GetCorpseDelay();
+ uint32 respawnDelay = me->GetRespawnDelay();
+
+ me->SetCorpseDelay(1);
+ me->SetRespawnDelay(30);
+
+ me->DespawnOrUnsummon();
+
+ me->SetCorpseDelay(corpseDelay);
+ me->SetRespawnDelay(respawnDelay);
}
void DoAction(int32 action) override
@@ -649,7 +633,16 @@ class npc_halion_controller : public CreatureScript
case ACTION_INTRO_HALION:
_events.Reset();
_events.SetPhase(PHASE_INTRO);
- _events.ScheduleEvent(EVENT_START_INTRO, 2000);
+ _events.ScheduleEvent(EVENT_START_INTRO, Seconds(2));
+ break;
+ case ACTION_INTRO_HALION_2:
+ if (_instance->GetGuidData(DATA_HALION))
+ return;
+
+ for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_4; ++i)
+ if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i)))
+ _instance->HandleGameObject(_instance->GetGuidData(i), true, tree);
+ me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos);
break;
case ACTION_MONITOR_CORPOREALITY:
{
@@ -677,8 +670,11 @@ class npc_halion_controller : public CreatureScript
_instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 50);
_instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 50);
- _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 7500);
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, Seconds(7));
}
+ case ACTION_ACTIVATE_EMBERS:
+ _events.ScheduleEvent(EVENT_ACTIVATE_EMBERS, Seconds(6));
+ break;
default:
break;
}
@@ -691,7 +687,7 @@ class npc_halion_controller : public CreatureScript
// combat state.
if (!_events.IsInPhase(PHASE_INTRO) && me->IsInCombat() && !UpdateVictim())
{
- EnterEvadeMode();
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return;
}
@@ -703,29 +699,31 @@ class npc_halion_controller : public CreatureScript
{
case EVENT_START_INTRO:
DoCast(me, SPELL_COSMETIC_FIRE_PILLAR, true);
- _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, 4000);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, Seconds(4));
break;
case EVENT_INTRO_PROGRESS_1:
for (uint8 i = DATA_BURNING_TREE_3; i <= DATA_BURNING_TREE_4; ++i)
if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i)))
_instance->HandleGameObject(_instance->GetGuidData(i), true, tree);
- _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, 4000);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, Seconds(4));
break;
case EVENT_INTRO_PROGRESS_2:
for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_2; ++i)
if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetGuidData(i)))
_instance->HandleGameObject(_instance->GetGuidData(i), true, tree);
- _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, 4000);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, Seconds(4));
break;
case EVENT_INTRO_PROGRESS_3:
DoCast(me, SPELL_FIERY_EXPLOSION);
+ if (_instance->GetGuidData(DATA_HALION))
+ return;
if (Creature* halion = me->GetMap()->SummonCreature(NPC_HALION, HalionSpawnPos))
halion->AI()->Talk(SAY_INTRO);
break;
case EVENT_TWILIGHT_MENDING:
if (ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION))) // Just check if physical Halion is spawned
if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION)))
- twilightHalion->CastSpell((Unit*)NULL, SPELL_TWILIGHT_MENDING, true);
+ twilightHalion->CastSpell((Unit*)nullptr, SPELL_TWILIGHT_MENDING, true);
break;
case EVENT_TRIGGER_BERSERK:
for (uint8 i = DATA_HALION; i <= DATA_TWILIGHT_HALION; i++)
@@ -733,17 +731,16 @@ class npc_halion_controller : public CreatureScript
halion->CastSpell(halion, SPELL_BERSERK, true);
break;
case EVENT_SHADOW_PULSARS_SHOOT:
- if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION)))
- twilightHalion->AI()->Talk(SAY_SPHERE_PULSE);
-
if (Creature* orbCarrier = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ORB_CARRIER)))
- orbCarrier->AI()->DoAction(ACTION_SHOOT);
-
- _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ orbCarrier->AI()->DoAction(ACTION_WARNING_SHOOT);
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, Seconds(30));
break;
case EVENT_CHECK_CORPOREALITY:
UpdateCorporeality();
- _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000);
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, Seconds(5));
+ break;
+ case EVENT_ACTIVATE_EMBERS:
+ _summons.DoZoneInCombat(NPC_LIVING_EMBER);
break;
default:
break;
@@ -769,7 +766,7 @@ class npc_halion_controller : public CreatureScript
DoZoneInCombat();
break;
case PHASE_TWO:
- _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, Seconds(35));
break;
default:
break;
@@ -792,7 +789,7 @@ class npc_halion_controller : public CreatureScript
uint8 oldValue = _materialCorporealityValue;
if (_twilightDamageTaken == 0 || _materialDamageTaken == 0)
{
- _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100);
+ _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100));
_twilightDamageTaken = 0;
_materialDamageTaken = 0;
return;
@@ -832,7 +829,7 @@ class npc_halion_controller : public CreatureScript
}
case CORPOREALITY_TWILIGHT_MENDING:
{
- _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, 100);
+ _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100));
_materialDamageTaken = 0;
_twilightDamageTaken = 0;
return;
@@ -888,52 +885,73 @@ class npc_orb_carrier : public CreatureScript
struct npc_orb_carrierAI : public ScriptedAI
{
npc_orb_carrierAI(Creature* creature) : ScriptedAI(creature),
- instance(creature->GetInstanceScript())
+ _instance(creature->GetInstanceScript())
{
ASSERT(creature->GetVehicleKit());
}
- void UpdateAI(uint32 /*diff*/) override
+ void UpdateAI(uint32 diff) override
{
/// According to sniffs this spell is cast every 1 or 2 seconds.
/// However, refreshing it looks bad, so just cast the spell if
/// we are not channeling it.
if (!me->HasUnitState(UNIT_STATE_CASTING))
- me->CastSpell((Unit*)NULL, SPELL_TRACK_ROTATION, false);
+ me->CastSpell((Unit*)nullptr, SPELL_TRACK_ROTATION, false);
+
+ scheduler.Update(diff);
/// Workaround: This is here because even though the above spell has SPELL_ATTR1_CHANNEL_TRACK_TARGET,
/// we are having two creatures involded here. This attribute is handled clientside, meaning the client
/// sends orientation update itself. Here, no packet is sent, and the creature does not rotate. By
/// forcing the carrier to always be facing the rotation focus, we ensure everything works as it should.
- if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ORB_ROTATION_FOCUS)))
+ if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ORB_ROTATION_FOCUS)))
me->SetFacingToObject(rotationFocus); // setInFront
}
void DoAction(int32 action) override
{
- if (action == ACTION_SHOOT)
+ switch (action)
{
- Vehicle* vehicle = me->GetVehicleKit();
- Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH);
- Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH);
- if (southOrb && northOrb)
+ case ACTION_WARNING_SHOOT:
{
- if (northOrb->GetTypeId() == TYPEID_UNIT)
+ Vehicle* vehicle = me->GetVehicleKit();
+ Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH);
+ if (northOrb && northOrb->GetTypeId() == TYPEID_UNIT)
northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER);
- TriggerCutter(northOrb, southOrb);
+
+ scheduler.Schedule(Seconds(5), [this](TaskContext /*context*/)
+ {
+ DoAction(ACTION_SHOOT);
+ });
+ break;
}
+ case ACTION_SHOOT:
+ {
+ Vehicle* vehicle = me->GetVehicleKit();
+ Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH);
+ Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH);
+ if (southOrb && northOrb)
+ TriggerCutter(northOrb, southOrb);
- if (!IsHeroic())
- return;
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_TWILIGHT_HALION)))
+ twilightHalion->AI()->Talk(SAY_SPHERE_PULSE);
+
+ if (!IsHeroic())
+ return;
- Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST);
- Unit* westOrb = vehicle->GetPassenger(SEAT_WEST);
- if (eastOrb && westOrb)
- TriggerCutter(eastOrb, westOrb);
+ Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST);
+ Unit* westOrb = vehicle->GetPassenger(SEAT_WEST);
+ if (eastOrb && westOrb)
+ TriggerCutter(eastOrb, westOrb);
+ break;
+ }
+ default:
+ break;
}
}
private:
- InstanceScript* instance;
+ InstanceScript* _instance;
+ TaskScheduler scheduler;
void TriggerCutter(Unit* caster, Unit* target)
{
@@ -986,12 +1004,12 @@ class npc_meteor_strike_initial : public CreatureScript
controller->AI()->JustSummoned(me);
DoCast(me, SPELL_METEOR_STRIKE_COUNTDOWN);
- DoCast(me, SPELL_BIRTH_NO_VISUAL); // Unknown purpose
+ DoCast(me, SPELL_BIRTH_NO_VISUAL);
if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI()))
{
Position const* ownerPos = halionAI->GetMeteorStrikePosition();
- float randomAdjustment = frand(0.0f, static_cast<float>(M_PI / 5.0f));
+ float randomAdjustment = frand(static_cast<float>(M_PI / 5.0f), static_cast<float>(M_PI / 2.0f));
float angle[4];
angle[0] = me->GetAngle(ownerPos);
angle[1] = angle[0] + randomAdjustment;
@@ -1005,10 +1023,7 @@ class npc_meteor_strike_initial : public CreatureScript
me->SetOrientation(angle[i]);
Position newPos = me->GetNearPosition(10.0f, 0.0f); // Exact distance
if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000))
- {
- meteor->SetOrientation(angle[i]);
_meteorList.push_back(meteor);
- }
}
}
}
@@ -1045,7 +1060,7 @@ class npc_meteor_strike : public CreatureScript
{
DoCast(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
me->setActive(true);
- _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 500);
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(500));
}
}
@@ -1109,7 +1124,7 @@ class npc_meteor_strike_flame : public CreatureScript
void SetGUID(ObjectGuid guid, int32 /*id = 0 */) override
{
_rootOwnerGuid = guid;
- _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800);
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(800));
}
void IsSummonedBy(Unit* /*summoner*/) override
@@ -1201,7 +1216,7 @@ class npc_combustion_consumption : public CreatureScript
if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner)
return;
- me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me);
+ me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount + 1, me);
DoCast(me, _damageSpell);
int32 damage = 1200 + (stackAmount * 1290); // Needs more research.
@@ -1239,17 +1254,31 @@ class npc_living_inferno : public CreatureScript
// SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs.
if (me->GetMap()->GetDifficultyID() == DIFFICULTY_25_HC)
- me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true);
-
+ scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/)
+ {
+ me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true);
+ });
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
+ {
+ controller->AI()->DoAction(ACTION_ACTIVATE_EMBERS);
controller->AI()->JustSummoned(me);
+ }
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(1);
}
+
+ void UpdateAI(uint32 diff) override
+ {
+ scheduler.Update(diff);
+ ScriptedAI::UpdateAI(diff);
+ }
+
+ private:
+ TaskScheduler scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1265,27 +1294,7 @@ class npc_living_ember : public CreatureScript
struct npc_living_emberAI : public ScriptedAI
{
- npc_living_emberAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- _enrageTimer = 0;
- }
-
- void Initialize()
- {
- _hasEnraged = false;
- }
-
- void Reset() override
- {
- Initialize();
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- _enrageTimer = 20000;
- _hasEnraged = false;
- }
+ npc_living_emberAI(Creature* creature) : ScriptedAI(creature) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
@@ -1298,25 +1307,6 @@ class npc_living_ember : public CreatureScript
{
me->DespawnOrUnsummon(1);
}
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- if (!_hasEnraged && _enrageTimer <= diff)
- {
- _hasEnraged = true;
- DoCast(me, SPELL_BERSERK);
- }
- else _enrageTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
-
- private:
- uint32 _enrageTimer;
- bool _hasEnraged;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1474,6 +1464,47 @@ class spell_halion_combustion_consumption : public SpellScriptLoader
uint32 _spellID;
};
+class spell_halion_combustion_consumption_periodic : public SpellScriptLoader
+{
+ public:
+ spell_halion_combustion_consumption_periodic() : SpellScriptLoader("spell_halion_combustion_consumption_periodic") { }
+
+ class spell_halion_combustion_consumption_periodic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_combustion_consumption_periodic_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
+ return false;
+ return true;
+ }
+
+ void HandleTick(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell;
+ int32 radius = caster->GetObjectScale() * M_PI * 10000 / 3;
+
+ caster->CastCustomSpell(triggerSpell, SPELLVALUE_RADIUS_MOD, radius, (Unit*)nullptr, TRIGGERED_FULL_MASK, nullptr, aurEff, caster->GetGUID());
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption_periodic_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_halion_combustion_consumption_periodic_AuraScript();
+ }
+};
+
class spell_halion_marks : public SpellScriptLoader
{
public:
@@ -1512,7 +1543,7 @@ class spell_halion_marks : public SpellScriptLoader
return;
// Stacks marker
- GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, NULL, NULL, GetCasterGUID());
+ GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, nullptr, nullptr, GetCasterGUID());
}
void Register() override
@@ -1820,6 +1851,35 @@ class spell_halion_spawn_living_embers : public SpellScriptLoader
}
};
+class spell_halion_blazing_aura : public SpellScriptLoader
+{
+ public:
+ spell_halion_blazing_aura() : SpellScriptLoader("spell_halion_blazing_aura") { }
+
+ class spell_halion_blazing_aura_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_blazing_aura_SpellScript);
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ GetHitUnit()->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[EFFECT_1].TriggerSpell);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_halion_blazing_aura_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_FORCE_CAST);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_halion_blazing_aura_SpellScript();
+ }
+};
+
+
+
void AddSC_boss_halion()
{
new boss_halion();
@@ -1841,6 +1901,7 @@ void AddSC_boss_halion()
new spell_halion_combustion_consumption("spell_halion_fiery_combustion", SPELL_MARK_OF_COMBUSTION);
new spell_halion_marks("spell_halion_mark_of_combustion", SPELL_FIERY_COMBUSTION_SUMMON, SPELL_FIERY_COMBUSTION);
new spell_halion_marks("spell_halion_mark_of_consumption", SPELL_SOUL_CONSUMPTION_SUMMON, SPELL_SOUL_CONSUMPTION);
+ new spell_halion_combustion_consumption_periodic();
new spell_halion_damage_aoe_summon();
new spell_halion_twilight_realm_handlers("spell_halion_leave_twilight_realm", SPELL_SOUL_CONSUMPTION, false);
new spell_halion_twilight_realm_handlers("spell_halion_enter_twilight_realm", SPELL_FIERY_COMBUSTION, true);
@@ -1849,4 +1910,5 @@ void AddSC_boss_halion()
new spell_halion_twilight_cutter();
new spell_halion_clear_debuffs();
new spell_halion_spawn_living_embers();
+ new spell_halion_blazing_aura();
}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
index 398d66009a0..52049a13962 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
@@ -53,11 +53,11 @@ class instance_ruby_sanctum : public InstanceMapScript
void OnPlayerEnter(Player* /*player*/) override
{
- if (!GetGuidData(DATA_HALION_CONTROLLER) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
+ if (!GetGuidData(DATA_HALION) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
{
instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY());
- if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
- halionController->AI()->DoAction(ACTION_INTRO_HALION);
+ if (Creature* halionController = instance->GetCreature(GetGuidData(DATA_HALION_CONTROLLER)))
+ halionController->AI()->DoAction(ACTION_INTRO_HALION_2);
}
}
@@ -161,6 +161,12 @@ class instance_ruby_sanctum : public InstanceMapScript
}
}
+ void OnCreatureRemove(Creature* creature) override
+ {
+ if (creature->GetEntry() == NPC_HALION)
+ HalionGUID = ObjectGuid::Empty;
+ }
+
void OnUnitDeath(Unit* unit) override
{
Creature* creature = unit->ToCreature();
@@ -170,7 +176,7 @@ class instance_ruby_sanctum : public InstanceMapScript
if (creature->GetEntry() == NPC_GENERAL_ZARITHRIAN && GetBossState(DATA_HALION) != DONE)
{
instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY());
- if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
+ if (Creature* halionController = instance->GetCreature(GetGuidData(DATA_HALION_CONTROLLER)))
halionController->AI()->DoAction(ACTION_INTRO_HALION);
}
}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
index e387fd63285..afd5dc3a0bd 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
@@ -56,6 +56,7 @@ enum RSSharedActions
ACTION_INTRO_BALTHARUS = -3975101,
ACTION_BALTHARUS_DEATH = -3975102,
ACTION_INTRO_HALION = -4014601,
+ ACTION_INTRO_HALION_2 = -4014602,
};
enum RSCreaturesIds