diff options
| -rw-r--r-- | src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp | 2725 | ||||
| -rw-r--r-- | src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h | 1 |
2 files changed, 1239 insertions, 1487 deletions
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index dc587a42e96..95d59c34b71 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -32,7 +32,7 @@ #include "TemporarySummon.h" #include "Vehicle.h" -enum Texts +enum HalionTexts { // Shared SAY_REGENERATE = 0, // Without pressure in both realms, %s begins to regenerate. @@ -57,7 +57,7 @@ enum Texts EMOTE_WARN_LASER = 0 // The orbiting spheres pulse with dark energy! }; -enum Spells +enum HalionSpells { // Halion SPELL_FLAME_BREATH = 74525, @@ -119,7 +119,7 @@ enum Spells SPELL_COPY_DAMAGE = 74810 // Aura not found in DBCs. }; -enum Events +enum HalionEvents { // Halion EVENT_ACTIVATE_FIREWALL = 1, @@ -148,7 +148,7 @@ enum Events EVENT_EVADE_CHECK = 18 }; -enum Actions +enum HalionActions { // Meteor Strike ACTION_METEOR_STRIKE_BURN = 1, @@ -163,7 +163,7 @@ enum Actions ACTION_ACTIVATE_EMBERS = 6 }; -enum Phases +enum HalionPhases { PHASE_ALL = 0, PHASE_INTRO = 1, @@ -172,7 +172,7 @@ enum Phases PHASE_THREE = 4 }; -enum Misc +enum HalionMisc { DATA_TWILIGHT_DAMAGE_TAKEN = 1, DATA_MATERIAL_DAMAGE_TAKEN = 2, @@ -223,1510 +223,1316 @@ CorporealityEntry const _corporealityReference[MAX_CORPOREALITY_STATE] = {74831, 74836} }; -class boss_halion : public CreatureScript +// 39863 - Halion +struct boss_halion : public BossAI { - public: - boss_halion() : CreatureScript("boss_halion") { } + boss_halion(Creature* creature) : BossAI(creature, DATA_HALION) { } - struct boss_halionAI : public BossAI - { - boss_halionAI(Creature* creature) : BossAI(creature, DATA_HALION) { } + void EnterEvadeMode(EvadeReason why) override + { + if (why == EVADE_REASON_BOUNDARY || events.IsInPhase(PHASE_ONE)) + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->EnterEvadeMode(why); + } - void EnterEvadeMode(EvadeReason why) override - { - if (why == EVADE_REASON_BOUNDARY || events.IsInPhase(PHASE_ONE)) - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->EnterEvadeMode(why); - } + void JustEngagedWith(Unit* who) override + { + Talk(SAY_AGGRO); - void JustEngagedWith(Unit* who) override - { - Talk(SAY_AGGRO); + events.Reset(); + events.SetPhase(PHASE_ONE); - events.Reset(); - events.SetPhase(PHASE_ONE); + BossAI::JustEngagedWith(who); + me->AddAura(SPELL_TWILIGHT_PRECISION, me); + events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 5s); + 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, 18s); - BossAI::JustEngagedWith(who); - me->AddAura(SPELL_TWILIGHT_PRECISION, me); - events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 5s); - 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, 18s); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1); - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1); + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE); + } - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE); - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); - void JustDied(Unit* /*killer*/) override - { - _JustDied(); + Talk(SAY_DEATH); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - Talk(SAY_DEATH); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (Creature* twilightHalion = instance->GetCreature(DATA_TWILIGHT_HALION)) + if (twilightHalion->IsAlive()) + twilightHalion->KillSelf(); - if (Creature* twilightHalion = instance->GetCreature(DATA_TWILIGHT_HALION)) - if (twilightHalion->IsAlive()) - twilightHalion->KillSelf(); + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + if (controller->IsAlive()) + controller->KillSelf(); + } - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - if (controller->IsAlive()) - controller->KillSelf(); - } + Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; } - Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; } + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (damage >= me->GetHealth() && !events.IsInPhase(PHASE_THREE)) + damage = me->GetHealth() - 1; - void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override - { - if (damage >= me->GetHealth() && !events.IsInPhase(PHASE_THREE)) - damage = me->GetHealth() - 1; - - if (me->HealthBelowPctDamaged(75, damage) && events.IsInPhase(PHASE_ONE)) - { - events.SetPhase(PHASE_TWO); - Talk(SAY_PHASE_TWO); + if (me->HealthBelowPctDamaged(75, damage) && events.IsInPhase(PHASE_ONE)) + { + events.SetPhase(PHASE_TWO); + Talk(SAY_PHASE_TWO); - me->CastStop(); - me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE); - DoCastSelf(SPELL_TWILIGHT_PHASING); + me->CastStop(); + me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE); + DoCastSelf(SPELL_TWILIGHT_PHASING); - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_TWO); - return; - } + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_TWO); + return; + } - if (events.IsInPhase(PHASE_THREE)) - { - // Don't consider copied damage. - if (!me->InSamePhase(attacker)) - return; + if (events.IsInPhase(PHASE_THREE)) + { + // Don't consider copied damage. + if (!me->InSamePhase(attacker)) + return; - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->SetData(DATA_MATERIAL_DAMAGE_TAKEN, damage); - } - } + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->SetData(DATA_MATERIAL_DAMAGE_TAKEN, damage); + } + } - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_TWILIGHT_MENDING) - Talk(SAY_REGENERATE); - } + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_TWILIGHT_MENDING) + Talk(SAY_REGENERATE); + } - void UpdateAI(uint32 diff) override - { - if (events.IsInPhase(PHASE_TWO)) - return; + void UpdateAI(uint32 diff) override + { + if (events.IsInPhase(PHASE_TWO)) + return; - if (!UpdateVictim()) - return; + if (!UpdateVictim()) + return; - events.Update(diff); + events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - while (uint32 eventId = events.ExecuteEvent()) + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + 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: + DoCastSelf(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 = instance->GetGameObject(i)) + instance->HandleGameObject(ObjectGuid::Empty, false, flameRing); + break; + case EVENT_METEOR_STRIKE: { - switch (eventId) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, 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: - DoCastSelf(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 = instance->GetGameObject(i)) - instance->HandleGameObject(ObjectGuid::Empty, false, flameRing); - break; - case EVENT_METEOR_STRIKE: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_TWILIGHT_REALM)) - { - _meteorStrikePos = target->GetPosition(); - me->CastSpell(_meteorStrikePos, SPELL_METEOR_STRIKE, me->GetGUID()); - Talk(SAY_METEOR_STRIKE); - } - events.ScheduleEvent(EVENT_METEOR_STRIKE, 38s); - break; - } - case EVENT_FIERY_COMBUSTION: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, -SPELL_TWILIGHT_REALM)) - me->CastSpell(target, SPELL_FIERY_COMBUSTION, TRIGGERED_IGNORE_SET_FACING); - events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25s); - break; - } - default: - break; + _meteorStrikePos = target->GetPosition(); + me->CastSpell(_meteorStrikePos, SPELL_METEOR_STRIKE, me->GetGUID()); + Talk(SAY_METEOR_STRIKE); } + events.ScheduleEvent(EVENT_METEOR_STRIKE, 38s); + break; } - - DoMeleeAttackIfReady(); + case EVENT_FIERY_COMBUSTION: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, -SPELL_TWILIGHT_REALM)) + me->CastSpell(target, SPELL_FIERY_COMBUSTION, TRIGGERED_IGNORE_SET_FACING); + events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25s); + break; + } + default: + break; } + } - void SetData(uint32 index, uint32 value) override - { - if (index != DATA_FIGHT_PHASE) - return; + DoMeleeAttackIfReady(); + } - events.SetPhase(value); - } + void SetData(uint32 index, uint32 value) override + { + if (index != DATA_FIGHT_PHASE) + return; - private: - Position _meteorStrikePos; - }; + events.SetPhase(value); + } - CreatureAI* GetAI(Creature* creature) const override - { - return GetRubySanctumAI<boss_halionAI>(creature); - } +private: + Position _meteorStrikePos; }; -typedef boss_halion::boss_halionAI HalionAI; +typedef boss_halion HalionAI; -class boss_twilight_halion : public CreatureScript +// 40142 - Halion +struct boss_twilight_halion : public BossAI { - public: - boss_twilight_halion() : CreatureScript("boss_twilight_halion") { } - - struct boss_twilight_halionAI : public BossAI + boss_twilight_halion(Creature* creature) : BossAI(creature, DATA_TWILIGHT_HALION) + { + Creature* halion = instance->GetCreature(DATA_HALION); + if (!halion) + return; + + // 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); + DoCastSelf(SPELL_DUSK_SHROUD, true); + + me->SetHealth(halion->GetHealth()); + me->SetPhaseMask(0x20, true); + me->SetReactState(REACT_DEFENSIVE); + me->SetUnitFlag(UNIT_FLAG_IN_COMBAT); + events.ScheduleEvent(EVENT_TAIL_LASH, 12s); + events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 15s); + } + + void JustEngagedWith(Unit* who) override + { + events.SetPhase(PHASE_TWO); + + BossAI::JustEngagedWith(who); + me->AddAura(SPELL_TWILIGHT_PRECISION, me); + events.ScheduleEvent(EVENT_CLEAVE, 3s); + events.ScheduleEvent(EVENT_BREATH, 12s); + + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2); + } + + void Reset() override { } + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + + // Victims should not be in the Twilight Realm + me->CastSpell(victim, SPELL_LEAVE_TWILIGHT_REALM, true); + } + + void JustDied(Unit* killer) override + { + if (Creature* halion = instance->GetCreature(DATA_HALION)) { - boss_twilight_halionAI(Creature* creature) : BossAI(creature, DATA_TWILIGHT_HALION) - { - Creature* halion = instance->GetCreature(DATA_HALION); - if (!halion) - return; - - // 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); - DoCastSelf(SPELL_DUSK_SHROUD, true); - - me->SetHealth(halion->GetHealth()); - me->SetPhaseMask(0x20, true); - me->SetReactState(REACT_DEFENSIVE); - me->SetUnitFlag(UNIT_FLAG_IN_COMBAT); - events.ScheduleEvent(EVENT_TAIL_LASH, 12s); - events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 15s); - } - - void JustEngagedWith(Unit* who) override - { - events.SetPhase(PHASE_TWO); + // Ensure looting + if (me->IsDamageEnoughForLootingAndReward()) + halion->LowerPlayerDamageReq(halion->GetMaxHealth()); - BossAI::JustEngagedWith(who); - me->AddAura(SPELL_TWILIGHT_PRECISION, me); - events.ScheduleEvent(EVENT_CLEAVE, 3s); - events.ScheduleEvent(EVENT_BREATH, 12s); + if (halion->IsAlive()) + Unit::Kill(killer, halion); + } - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2); - } + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + if (controller->IsAlive()) + controller->KillSelf(); - void Reset() override { } - void EnterEvadeMode(EvadeReason /*why*/) override { } + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_KILL); + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (damage >= me->GetHealth() && !events.IsInPhase(PHASE_THREE)) + damage = me->GetHealth() - 1; + //Needed because we already have UNIT_FLAG_IN_COMBAT, otherwise JustEngagedWith won't ever be called + if (!events.IsInPhase(PHASE_TWO) && !events.IsInPhase(PHASE_THREE)) + JustEngagedWith(attacker); - // Victims should not be in the Twilight Realm - me->CastSpell(victim, SPELL_LEAVE_TWILIGHT_REALM, true); - } + if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO)) + { + events.SetPhase(PHASE_THREE); + me->CastStop(); + DoCastSelf(SPELL_TWILIGHT_DIVISION); + Talk(SAY_PHASE_THREE); + return; + } - void JustDied(Unit* killer) override - { - if (Creature* halion = instance->GetCreature(DATA_HALION)) - { - // Ensure looting - if (me->IsDamageEnoughForLootingAndReward()) - halion->LowerPlayerDamageReq(halion->GetMaxHealth()); + if (events.IsInPhase(PHASE_THREE)) + { + // Don't consider copied damage. + if (!me->InSamePhase(attacker)) + return; - if (halion->IsAlive()) - Unit::Kill(killer, halion); - } + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->SetData(DATA_TWILIGHT_DAMAGE_TAKEN, damage); + } + } + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + switch (spellInfo->Id) + { + case SPELL_TWILIGHT_DIVISION: if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - if (controller->IsAlive()) - controller->KillSelf(); - - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - } - - void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override - { - if (damage >= me->GetHealth() && !events.IsInPhase(PHASE_THREE)) - damage = me->GetHealth() - 1; - //Needed because we already have UNIT_FLAG_IN_COMBAT, otherwise JustEngagedWith won't ever be called - if (!events.IsInPhase(PHASE_TWO) && !events.IsInPhase(PHASE_THREE)) - JustEngagedWith(attacker); - - if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO)) - { - events.SetPhase(PHASE_THREE); - me->CastStop(); - DoCastSelf(SPELL_TWILIGHT_DIVISION); - Talk(SAY_PHASE_THREE); - return; - } - - if (events.IsInPhase(PHASE_THREE)) - { - // Don't consider copied damage. - if (!me->InSamePhase(attacker)) - return; - - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->SetData(DATA_TWILIGHT_DAMAGE_TAKEN, damage); - } - } - - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - switch (spellInfo->Id) - { - case SPELL_TWILIGHT_DIVISION: - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->DoAction(ACTION_MONITOR_CORPOREALITY); - break; - case SPELL_TWILIGHT_MENDING: - Talk(SAY_REGENERATE); - break; - default: - break; - } - } - - void UpdateAI(uint32 diff) override - { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + controller->AI()->DoAction(ACTION_MONITOR_CORPOREALITY); + break; + case SPELL_TWILIGHT_MENDING: + Talk(SAY_REGENERATE); + break; + default: + break; + } + } - if (!UpdateVictim()) - return; + void UpdateAI(uint32 diff) override + { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - events.Update(diff); + if (!UpdateVictim()) + return; - while (uint32 eventId = events.ExecuteEvent()) - { - 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: - DoCastSelf(SPELL_DARK_BREATH); - events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(10), Seconds(14))); - break; - case EVENT_SOUL_CONSUMPTION: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, SPELL_TWILIGHT_REALM)) - me->CastSpell(target, SPELL_SOUL_CONSUMPTION, TRIGGERED_IGNORE_SET_FACING); - events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20s); - break; - default: - break; - } - } + events.Update(diff); - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + while (uint32 eventId = events.ExecuteEvent()) { - return GetRubySanctumAI<boss_twilight_halionAI>(creature); + 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: + DoCastSelf(SPELL_DARK_BREATH); + events.ScheduleEvent(EVENT_BREATH, randtime(Seconds(10), Seconds(14))); + break; + case EVENT_SOUL_CONSUMPTION: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, SPELL_TWILIGHT_REALM)) + me->CastSpell(target, SPELL_SOUL_CONSUMPTION, TRIGGERED_IGNORE_SET_FACING); + events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20s); + break; + default: + break; + } } + + DoMeleeAttackIfReady(); + } }; -class npc_halion_controller : public CreatureScript +// 40146 - Halion Controller +struct npc_halion_controller : public ScriptedAI { - public: - npc_halion_controller() : CreatureScript("npc_halion_controller") { } - - struct npc_halion_controllerAI : public ScriptedAI + npc_halion_controller(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()), _summons(me) + { + Initialize(); + } + + void Initialize() + { + _materialCorporealityValue = 5; + _materialDamageTaken = 0; + _twilightDamageTaken = 0; + SetBoundary(_instance->GetBossBoundary(DATA_HALION)); + } + + void JustAppeared() override + { + if (_instance->GetGuidData(DATA_HALION) || _instance->GetBossState(DATA_GENERAL_ZARITHRIAN) != DONE) + return; + + Reset(); + me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); + } + + void Reset() override + { + _summons.DespawnAll(); + _events.Reset(); + Initialize(); + + DoCastSelf(SPELL_CLEAR_DEBUFFS); + } + + void JustSummoned(Creature* who) override + { + _summons.Summon(who); + } + + void JustDied(Unit* /*killer*/) override + { + _events.Reset(); + _summons.DespawnAll(); + + DoCastSelf(SPELL_CLEAR_DEBUFFS); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _twilightDamageTaken = 0; + _materialDamageTaken = 0; + + _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8min); + _events.ScheduleEvent(EVENT_EVADE_CHECK, 5s); + } + + void JustExitedCombat() override + { + if (_instance->GetBossState(DATA_HALION) == DONE) + return; + + if (Creature* twilightHalion = _instance->GetCreature(DATA_TWILIGHT_HALION)) { - npc_halion_controllerAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()), _summons(me) - { - Initialize(); - } - - void Initialize() - { - _materialCorporealityValue = 5; - _materialDamageTaken = 0; - _twilightDamageTaken = 0; - SetBoundary(_instance->GetBossBoundary(DATA_HALION)); - } - - void JustAppeared() override - { - if (_instance->GetGuidData(DATA_HALION) || _instance->GetBossState(DATA_GENERAL_ZARITHRIAN) != DONE) - return; - - Reset(); - me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); - } + twilightHalion->DespawnOrUnsummon(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, twilightHalion); + } - void Reset() override - { - _summons.DespawnAll(); - _events.Reset(); - Initialize(); + if (Creature* halion = _instance->GetCreature(DATA_HALION)) + { + halion->DespawnOrUnsummon(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, halion); + } - DoCastSelf(SPELL_CLEAR_DEBUFFS); - } + _instance->SetBossState(DATA_HALION, FAIL); + _summons.DespawnAll(); - void JustSummoned(Creature* who) override - { - _summons.Summon(who); - } + me->DespawnOrUnsummon(0s, 30s); + } - void JustDied(Unit* /*killer*/) override - { + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_INTRO_HALION: _events.Reset(); - _summons.DespawnAll(); - - DoCastSelf(SPELL_CLEAR_DEBUFFS); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _twilightDamageTaken = 0; - _materialDamageTaken = 0; - - _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8min); - _events.ScheduleEvent(EVENT_EVADE_CHECK, 5s); - } - - void JustExitedCombat() override - { - if (_instance->GetBossState(DATA_HALION) == DONE) + _events.SetPhase(PHASE_INTRO); + _events.ScheduleEvent(EVENT_START_INTRO, 2s); + break; + case ACTION_INTRO_HALION_2: + if (_instance->GetGuidData(DATA_HALION)) return; - if (Creature* twilightHalion = _instance->GetCreature(DATA_TWILIGHT_HALION)) - { - twilightHalion->DespawnOrUnsummon(); - _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, twilightHalion); - } - - if (Creature* halion = _instance->GetCreature(DATA_HALION)) - { - halion->DespawnOrUnsummon(); - _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, halion); - } - - _instance->SetBossState(DATA_HALION, FAIL); - _summons.DespawnAll(); - - me->DespawnOrUnsummon(0s, 30s); - } - - void DoAction(int32 action) override + for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_4; ++i) + if (GameObject* tree = _instance->GetGameObject(i)) + _instance->HandleGameObject(ObjectGuid::Empty, true, tree); + me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); + break; + case ACTION_MONITOR_CORPOREALITY: { - switch (action) + for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++) { - case ACTION_INTRO_HALION: - _events.Reset(); - _events.SetPhase(PHASE_INTRO); - _events.ScheduleEvent(EVENT_START_INTRO, 2s); - 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 = _instance->GetGameObject(i)) - _instance->HandleGameObject(ObjectGuid::Empty, true, tree); - me->GetMap()->SummonCreature(NPC_HALION, HalionRespawnPos); - break; - case ACTION_MONITOR_CORPOREALITY: - { - for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++) - { - Creature* halion = _instance->GetCreature(itr); - if (!halion) - continue; - - halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), false); - halion->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE); + Creature* halion = _instance->GetCreature(itr); + if (!halion) + continue; - if (itr == DATA_TWILIGHT_HALION) - continue; + halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), false); + halion->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE); - halion->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING); - halion->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE); - } + if (itr == DATA_TWILIGHT_HALION) + continue; - // Summon Twilight portals - DoCastSelf(SPELL_SUMMON_EXIT_PORTALS); - - _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TOGGLE, 1); - // Hardcoding doesn't really matter here. - _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 50); - _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 50); - - _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 7s); - break; - } - case ACTION_ACTIVATE_EMBERS: - _events.ScheduleEvent(EVENT_ACTIVATE_EMBERS, 6s); - break; - default: - break; + halion->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING); + halion->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE); } - } - void UpdateAI(uint32 diff) override - { - // The IsEngaged() check is needed because that check should be false when Halion is - // not engaged, while it would return true without as UpdateVictim() checks for - // combat state. - if (me->IsEngaged() && !UpdateVictim()) - return; + // Summon Twilight portals + DoCastSelf(SPELL_SUMMON_EXIT_PORTALS); - _events.Update(diff); + _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TOGGLE, 1); + // Hardcoding doesn't really matter here. + _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 50); + _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 50); - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_START_INTRO: - DoCastSelf(SPELL_COSMETIC_FIRE_PILLAR, true); - _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 = _instance->GetGameObject(i)) - _instance->HandleGameObject(ObjectGuid::Empty, true, tree); - _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 = _instance->GetGameObject(i)) - _instance->HandleGameObject(ObjectGuid::Empty, true, tree); - _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, Seconds(4)); - break; - case EVENT_INTRO_PROGRESS_3: - DoCastSelf(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 (_instance->GetCreature(DATA_HALION)) // Just check if physical Halion is spawned - if (Creature* twilightHalion = _instance->GetCreature(DATA_TWILIGHT_HALION)) - twilightHalion->CastSpell(nullptr, SPELL_TWILIGHT_MENDING, true); - break; - case EVENT_TRIGGER_BERSERK: - if (Creature* halion = _instance->GetCreature(DATA_HALION)) - halion->CastSpell(halion, SPELL_BERSERK, true); - if (Creature* halion = _instance->GetCreature(DATA_TWILIGHT_HALION)) - halion->CastSpell(halion, SPELL_BERSERK, true); - break; - case EVENT_SHADOW_PULSARS_SHOOT: - if (Creature* orbCarrier = _instance->GetCreature(DATA_ORB_CARRIER)) - orbCarrier->AI()->DoAction(ACTION_WARNING_SHOOT); - _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 30s); - break; - case EVENT_CHECK_CORPOREALITY: - UpdateCorporeality(); - _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5s); - break; - case EVENT_ACTIVATE_EMBERS: - _summons.DoZoneInCombat(NPC_LIVING_EMBER); - break; - case EVENT_EVADE_CHECK: - DoCheckEvade(); - _events.Repeat(Seconds(5)); - break; - default: - break; - } - } + _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 7s); + break; } + case ACTION_ACTIVATE_EMBERS: + _events.ScheduleEvent(EVENT_ACTIVATE_EMBERS, 6s); + break; + default: + break; + } + } - void DoCheckEvade() - { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) - if (player->IsAlive() && IsInBoundary(player) && !player->IsGameMaster()) - return; - - EnterEvadeMode(EVADE_REASON_NO_HOSTILES); - } - - void SetData(uint32 id, uint32 value) override - { - switch (id) - { - case DATA_MATERIAL_DAMAGE_TAKEN: - _materialDamageTaken += value; - break; - case DATA_TWILIGHT_DAMAGE_TAKEN: - _twilightDamageTaken += value; - break; - case DATA_FIGHT_PHASE: - _events.SetPhase(value); - switch (value) - { - case PHASE_ONE: - DoZoneInCombat(); - break; - case PHASE_TWO: - _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 35s); - break; - default: - break; - } - break; - default: - break; - } - } - - private: - //// @todo Find out a better scaling, if any. - // [0 , 0.98[: Corporeality goes down - // [0.98, 0.99]: Do nothing - // ]0.99, 1.01[: Twilight Mending - // [1.01, 1.02]: Do nothing - // ]1.02, +oo [: Corporeality goes up - void UpdateCorporeality() - { - uint8 oldValue = _materialCorporealityValue; - if (_twilightDamageTaken == 0 || _materialDamageTaken == 0) - { - _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); - _twilightDamageTaken = 0; - _materialDamageTaken = 0; - return; - } - - float damageRatio = float(_materialDamageTaken) / float(_twilightDamageTaken); + void UpdateAI(uint32 diff) override + { + // The IsEngaged() check is needed because that check should be false when Halion is + // not engaged, while it would return true without as UpdateVictim() checks for + // combat state. + if (me->IsEngaged() && !UpdateVictim()) + return; - CorporealityEvent action = CORPOREALITY_NONE; - if (damageRatio < 0.98f) // [0 , 0.98[: Corporeality goes down - action = CORPOREALITY_DECREASE; - else if (0.99f < damageRatio && damageRatio < 1.01f) // ]0.99, 1.01[: Twilight Mending - action = CORPOREALITY_TWILIGHT_MENDING; - else if (1.02f < damageRatio) // ]1.02, +oo [: Corporeality goes up - action = CORPOREALITY_INCREASE; + _events.Update(diff); - switch (action) - { - case CORPOREALITY_NONE: - { - _materialDamageTaken = 0; - _twilightDamageTaken = 0; - return; - } - case CORPOREALITY_INCREASE: - { - if (_materialCorporealityValue >= (MAX_CORPOREALITY_STATE - 1)) - return; - ++_materialCorporealityValue; - break; - } - case CORPOREALITY_DECREASE: - { - if (_materialCorporealityValue <= 0) - return; - --_materialCorporealityValue; - break; - } - case CORPOREALITY_TWILIGHT_MENDING: - { - _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); - _materialDamageTaken = 0; - _twilightDamageTaken = 0; + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_START_INTRO: + DoCastSelf(SPELL_COSMETIC_FIRE_PILLAR, true); + _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 = _instance->GetGameObject(i)) + _instance->HandleGameObject(ObjectGuid::Empty, true, tree); + _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 = _instance->GetGameObject(i)) + _instance->HandleGameObject(ObjectGuid::Empty, true, tree); + _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, Seconds(4)); + break; + case EVENT_INTRO_PROGRESS_3: + DoCastSelf(SPELL_FIERY_EXPLOSION); + if (_instance->GetGuidData(DATA_HALION)) return; - } - } - - _materialDamageTaken = 0; - _twilightDamageTaken = 0; - - _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, _materialCorporealityValue * 10); - _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 100 - _materialCorporealityValue * 10); - - for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++) - { - if (Creature* halion = _instance->GetCreature(itr)) - { - halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true); - - if (itr == DATA_TWILIGHT_HALION) - halion->AI()->Talk(oldValue < _materialCorporealityValue ? EMOTE_CORPOREALITY_TOT : EMOTE_CORPOREALITY_TIT, halion); - else // if (itr == DATA_HALION) - halion->AI()->Talk(oldValue > _materialCorporealityValue ? EMOTE_CORPOREALITY_POT : EMOTE_CORPOREALITY_PIP, halion); - } - } - } - - uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const - { - CorporealityEntry entry = _corporealityReference[pctValue]; - return isTwilight ? entry.twilightRealmSpell : entry.materialRealmSpell; + if (Creature* halion = me->GetMap()->SummonCreature(NPC_HALION, HalionSpawnPos)) + halion->AI()->Talk(SAY_INTRO); + break; + case EVENT_TWILIGHT_MENDING: + if (_instance->GetCreature(DATA_HALION)) // Just check if physical Halion is spawned + if (Creature* twilightHalion = _instance->GetCreature(DATA_TWILIGHT_HALION)) + twilightHalion->CastSpell(nullptr, SPELL_TWILIGHT_MENDING, true); + break; + case EVENT_TRIGGER_BERSERK: + if (Creature* halion = _instance->GetCreature(DATA_HALION)) + halion->CastSpell(halion, SPELL_BERSERK, true); + if (Creature* halion = _instance->GetCreature(DATA_TWILIGHT_HALION)) + halion->CastSpell(halion, SPELL_BERSERK, true); + break; + case EVENT_SHADOW_PULSARS_SHOOT: + if (Creature* orbCarrier = _instance->GetCreature(DATA_ORB_CARRIER)) + orbCarrier->AI()->DoAction(ACTION_WARNING_SHOOT); + _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 30s); + break; + case EVENT_CHECK_CORPOREALITY: + UpdateCorporeality(); + _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5s); + break; + case EVENT_ACTIVATE_EMBERS: + _summons.DoZoneInCombat(NPC_LIVING_EMBER); + break; + case EVENT_EVADE_CHECK: + DoCheckEvade(); + _events.Repeat(Seconds(5)); + break; + default: + break; } - - EventMap _events; - InstanceScript* _instance; - SummonList _summons; - - uint32 _twilightDamageTaken; - uint32 _materialDamageTaken; - uint8 _materialCorporealityValue; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRubySanctumAI<npc_halion_controllerAI>(creature); } -}; + } + + void DoCheckEvade() + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->GetSource()) + if (player->IsAlive() && IsInBoundary(player) && !player->IsGameMaster()) + return; -class npc_orb_carrier : public CreatureScript -{ - public: - npc_orb_carrier() : CreatureScript("npc_orb_carrier") { } + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); + } - struct npc_orb_carrierAI : public ScriptedAI + void SetData(uint32 id, uint32 value) override + { + switch (id) { - npc_orb_carrierAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) - { - ASSERT(creature->GetVehicleKit()); - } - - 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(nullptr, SPELL_TRACK_ROTATION, false); - - scheduler.Update(diff); - } - - void DoAction(int32 action) override - { - switch (action) + case DATA_MATERIAL_DAMAGE_TAKEN: + _materialDamageTaken += value; + break; + case DATA_TWILIGHT_DAMAGE_TAKEN: + _twilightDamageTaken += value; + break; + case DATA_FIGHT_PHASE: + _events.SetPhase(value); + switch (value) { - case ACTION_WARNING_SHOOT: - { - Vehicle* vehicle = me->GetVehicleKit(); - Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); - if (northOrb && northOrb->GetTypeId() == TYPEID_UNIT) - northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER); - - scheduler.Schedule(Seconds(5), [this](TaskContext /*context*/) - { - DoAction(ACTION_SHOOT); - }); + case PHASE_ONE: + DoZoneInCombat(); 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 (Creature* twilightHalion = _instance->GetCreature(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); + case PHASE_TWO: + _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 35s); break; - } default: break; } - } - private: - InstanceScript* _instance; - TaskScheduler scheduler; - - void TriggerCutter(Unit* caster, Unit* target) - { - caster->CastSpell(caster, SPELL_TWILIGHT_PULSE_PERIODIC, true); - target->CastSpell(target, SPELL_TWILIGHT_PULSE_PERIODIC, true); - caster->CastSpell(target, SPELL_TWILIGHT_CUTTER, false); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + break; + default: + break; + } + } + +private: + //// @todo Find out a better scaling, if any. + // [0 , 0.98[: Corporeality goes down + // [0.98, 0.99]: Do nothing + // ]0.99, 1.01[: Twilight Mending + // [1.01, 1.02]: Do nothing + // ]1.02, +oo [: Corporeality goes up + void UpdateCorporeality() + { + uint8 oldValue = _materialCorporealityValue; + if (_twilightDamageTaken == 0 || _materialDamageTaken == 0) { - return GetRubySanctumAI<npc_orb_carrierAI>(creature); + _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); + _twilightDamageTaken = 0; + _materialDamageTaken = 0; + return; } -}; -class npc_meteor_strike_initial : public CreatureScript -{ - public: - npc_meteor_strike_initial() : CreatureScript("npc_meteor_strike_initial") { } + float damageRatio = float(_materialDamageTaken) / float(_twilightDamageTaken); + + CorporealityEvent action = CORPOREALITY_NONE; + if (damageRatio < 0.98f) // [0 , 0.98[: Corporeality goes down + action = CORPOREALITY_DECREASE; + else if (0.99f < damageRatio && damageRatio < 1.01f) // ]0.99, 1.01[: Twilight Mending + action = CORPOREALITY_TWILIGHT_MENDING; + else if (1.02f < damageRatio) // ]1.02, +oo [: Corporeality goes up + action = CORPOREALITY_INCREASE; - struct npc_meteor_strike_initialAI : public ScriptedAI + switch (action) { - npc_meteor_strike_initialAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) + case CORPOREALITY_NONE: { - SetCombatMovement(false); + _materialDamageTaken = 0; + _twilightDamageTaken = 0; + return; } - - void DoAction(int32 action) override + case CORPOREALITY_INCREASE: { - switch (action) - { - case ACTION_METEOR_STRIKE_AOE: - DoCastSelf(SPELL_METEOR_STRIKE_AOE_DAMAGE, true); - DoCastSelf(SPELL_METEOR_STRIKE_FIRE_AURA_1, true); - for (std::list<Creature*>::iterator itr = _meteorList.begin(); itr != _meteorList.end(); ++itr) - (*itr)->AI()->DoAction(ACTION_METEOR_STRIKE_BURN); - break; - } + if (_materialCorporealityValue >= (MAX_CORPOREALITY_STATE - 1)) + return; + ++_materialCorporealityValue; + break; } - - void IsSummonedBy(WorldObject* summoner) override + case CORPOREALITY_DECREASE: { - Creature* owner = summoner->ToCreature(); - if (!owner) + if (_materialCorporealityValue <= 0) return; - - // Let Controller count as summoner - if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->JustSummoned(me); - - DoCastSelf(SPELL_METEOR_STRIKE_COUNTDOWN); - DoCastSelf(SPELL_BIRTH_NO_VISUAL); - - if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI())) - { - Position const* ownerPos = halionAI->GetMeteorStrikePosition(); - float randomAdjustment = frand(static_cast<float>(M_PI / 5.0f), static_cast<float>(M_PI / 2.0f)); - float angle[4]; - angle[0] = me->GetAbsoluteAngle(ownerPos); - angle[1] = angle[0] + randomAdjustment; - angle[2] = angle[0] + static_cast<float>(M_PI); - angle[3] = angle[2] + randomAdjustment; - - _meteorList.clear(); - for (uint8 i = 0; i < 4; i++) - { - angle[i] = Position::NormalizeOrientation(angle[i]); - 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, 30s)) - _meteorList.push_back(meteor); - } - } + --_materialCorporealityValue; + break; } - - void UpdateAI(uint32 /*diff*/) override { } - void EnterEvadeMode(EvadeReason /*why*/) override { } - private: - InstanceScript* _instance; - std::list<Creature*> _meteorList; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRubySanctumAI<npc_meteor_strike_initialAI>(creature); - } -}; - -class npc_meteor_strike : public CreatureScript -{ - public: - npc_meteor_strike() : CreatureScript("npc_meteor_strike") { } - - struct npc_meteor_strikeAI : public ScriptedAI - { - npc_meteor_strikeAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()), _spawnCount(0) + case CORPOREALITY_TWILIGHT_MENDING: { - SetCombatMovement(false); + _events.ScheduleEvent(EVENT_TWILIGHT_MENDING, Milliseconds(100)); + _materialDamageTaken = 0; + _twilightDamageTaken = 0; + return; } + } - void DoAction(int32 action) override - { - if (action == ACTION_METEOR_STRIKE_BURN) - { - DoCastSelf(SPELL_METEOR_STRIKE_FIRE_AURA_2, true); - me->setActive(true); - me->SetFarVisible(true); - _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(500)); - } - } + _materialDamageTaken = 0; + _twilightDamageTaken = 0; - void IsSummonedBy(WorldObject* /*summoner*/) override - { - // Let Halion Controller count as summoner. - if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->JustSummoned(me); - } + _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, _materialCorporealityValue * 10); + _instance->DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 100 - _materialCorporealityValue * 10); - void SetData(uint32 dataType, uint32 dataCount) override + for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++) + { + if (Creature* halion = _instance->GetCreature(itr)) { - if (dataType == DATA_SPAWNED_FLAMES) - _spawnCount += dataCount; - } + halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true); - uint32 GetData(uint32 dataType) const override - { - if (dataType == DATA_SPAWNED_FLAMES) - return _spawnCount; - return 0; + if (itr == DATA_TWILIGHT_HALION) + halion->AI()->Talk(oldValue < _materialCorporealityValue ? EMOTE_CORPOREALITY_TOT : EMOTE_CORPOREALITY_TIT, halion); + else // if (itr == DATA_HALION) + halion->AI()->Talk(oldValue > _materialCorporealityValue ? EMOTE_CORPOREALITY_POT : EMOTE_CORPOREALITY_PIP, halion); } + } + } - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME) - { - Position pos = me->GetNearPosition(5.0f, frand(-static_cast<float>(M_PI / 6.0f), static_cast<float>(M_PI / 6.0f))); - if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) - flame->AI()->SetGUID(me->GetGUID()); - } - } + uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const + { + CorporealityEntry entry = _corporealityReference[pctValue]; + return isTwilight ? entry.twilightRealmSpell : entry.materialRealmSpell; + } - private: - InstanceScript* _instance; - EventMap _events; - uint8 _spawnCount; - }; + EventMap _events; + InstanceScript* _instance; + SummonList _summons; - CreatureAI* GetAI(Creature* creature) const override - { - return GetRubySanctumAI<npc_meteor_strikeAI>(creature); - } + uint32 _twilightDamageTaken; + uint32 _materialDamageTaken; + uint8 _materialCorporealityValue; }; -class npc_meteor_strike_flame : public CreatureScript +// 40081 - Orb Carrier +struct npc_orb_carrier : public ScriptedAI { - public: - npc_meteor_strike_flame() : CreatureScript("npc_meteor_strike_flame") { } - - struct npc_meteor_strike_flameAI : public ScriptedAI + npc_orb_carrier(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + ASSERT(creature->GetVehicleKit()); + } + + 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(nullptr, SPELL_TRACK_ROTATION, false); + + scheduler.Update(diff); + } + + void DoAction(int32 action) override + { + switch (action) { - npc_meteor_strike_flameAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) + case ACTION_WARNING_SHOOT: { - SetCombatMovement(false); - } + Vehicle* vehicle = me->GetVehicleKit(); + Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); + if (northOrb && northOrb->GetTypeId() == TYPEID_UNIT) + northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER); - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override - { - _rootOwnerGuid = guid; - _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(800)); - } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - // Let Halion Controller count as summoner. - if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->JustSummoned(me); + scheduler.Schedule(Seconds(5), [this](TaskContext /*context*/) + { + DoAction(ACTION_SHOOT); + }); + break; } - - void UpdateAI(uint32 diff) override + case ACTION_SHOOT: { - _events.Update(diff); - if (_events.ExecuteEvent() != EVENT_SPAWN_METEOR_FLAME) - return; - - me->CastSpell(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true); + Vehicle* vehicle = me->GetVehicleKit(); + Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH); + Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH); + if (southOrb && northOrb) + TriggerCutter(northOrb, southOrb); - Creature* meteorStrike = ObjectAccessor::GetCreature(*me, _rootOwnerGuid); - if (!meteorStrike) - return; + if (Creature* twilightHalion = _instance->GetCreature(DATA_TWILIGHT_HALION)) + twilightHalion->AI()->Talk(SAY_SPHERE_PULSE); - meteorStrike->AI()->SetData(DATA_SPAWNED_FLAMES, 1); - if (meteorStrike->AI()->GetData(DATA_SPAWNED_FLAMES) > 5) + if (!IsHeroic()) return; - Position pos = me->GetNearPosition(5.0f, frand(-static_cast<float>(M_PI / 6.0f), static_cast<float>(M_PI / 6.0f))); - if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) - flame->AI()->SetGUID(_rootOwnerGuid); + Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST); + Unit* westOrb = vehicle->GetPassenger(SEAT_WEST); + if (eastOrb && westOrb) + TriggerCutter(eastOrb, westOrb); + break; } - - void EnterEvadeMode(EvadeReason /*why*/) override { } - - private: - InstanceScript* _instance; - EventMap _events; - ObjectGuid _rootOwnerGuid; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRubySanctumAI<npc_meteor_strike_flameAI>(creature); + default: + break; } + } +private: + InstanceScript* _instance; + TaskScheduler scheduler; + + void TriggerCutter(Unit* caster, Unit* target) + { + caster->CastSpell(caster, SPELL_TWILIGHT_PULSE_PERIODIC, true); + target->CastSpell(target, SPELL_TWILIGHT_PULSE_PERIODIC, true); + caster->CastSpell(target, SPELL_TWILIGHT_CUTTER, false); + } }; -class npc_combustion_consumption : public CreatureScript +// 40029 - Meteor Strike +struct npc_meteor_strike_initial : public ScriptedAI { - public: - npc_combustion_consumption() : CreatureScript("npc_combustion_consumption") { } - - struct npc_combustion_consumptionAI : public ScriptedAI + npc_meteor_strike_initial(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + } + + void DoAction(int32 action) override + { + switch (action) { - npc_combustion_consumptionAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) - { - SetCombatMovement(false); - - switch (creature->GetEntry()) - { - case NPC_COMBUSTION: - _explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION; - _damageSpell = SPELL_COMBUSTION_DAMAGE_AURA; - creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x01, true); - break; - case NPC_CONSUMPTION: - _explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION; - _damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA; - creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x20, true); - break; - default: // Should never happen - _explosionSpell = 0; - _damageSpell = 0; - break; - } - } - - void IsSummonedBy(WorldObject* summoner) override - { - // Let Halion Controller count as summoner - if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->JustSummoned(me); - - _summonerGuid = summoner->GetGUID(); - } - - void SetData(uint32 type, uint32 stackAmount) override - { - Unit* summoner = ObjectAccessor::GetUnit(*me, _summonerGuid); - - if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner) - return; + case ACTION_METEOR_STRIKE_AOE: + DoCastSelf(SPELL_METEOR_STRIKE_AOE_DAMAGE, true); + DoCastSelf(SPELL_METEOR_STRIKE_FIRE_AURA_1, true); + for (std::list<Creature*>::iterator itr = _meteorList.begin(); itr != _meteorList.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_METEOR_STRIKE_BURN); + break; + } + } - CastSpellExtraArgs args; - args.AddSpellMod(SPELLVALUE_AURA_STACK, stackAmount + 1); - me->CastSpell(me, SPELL_SCALE_AURA, args); - DoCastSelf(_damageSpell); + void IsSummonedBy(WorldObject* summoner) override + { + Creature* owner = summoner->ToCreature(); + if (!owner) + return; - int32 damage = 1200 + (stackAmount * 1290); // Needs more research. - CastSpellExtraArgs args2; - args2.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); - summoner->CastSpell(summoner, _explosionSpell, args2); - } + // Let Controller count as summoner + if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->JustSummoned(me); - void UpdateAI(uint32 /*diff*/) override { } + DoCastSelf(SPELL_METEOR_STRIKE_COUNTDOWN); + DoCastSelf(SPELL_BIRTH_NO_VISUAL); - private: - InstanceScript* _instance; - uint32 _explosionSpell; - uint32 _damageSpell; - ObjectGuid _summonerGuid; - }; - - CreatureAI* GetAI(Creature* creature) const override + if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI())) { - return GetRubySanctumAI<npc_combustion_consumptionAI>(creature); + Position const* ownerPos = halionAI->GetMeteorStrikePosition(); + float randomAdjustment = frand(static_cast<float>(M_PI / 5.0f), static_cast<float>(M_PI / 2.0f)); + float angle[4]; + angle[0] = me->GetAbsoluteAngle(ownerPos); + angle[1] = angle[0] + randomAdjustment; + angle[2] = angle[0] + static_cast<float>(M_PI); + angle[3] = angle[2] + randomAdjustment; + + _meteorList.clear(); + for (uint8 i = 0; i < 4; i++) + { + angle[i] = Position::NormalizeOrientation(angle[i]); + 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, 30s)) + _meteorList.push_back(meteor); + } } + } + + void UpdateAI(uint32 /*diff*/) override { } + void EnterEvadeMode(EvadeReason /*why*/) override { } +private: + InstanceScript* _instance; + std::list<Creature*> _meteorList; }; -class npc_living_inferno : public CreatureScript +// 40041, 40042, 40043, 40044 - Meteor Strike +struct npc_meteor_strike : public ScriptedAI { - public: - npc_living_inferno() : CreatureScript("npc_living_inferno") { } - - struct npc_living_infernoAI : public ScriptedAI + npc_meteor_strike(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()), _spawnCount(0) + { + SetCombatMovement(false); + } + + void DoAction(int32 action) override + { + if (action == ACTION_METEOR_STRIKE_BURN) { - npc_living_infernoAI(Creature* creature) : ScriptedAI(creature) { } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - DoZoneInCombat(); - me->CastSpell(me, SPELL_BLAZING_AURA, true); - - // SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs. - if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) - scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) - { - me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true); - }); - - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - { - controller->AI()->DoAction(ACTION_ACTIVATE_EMBERS); - controller->AI()->JustSummoned(me); - } - } - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(1ms); - } - - void UpdateAI(uint32 diff) override - { - scheduler.Update(diff); - ScriptedAI::UpdateAI(diff); - } - - private: - TaskScheduler scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override + DoCastSelf(SPELL_METEOR_STRIKE_FIRE_AURA_2, true); + me->setActive(true); + me->SetFarVisible(true); + _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(500)); + } + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + // Let Halion Controller count as summoner. + if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->JustSummoned(me); + } + + void SetData(uint32 dataType, uint32 dataCount) override + { + if (dataType == DATA_SPAWNED_FLAMES) + _spawnCount += dataCount; + } + + uint32 GetData(uint32 dataType) const override + { + if (dataType == DATA_SPAWNED_FLAMES) + return _spawnCount; + return 0; + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME) { - return GetRubySanctumAI<npc_living_infernoAI>(creature); + Position pos = me->GetNearPosition(5.0f, frand(-static_cast<float>(M_PI / 6.0f), static_cast<float>(M_PI / 6.0f))); + if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) + flame->AI()->SetGUID(me->GetGUID()); } + } + +private: + InstanceScript* _instance; + EventMap _events; + uint8 _spawnCount; }; -class npc_living_ember : public CreatureScript +// 40055 - Meteor Strike +struct npc_meteor_strike_flame : public ScriptedAI { - public: - npc_living_ember() : CreatureScript("npc_living_ember") { } - - struct npc_living_emberAI : public ScriptedAI - { - npc_living_emberAI(Creature* creature) : ScriptedAI(creature) { } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) - controller->AI()->JustSummoned(me); - } + npc_meteor_strike_flame(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + } + + void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + { + _rootOwnerGuid = guid; + _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, Milliseconds(800)); + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + // Let Halion Controller count as summoner. + if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->JustSummoned(me); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + if (_events.ExecuteEvent() != EVENT_SPAWN_METEOR_FLAME) + return; + + me->CastSpell(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true); + + Creature* meteorStrike = ObjectAccessor::GetCreature(*me, _rootOwnerGuid); + if (!meteorStrike) + return; + + meteorStrike->AI()->SetData(DATA_SPAWNED_FLAMES, 1); + if (meteorStrike->AI()->GetData(DATA_SPAWNED_FLAMES) > 5) + return; + + Position pos = me->GetNearPosition(5.0f, frand(-static_cast<float>(M_PI / 6.0f), static_cast<float>(M_PI / 6.0f))); + if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25s)) + flame->AI()->SetGUID(_rootOwnerGuid); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + +private: + InstanceScript* _instance; + EventMap _events; + ObjectGuid _rootOwnerGuid; +}; - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(1ms); - } - }; +// 40001 - Combustion +// 40135 - Consumption +struct npc_combustion_consumption : public ScriptedAI +{ + npc_combustion_consumption(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); - CreatureAI* GetAI(Creature* creature) const override + switch (creature->GetEntry()) { - return GetRubySanctumAI<npc_living_emberAI>(creature); + case NPC_COMBUSTION: + _explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION; + _damageSpell = SPELL_COMBUSTION_DAMAGE_AURA; + creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x01, true); + break; + case NPC_CONSUMPTION: + _explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION; + _damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA; + creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x20, true); + break; + default: // Should never happen + _explosionSpell = 0; + _damageSpell = 0; + break; } + } + + void IsSummonedBy(WorldObject* summoner) override + { + // Let Halion Controller count as summoner + if (Creature* controller = _instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->JustSummoned(me); + + _summonerGuid = summoner->GetGUID(); + } + + void SetData(uint32 type, uint32 stackAmount) override + { + Unit* summoner = ObjectAccessor::GetUnit(*me, _summonerGuid); + + if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner) + return; + + CastSpellExtraArgs args; + args.AddSpellMod(SPELLVALUE_AURA_STACK, stackAmount + 1); + me->CastSpell(me, SPELL_SCALE_AURA, args); + DoCastSelf(_damageSpell); + + int32 damage = 1200 + (stackAmount * 1290); // Needs more research. + CastSpellExtraArgs args2; + args2.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); + summoner->CastSpell(summoner, _explosionSpell, args2); + } + + void UpdateAI(uint32 /*diff*/) override { } + +private: + InstanceScript* _instance; + uint32 _explosionSpell; + uint32 _damageSpell; + ObjectGuid _summonerGuid; }; -class go_twilight_portal : public GameObjectScript +// 40681 - Living Inferno +struct npc_living_inferno : public ScriptedAI { - public: - go_twilight_portal() : GameObjectScript("go_twilight_portal") { } + npc_living_inferno(Creature* creature) : ScriptedAI(creature) { } - struct go_twilight_portalAI : public GameObjectAI - { - go_twilight_portalAI(GameObject* gameobject) : GameObjectAI(gameobject), - _instance(gameobject->GetInstanceScript()), _deleted(false) - { - switch (gameobject->GetEntry()) - { - case GO_HALION_PORTAL_EXIT: - gameobject->SetPhaseMask(0x20, true); - _spellId = gameobject->GetGOInfo()->goober.spellId; - break; - case GO_HALION_PORTAL_1: - case GO_HALION_PORTAL_2: - gameobject->SetPhaseMask(0x1, true); - /// Because WDB template has non-existent spell ID, not seen in sniffs either, meh - _spellId = SPELL_TWILIGHT_REALM; - break; - default: - _spellId = 0; - break; - } - } + void IsSummonedBy(WorldObject* /*summoner*/) override + { + DoZoneInCombat(); + me->CastSpell(me, SPELL_BLAZING_AURA, true); - bool OnGossipHello(Player* player) override + // SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs. + if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) + scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) { - if (_spellId != 0) - player->CastSpell(player, _spellId, true); - return true; - } + me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true); + }); - void UpdateAI(uint32 /*diff*/) override + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) { - if (_instance->GetBossState(DATA_HALION) == IN_PROGRESS) - return; - - if (!_deleted) - { - _deleted = true; - me->Delete(); - } + controller->AI()->DoAction(ACTION_ACTIVATE_EMBERS); + controller->AI()->JustSummoned(me); } + } - private: - InstanceScript* _instance; - uint32 _spellId; - bool _deleted; - }; + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(1ms); + } - GameObjectAI* GetAI(GameObject* gameobject) const override - { - return GetRubySanctumAI<go_twilight_portalAI>(gameobject); - } + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + ScriptedAI::UpdateAI(diff); + } + +private: + TaskScheduler scheduler; }; -// 74641 - Meteor Strike -class spell_halion_meteor_strike_marker : public SpellScriptLoader +// 40683 - Living Ember +struct npc_living_ember : public ScriptedAI { - public: - spell_halion_meteor_strike_marker() : SpellScriptLoader("spell_halion_meteor_strike_marker") { } + npc_living_ember(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* controller = instance->GetCreature(DATA_HALION_CONTROLLER)) + controller->AI()->JustSummoned(me); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(1ms); + } +}; - class spell_halion_meteor_strike_marker_AuraScript : public AuraScript +// 202794, 202796 - Twilight Portal +struct go_twilight_portal : public GameObjectAI +{ + go_twilight_portal(GameObject* gameobject) : GameObjectAI(gameobject), + _instance(gameobject->GetInstanceScript()), _deleted(false) + { + switch (gameobject->GetEntry()) { - PrepareAuraScript(spell_halion_meteor_strike_marker_AuraScript); + case GO_HALION_PORTAL_EXIT: + gameobject->SetPhaseMask(0x20, true); + _spellId = gameobject->GetGOInfo()->goober.spellId; + break; + case GO_HALION_PORTAL_1: + case GO_HALION_PORTAL_2: + gameobject->SetPhaseMask(0x1, true); + /// Because WDB template has non-existent spell ID, not seen in sniffs either, meh + _spellId = SPELL_TWILIGHT_REALM; + break; + default: + _spellId = 0; + break; + } + } - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (!GetCaster()) - return; + bool OnGossipHello(Player* player) override + { + if (_spellId != 0) + player->CastSpell(player, _spellId, true); + return true; + } - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) - if (Creature* creCaster = GetCaster()->ToCreature()) - creCaster->AI()->DoAction(ACTION_METEOR_STRIKE_AOE); - } + void UpdateAI(uint32 /*diff*/) override + { + if (_instance->GetBossState(DATA_HALION) == IN_PROGRESS) + return; - void Register() override - { - AfterEffectRemove += AuraEffectRemoveFn(spell_halion_meteor_strike_marker_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + if (!_deleted) { - return new spell_halion_meteor_strike_marker_AuraScript(); + _deleted = true; + me->Delete(); } + } + +private: + InstanceScript* _instance; + uint32 _spellId; + bool _deleted; }; -class spell_halion_combustion_consumption : public SpellScriptLoader +// 74641 - Meteor Strike +class spell_halion_meteor_strike_marker : public AuraScript { - public: - spell_halion_combustion_consumption(char const* scriptName, uint32 spell) : SpellScriptLoader(scriptName), _spellID(spell) { } - - class spell_halion_combustion_consumption_AuraScript : public AuraScript - { - PrepareAuraScript(spell_halion_combustion_consumption_AuraScript); - - public: - spell_halion_combustion_consumption_AuraScript(uint32 spellID) : AuraScript(), _markSpell(spellID) { } - - private: - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ _markSpell }); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) - return; - - if (GetTarget()->HasAura(_markSpell)) - GetTarget()->RemoveAurasDueToSpell(_markSpell, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE); - } - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->CastSpell(GetTarget(), _markSpell, true); - } - - void AddMarkStack(AuraEffect const* /*aurEff*/) - { - GetTarget()->CastSpell(GetTarget(), _markSpell, true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption_AuraScript::AddMarkStack, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); - AfterEffectApply += AuraEffectApplyFn(spell_halion_combustion_consumption_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_halion_combustion_consumption_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); - } - - uint32 _markSpell; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_halion_combustion_consumption_AuraScript(_spellID); - } + PrepareAuraScript(spell_halion_meteor_strike_marker); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (!GetCaster()) + return; + + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + if (Creature* creCaster = GetCaster()->ToCreature()) + creCaster->AI()->DoAction(ACTION_METEOR_STRIKE_AOE); + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_halion_meteor_strike_marker::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; - private: - uint32 _spellID; +// 74792 - Soul Consumption +// 74562 - Fiery Combustion +class spell_halion_combustion_consumption : public AuraScript +{ + PrepareAuraScript(spell_halion_combustion_consumption); + +public: + spell_halion_combustion_consumption(uint32 spellID) : AuraScript(), _markSpell(spellID) { } + +private: + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ _markSpell }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) + return; + + if (GetTarget()->HasAura(_markSpell)) + GetTarget()->RemoveAurasDueToSpell(_markSpell, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE); + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->CastSpell(GetTarget(), _markSpell, true); + } + + void AddMarkStack(AuraEffect const* /*aurEff*/) + { + GetTarget()->CastSpell(GetTarget(), _markSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption::AddMarkStack, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + AfterEffectApply += AuraEffectApplyFn(spell_halion_combustion_consumption::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_halion_combustion_consumption::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } + + uint32 _markSpell; }; // 74629 - Combustion Periodic // 74803 - Consumption Periodic -class spell_halion_combustion_consumption_periodic : public SpellScriptLoader +class spell_halion_combustion_consumption_periodic : public AuraScript { - 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 - { - return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); - } - - void HandleTick(AuraEffect const* aurEff) - { - PreventDefaultAction(); - Unit* caster = GetCaster(); - if (!caster) - return; - - uint32 triggerSpell = aurEff->GetSpellEffectInfo().TriggerSpell; - int32 radius = caster->GetObjectScale() * M_PI * 10000 / 3; - - CastSpellExtraArgs args(aurEff); - args.OriginalCaster = caster->GetGUID(); - args.AddSpellMod(SPELLVALUE_RADIUS_MOD, radius); - caster->CastSpell(nullptr, triggerSpell, args); - } - - 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(); - } + PrepareAuraScript(spell_halion_combustion_consumption_periodic); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + } + + void HandleTick(AuraEffect const* aurEff) + { + PreventDefaultAction(); + Unit* caster = GetCaster(); + if (!caster) + return; + + uint32 triggerSpell = aurEff->GetSpellEffectInfo().TriggerSpell; + int32 radius = caster->GetObjectScale() * M_PI * 10000 / 3; + + CastSpellExtraArgs args(aurEff); + args.OriginalCaster = caster->GetGUID(); + args.AddSpellMod(SPELLVALUE_RADIUS_MOD, radius); + caster->CastSpell(nullptr, triggerSpell, args); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_halion_combustion_consumption_periodic::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; -class spell_halion_marks : public SpellScriptLoader +// 74567 - Mark of Combustion +// 74795 - Mark of Consumption +class spell_halion_marks : public AuraScript { - public: - spell_halion_marks(char const* scriptName, uint32 summonSpell, uint32 removeSpell) : SpellScriptLoader(scriptName), - _summonSpell(summonSpell), _removeSpell(removeSpell) { } - - class spell_halion_marks_AuraScript : public AuraScript - { - PrepareAuraScript(spell_halion_marks_AuraScript); - - public: - spell_halion_marks_AuraScript(uint32 summonSpell, uint32 removeSpell) : AuraScript(), - _summonSpellId(summonSpell), _removeSpellId(removeSpell) { } - - private: - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ _summonSpellId, _removeSpellId }); - } - - /// We were purged. Force removed stacks to zero and trigger the appropriated remove handler. - void BeforeDispel(DispelInfo* dispelData) - { - // Prevent any stack from being removed at this point. - dispelData->SetRemovedCharges(0); - - if (Unit* dispelledUnit = GetUnitOwner()) - if (dispelledUnit->HasAura(_removeSpellId)) - dispelledUnit->RemoveAurasDueToSpell(_removeSpellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE); - } - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) - return; - - // Stacks marker - CastSpellExtraArgs args(GetCasterGUID()); - args.AddSpellMod(SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount()); - GetTarget()->CastSpell(GetTarget(), _summonSpellId, args); - } - - void Register() override - { - OnDispel += AuraDispelFn(spell_halion_marks_AuraScript::BeforeDispel); - AfterEffectRemove += AuraEffectRemoveFn(spell_halion_marks_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - - uint32 _summonSpellId; - uint32 _removeSpellId; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_halion_marks_AuraScript(_summonSpell, _removeSpell); - } - - private: - uint32 _summonSpell; - uint32 _removeSpell; + PrepareAuraScript(spell_halion_marks); + +public: + spell_halion_marks(uint32 summonSpell, uint32 removeSpell) : AuraScript(), + _summonSpellId(summonSpell), _removeSpellId(removeSpell) { } + +private: + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ _summonSpellId, _removeSpellId }); + } + + /// We were purged. Force removed stacks to zero and trigger the appropriated remove handler. + void BeforeDispel(DispelInfo* dispelData) + { + // Prevent any stack from being removed at this point. + dispelData->SetRemovedCharges(0); + + if (Unit* dispelledUnit = GetUnitOwner()) + if (dispelledUnit->HasAura(_removeSpellId)) + dispelledUnit->RemoveAurasDueToSpell(_removeSpellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE); + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + return; + + // Stacks marker + CastSpellExtraArgs args(GetCasterGUID()); + args.AddSpellMod(SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount()); + GetTarget()->CastSpell(GetTarget(), _summonSpellId, args); + } + + void Register() override + { + OnDispel += AuraDispelFn(spell_halion_marks::BeforeDispel); + AfterEffectRemove += AuraEffectRemoveFn(spell_halion_marks::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + + uint32 _summonSpellId; + uint32 _removeSpellId; }; // 74610 - Fiery Combustion // 74800 - Soul Consumption -class spell_halion_damage_aoe_summon : public SpellScriptLoader +class spell_halion_damage_aoe_summon : public SpellScript { - public: - spell_halion_damage_aoe_summon() : SpellScriptLoader("spell_halion_damage_aoe_summon") { } - - class spell_halion_damage_aoe_summon_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_damage_aoe_summon_SpellScript); - - void HandleSummon(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Unit* caster = GetCaster(); - uint32 entry = uint32(GetEffectInfo().MiscValue); - SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetEffectInfo().MiscValueB)); - uint32 duration = uint32(GetSpellInfo()->GetDuration()); - - Position pos = caster->GetPosition(); - if (Creature* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id)) - if (summon->IsAIEnabled()) - summon->AI()->SetData(DATA_STACKS_DISPELLED, GetSpellValue()->EffectBasePoints[EFFECT_1]); - } - - void Register() override - { - OnEffectHit += SpellEffectFn(spell_halion_damage_aoe_summon_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_halion_damage_aoe_summon_SpellScript(); - } + PrepareSpellScript(spell_halion_damage_aoe_summon); + + void HandleSummon(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Unit* caster = GetCaster(); + uint32 entry = uint32(GetEffectInfo().MiscValue); + SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetEffectInfo().MiscValueB)); + uint32 duration = uint32(GetSpellInfo()->GetDuration()); + + Position pos = caster->GetPosition(); + if (Creature* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id)) + if (summon->IsAIEnabled()) + summon->AI()->SetData(DATA_STACKS_DISPELLED, GetSpellValue()->EffectBasePoints[EFFECT_1]); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_halion_damage_aoe_summon::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); + } }; -class spell_halion_twilight_realm_handlers : public SpellScriptLoader +// 74812 - Leave Twilight Realm +// 74807 - Twilight Realm +class spell_halion_twilight_realm_handlers : public AuraScript { - public: - spell_halion_twilight_realm_handlers(char const* scriptName, uint32 beforeHitSpell, bool isApplyHandler) : SpellScriptLoader(scriptName), - _beforeHitSpell(beforeHitSpell), _isApplyHandler(isApplyHandler) - { } - - class spell_halion_twilight_realm_handlers_AuraScript : public AuraScript + PrepareAuraScript(spell_halion_twilight_realm_handlers); + +public: + spell_halion_twilight_realm_handlers(uint32 beforeHitSpell, bool isApplyHandler) : AuraScript(), + _isApply(isApplyHandler), _beforeHitSpellId(beforeHitSpell) + { } + +private: + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ _beforeHitSpellId }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_TWILIGHT_REALM); + if (InstanceScript* instance = GetTarget()->GetInstanceScript()) + instance->SendEncounterUnit(ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED); + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/) + { + Unit* target = GetTarget(); + if (!target) + return; + + target->RemoveAurasDueToSpell(_beforeHitSpellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_ENEMY_SPELL); + if (InstanceScript* instance = target->GetInstanceScript()) + instance->SendEncounterUnit(ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED); + } + + void Register() override + { + if (!_isApply) { - PrepareAuraScript(spell_halion_twilight_realm_handlers_AuraScript); - - public: - spell_halion_twilight_realm_handlers_AuraScript(uint32 beforeHitSpell, bool isApplyHandler) : AuraScript(), - _isApply(isApplyHandler), _beforeHitSpellId(beforeHitSpell) - { } - - private: - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ _beforeHitSpellId }); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/) - { - GetTarget()->RemoveAurasDueToSpell(SPELL_TWILIGHT_REALM); - if (InstanceScript* instance = GetTarget()->GetInstanceScript()) - instance->SendEncounterUnit(ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED); - } - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/) - { - Unit* target = GetTarget(); - if (!target) - return; - - target->RemoveAurasDueToSpell(_beforeHitSpellId, ObjectGuid::Empty, 0, AURA_REMOVE_BY_ENEMY_SPELL); - if (InstanceScript* instance = target->GetInstanceScript()) - instance->SendEncounterUnit(ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED); - } - - void Register() override - { - if (!_isApply) - { - AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_halion_twilight_realm_handlers_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - else - AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PHASE, AURA_EFFECT_HANDLE_REAL); - } - - bool _isApply; - uint32 _beforeHitSpellId; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_halion_twilight_realm_handlers_AuraScript(_beforeHitSpell, _isApplyHandler); + AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_halion_twilight_realm_handlers::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } + else + AfterEffectApply += AuraEffectApplyFn(spell_halion_twilight_realm_handlers::OnApply, EFFECT_0, SPELL_AURA_PHASE, AURA_EFFECT_HANDLE_REAL); + } - private: - uint32 _beforeHitSpell; - bool _isApplyHandler; + bool _isApply; + uint32 _beforeHitSpellId; }; // 75396 - Clear Debuffs -class spell_halion_clear_debuffs : public SpellScriptLoader +class spell_halion_clear_debuffs : public SpellScript { - public: - spell_halion_clear_debuffs() : SpellScriptLoader("spell_halion_clear_debuffs") { } - - class spell_halion_clear_debuffs_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_clear_debuffs_SpellScript); - - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_CLEAR_DEBUFFS, SPELL_TWILIGHT_REALM }); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (GetHitUnit()->HasAura(GetEffectInfo().CalcValue())) - GetHitUnit()->RemoveAurasDueToSpell(GetEffectInfo().CalcValue()); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_halion_clear_debuffs_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_halion_clear_debuffs_SpellScript(); - } + PrepareSpellScript(spell_halion_clear_debuffs); + + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_CLEAR_DEBUFFS, SPELL_TWILIGHT_REALM }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitUnit()->HasAura(GetEffectInfo().CalcValue())) + GetHitUnit()->RemoveAurasDueToSpell(GetEffectInfo().CalcValue()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_halion_clear_debuffs::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } }; class TwilightCutterSelector @@ -1745,203 +1551,148 @@ class TwilightCutterSelector }; // 74769, 77844, 77845, 77846 - Twilight Cutter -class spell_halion_twilight_cutter : public SpellScriptLoader +class spell_halion_twilight_cutter : public SpellScript { - public: - spell_halion_twilight_cutter() : SpellScriptLoader("spell_halion_twilight_cutter") { } + PrepareSpellScript(spell_halion_twilight_cutter); - class spell_halion_twilight_cutter_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_twilight_cutter_SpellScript); - - void RemoveNotBetween(std::list<WorldObject*>& unitList) - { - if (unitList.empty()) - return; - - Unit* caster = GetCaster(); - if (Unit* channelTarget = ObjectAccessor::GetUnit(*caster, caster->GetChannelObjectGuid())) - { - unitList.remove_if(TwilightCutterSelector(caster, channelTarget)); - return; - } - - // In case cutter caster werent found for some reason - unitList.clear(); - } + void RemoveNotBetween(std::list<WorldObject*>& unitList) + { + if (unitList.empty()) + return; - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_twilight_cutter_SpellScript::RemoveNotBetween, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override + Unit* caster = GetCaster(); + if (Unit* channelTarget = ObjectAccessor::GetUnit(*caster, caster->GetChannelObjectGuid())) { - return new spell_halion_twilight_cutter_SpellScript(); + unitList.remove_if(TwilightCutterSelector(caster, channelTarget)); + return; } + + // In case cutter caster werent found for some reason + unitList.clear(); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_twilight_cutter::RemoveNotBetween, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } }; // 74808 - Twilight Phasing -class spell_halion_twilight_phasing : public SpellScriptLoader +class spell_halion_twilight_phasing : public SpellScript { - public: - spell_halion_twilight_phasing() : SpellScriptLoader("spell_halion_twilight_phasing") { } - - class spell_halion_twilight_phasing_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_twilight_phasing_SpellScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SUMMON_TWILIGHT_PORTAL }); - } - - void Phase() - { - Unit* caster = GetCaster(); - caster->CastSpell(caster->GetPosition(), SPELL_SUMMON_TWILIGHT_PORTAL, true); - caster->GetMap()->SummonCreature(NPC_TWILIGHT_HALION, HalionSpawnPos); - } - - void Register() override - { - OnHit += SpellHitFn(spell_halion_twilight_phasing_SpellScript::Phase); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_halion_twilight_phasing_SpellScript(); - } + PrepareSpellScript(spell_halion_twilight_phasing); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SUMMON_TWILIGHT_PORTAL }); + } + + void Phase() + { + Unit* caster = GetCaster(); + caster->CastSpell(caster->GetPosition(), SPELL_SUMMON_TWILIGHT_PORTAL, true); + caster->GetMap()->SummonCreature(NPC_TWILIGHT_HALION, HalionSpawnPos); + } + + void Register() override + { + OnHit += SpellHitFn(spell_halion_twilight_phasing::Phase); + } }; // 74805 - Summon Exit Portals -class spell_halion_summon_exit_portals : public SpellScriptLoader +class spell_halion_summon_exit_portals : public SpellScript { - public: - spell_halion_summon_exit_portals() : SpellScriptLoader("spell_halion_summon_exit_portals") { } - - class spell_halion_summon_exit_portals_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_summon_exit_portals_SpellScript); - - void SetDest0(SpellDestination& dest) - { - Position const offset = { 0.0f, 20.0f, 0.0f, 0.0f }; - dest.RelocateOffset(offset); - } - - void SetDest1(SpellDestination& dest) - { - Position const offset = { 0.0f, -20.0f, 0.0f, 0.0f }; - dest.RelocateOffset(offset); - } - - void Register() override - { - OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_halion_summon_exit_portals_SpellScript::SetDest0, EFFECT_0, TARGET_DEST_CASTER); - OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_halion_summon_exit_portals_SpellScript::SetDest1, EFFECT_1, TARGET_DEST_CASTER); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_halion_summon_exit_portals_SpellScript(); - } + PrepareSpellScript(spell_halion_summon_exit_portals); + + void SetDest0(SpellDestination& dest) + { + Position const offset = { 0.0f, 20.0f, 0.0f, 0.0f }; + dest.RelocateOffset(offset); + } + + void SetDest1(SpellDestination& dest) + { + Position const offset = { 0.0f, -20.0f, 0.0f, 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_halion_summon_exit_portals::SetDest0, EFFECT_0, TARGET_DEST_CASTER); + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_halion_summon_exit_portals::SetDest1, EFFECT_1, TARGET_DEST_CASTER); + } }; // 75880 - Spawn Living Embers -class spell_halion_spawn_living_embers : public SpellScriptLoader +class spell_halion_spawn_living_embers : public SpellScript { - public: - spell_halion_spawn_living_embers() : SpellScriptLoader("spell_halion_spawn_living_embers") { } - - class spell_halion_spawn_living_embers_SpellScript : public SpellScript - { - PrepareSpellScript(spell_halion_spawn_living_embers_SpellScript); - - void SelectMeteorFlames(std::list<WorldObject*>& unitList) - { - if (!unitList.empty()) - Trinity::Containers::RandomResize(unitList, 10); - } - - void HandleScript(SpellEffIndex /* effIndex */) - { - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_LIVING_EMBER, true); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_spawn_living_embers_SpellScript::SelectMeteorFlames, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_halion_spawn_living_embers_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_halion_spawn_living_embers_SpellScript(); - } + PrepareSpellScript(spell_halion_spawn_living_embers); + + void SelectMeteorFlames(std::list<WorldObject*>& unitList) + { + if (!unitList.empty()) + Trinity::Containers::RandomResize(unitList, 10); + } + + void HandleScript(SpellEffIndex /* effIndex */) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_LIVING_EMBER, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_spawn_living_embers::SelectMeteorFlames, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_halion_spawn_living_embers::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } }; // 75886, 75887 - Blazing Aura -class spell_halion_blazing_aura : public SpellScriptLoader +class spell_halion_blazing_aura : public SpellScript { - 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(), GetEffectInfo().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(); - } + PrepareSpellScript(spell_halion_blazing_aura); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetHitUnit(), GetEffectInfo().TriggerSpell); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_halion_blazing_aura::HandleScript, EFFECT_1, SPELL_EFFECT_FORCE_CAST); + } }; void AddSC_boss_halion() { - new boss_halion(); - new boss_twilight_halion(); - - new npc_halion_controller(); - new npc_meteor_strike_flame(); - new npc_meteor_strike_initial(); - new npc_meteor_strike(); - new npc_combustion_consumption(); - new npc_orb_carrier(); - new npc_living_inferno(); - new npc_living_ember(); - - new go_twilight_portal(); - - new spell_halion_meteor_strike_marker(); - new spell_halion_combustion_consumption("spell_halion_soul_consumption", SPELL_MARK_OF_CONSUMPTION); - 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); - new spell_halion_summon_exit_portals(); - new spell_halion_twilight_phasing(); - new spell_halion_twilight_cutter(); - new spell_halion_clear_debuffs(); - new spell_halion_spawn_living_embers(); - new spell_halion_blazing_aura(); + RegisterRubySanctumCreatureAI(boss_halion); + RegisterRubySanctumCreatureAI(boss_twilight_halion); + + RegisterRubySanctumCreatureAI(npc_halion_controller); + RegisterRubySanctumCreatureAI(npc_meteor_strike_flame); + RegisterRubySanctumCreatureAI(npc_meteor_strike_initial); + RegisterRubySanctumCreatureAI(npc_meteor_strike); + RegisterRubySanctumCreatureAI(npc_combustion_consumption); + RegisterRubySanctumCreatureAI(npc_orb_carrier); + RegisterRubySanctumCreatureAI(npc_living_inferno); + RegisterRubySanctumCreatureAI(npc_living_ember); + + RegisterRubySanctumGameObjectAI(go_twilight_portal); + + RegisterSpellScript(spell_halion_meteor_strike_marker); + RegisterSpellScriptWithArgs(spell_halion_combustion_consumption, "spell_halion_soul_consumption", SPELL_MARK_OF_CONSUMPTION); + RegisterSpellScriptWithArgs(spell_halion_combustion_consumption, "spell_halion_fiery_combustion", SPELL_MARK_OF_COMBUSTION); + RegisterSpellScriptWithArgs(spell_halion_marks, "spell_halion_mark_of_combustion", SPELL_FIERY_COMBUSTION_SUMMON, SPELL_FIERY_COMBUSTION); + RegisterSpellScriptWithArgs(spell_halion_marks, "spell_halion_mark_of_consumption", SPELL_SOUL_CONSUMPTION_SUMMON, SPELL_SOUL_CONSUMPTION); + RegisterSpellScript(spell_halion_combustion_consumption_periodic); + RegisterSpellScript(spell_halion_damage_aoe_summon); + RegisterSpellScriptWithArgs(spell_halion_twilight_realm_handlers, "spell_halion_leave_twilight_realm", SPELL_SOUL_CONSUMPTION, false); + RegisterSpellScriptWithArgs(spell_halion_twilight_realm_handlers, "spell_halion_enter_twilight_realm", SPELL_FIERY_COMBUSTION, true); + RegisterSpellScript(spell_halion_summon_exit_portals); + RegisterSpellScript(spell_halion_twilight_phasing); + RegisterSpellScript(spell_halion_twilight_cutter); + RegisterSpellScript(spell_halion_clear_debuffs); + RegisterSpellScript(spell_halion_spawn_living_embers); + RegisterSpellScript(spell_halion_blazing_aura); } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h index 7c243617e03..7f6b48d2e2f 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h @@ -136,5 +136,6 @@ inline AI* GetRubySanctumAI(T* obj) } #define RegisterRubySanctumCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetRubySanctumAI) +#define RegisterRubySanctumGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetRubySanctumAI) #endif // RUBY_SANCTUM_H_ |
