aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp14
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h20
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp2
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp76
-rw-r--r--src/server/scripts/Northrend/CMakeLists.txt1
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp4
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp1738
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp138
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h53
9 files changed, 1947 insertions, 99 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index c41436e1947..0ebb0c54a24 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -9113,6 +9113,9 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
case 4100: // The Culling of Stratholme
NumberOfFields = 13;
break;
+ case 4987: // The Ruby Sanctum
+ NumberOfFields = 3;
+ break;
case 4273: // Ulduar
NumberOfFields = 10;
break;
@@ -9639,6 +9642,17 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
data << uint32(4345) << uint32(1); // 24 unknown
}
break;
+ // The Ruby Sanctum
+ case 4987:
+ if (instance && mapid == 724)
+ instance->FillInitialWorldStates(data);
+ else
+ {
+ data << uint32(5049) << uint32(50); // 9 WORLDSTATE_CORPOREALITY_MATERIAL
+ data << uint32(5050) << uint32(50); // 10 WORLDSTATE_CORPOREALITY_TWILIGHT
+ data << uint32(5051) << uint32(0); // 11 WORLDSTATE_CORPOREALITY_TOGGLE
+ }
+ break;
// Icecrown Citadel
case 4812:
if (instance && mapid == 631)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 7f279a8b97e..d3a87a1c44e 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -794,21 +794,21 @@ enum MeleeHitOutcome
class DispelInfo
{
-private:
- Unit* const m_dispeller;
- uint32 const m_dispellerSpellId;
- uint8 m_chargesRemoved;
public:
- explicit DispelInfo(Unit* _dispeller, uint32 _dispellerSpellId, uint8 _chargesRemoved) :
- m_dispeller(_dispeller), m_dispellerSpellId(_dispellerSpellId), m_chargesRemoved(_chargesRemoved) {}
+ explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
+ _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) {}
- Unit* GetDispeller() { return m_dispeller; }
- uint32 GetDispellerSpellId() const { return m_dispellerSpellId; }
- uint8 GetRemovedCharges() const { return m_chargesRemoved; }
+ Unit* GetDispeller() const { return _dispellerUnit; }
+ uint32 GetDispellerSpellId() const { return _dispellerSpell; }
+ uint8 GetRemovedCharges() const { return _chargesRemoved; }
void SetRemovedCharges(uint8 amount)
{
- m_chargesRemoved = amount;
+ _chargesRemoved = amount;
}
+private:
+ Unit* _dispellerUnit;
+ uint32 _dispellerSpell;
+ uint8 _chargesRemoved;
};
struct CleanDamage
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index fc56106ab6f..54a74a021c1 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -502,6 +502,7 @@ void AddSC_ruby_sanctum();
void AddSC_boss_baltharus_the_warborn();
void AddSC_boss_saviana_ragefire();
void AddSC_boss_general_zarithrian();
+void AddSC_boss_halion();
void AddSC_dalaran();
void AddSC_borean_tundra();
@@ -1222,6 +1223,7 @@ void AddNorthrendScripts()
AddSC_boss_baltharus_the_warborn();
AddSC_boss_saviana_ragefire();
AddSC_boss_general_zarithrian();
+ AddSC_boss_halion();
AddSC_dalaran();
AddSC_borean_tundra();
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index c89442855e1..edce89a1a5b 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3402,7 +3402,7 @@ void SpellMgr::LoadDbcDataCorrections()
break;
case 69055: // Saber Lash (Lord Marrowgar)
case 70814: // Saber Lash (Lord Marrowgar)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd
break;
case 69075: // Bone Storm (Lord Marrowgar)
case 70834: // Bone Storm (Lord Marrowgar)
@@ -3412,7 +3412,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 71160: // Plague Stench (Stinky)
case 71161: // Plague Stench (Stinky)
case 71123: // Decimate (Stinky & Precious)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
break;
case 72378: // Blood Nova (Deathbringer Saurfang)
case 73058: // Blood Nova (Deathbringer Saurfang)
@@ -3430,7 +3430,7 @@ void SpellMgr::LoadDbcDataCorrections()
spellInfo->Effect[2] = 0;
break;
case 70460: // Coldflame Jets (Traps after Saurfang)
- spellInfo->DurationIndex = 1; // 10 seconds
+ spellInfo->DurationIndex = 1; // 10 seconds
break;
case 71412: // Green Ooze Summon (Professor Putricide)
case 71415: // Orange Ooze Summon (Professor Putricide)
@@ -3453,7 +3453,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 72464: // Mutated Plague (Professor Putricide)
case 72506: // Mutated Plague (Professor Putricide)
case 72507: // Mutated Plague (Professor Putricide)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 70911: // Unbound Plague (Professor Putricide) (needs target selection script)
case 72854: // Unbound Plague (Professor Putricide) (needs target selection script)
@@ -3464,7 +3464,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
@@ -3513,62 +3513,62 @@ void SpellMgr::LoadDbcDataCorrections()
case 73708: // Defile
case 73709: // Defile
case 73710: // Defile
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 69030: // Val'kyr Target Search
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 69198: // Raging Spirit Visual
- spellInfo->rangeIndex = 13; // 50000yd
+ spellInfo->rangeIndex = 13; // 50000yd
break;
case 73654: // Harvest Souls
case 74295: // Harvest Souls
case 74296: // Harvest Souls
case 74297: // Harvest Souls
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 73655: // Harvest Soul
spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
break;
case 73540: // Summon Shadow Trap
- spellInfo->DurationIndex = 23; // 90 seconds
+ spellInfo->DurationIndex = 23; // 90 seconds
break;
case 73530: // Shadow Trap (visual)
- spellInfo->DurationIndex = 28; // 5 seconds
+ spellInfo->DurationIndex = 28; // 5 seconds
break;
case 73529: // Shadow Trap
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd
break;
case 74282: // Shadow Trap (searcher)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd
break;
case 72595: // Restore Soul
case 73650: // Restore Soul
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 74086: // Destroy Soul
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
break;
case 74302: // Summon Spirit Bomb
case 74342: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->MaxAffectedTargets = 1;
break;
case 74341: // Summon Spirit Bomb
case 74343: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd
spellInfo->MaxAffectedTargets = 3;
break;
case 73579: // Summon Spirit Bomb
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
break;
case 72350: // Fury of Frostmourne
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 75127: // Kill Frostmourne Players
case 72351: // Fury of Frostmourne
@@ -3576,19 +3576,35 @@ void SpellMgr::LoadDbcDataCorrections()
case 72429: // Mass Resurrection
case 73159: // Play Movie
case 73582: // Trigger Vile Spirit (Inside, Heroic)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 72376: // Raise Dead
spellInfo->MaxAffectedTargets = 3;
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd
break;
case 71809: // Jump
- spellInfo->rangeIndex = 3; // 20yd
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
+ spellInfo->rangeIndex = 3; // 20yd
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd
break;
case 72405: // Broken Frostmourne
- spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd
+ break;
+ // ENDOF ICECROWN CITADEL SPELLS
+ //
+ // RUBY SANCTUM SPELLS
+ //
+ case 74769: // Twilight Cutter
+ case 77844: // Twilight Cutter
+ case 77845: // Twilight Cutter
+ case 77846: // Twilight Cutter
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd
break;
+ case 75509: // Twilight Mending
+ spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
+ spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
+ break;
+ // ENDOF RUBY SANCTUM SPELLS
+ //
case 40055: // Introspection
case 40165: // Introspection
case 40166: // Introspection
@@ -3630,5 +3646,5 @@ void SpellMgr::LoadDbcDataCorrections()
properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647)); // 52893
properties->Type = SUMMON_TYPE_TOTEM;
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loading spell dbc data corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded spell dbc data corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt
index dd8dd17c947..22d0f37a37f 100644
--- a/src/server/scripts/Northrend/CMakeLists.txt
+++ b/src/server/scripts/Northrend/CMakeLists.txt
@@ -51,6 +51,7 @@ set(scripts_STAT_SRCS
Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp
Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp
Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
+ Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h
Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp
Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
index 41eb31d815d..531e5d9268e 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp
@@ -158,9 +158,9 @@ class boss_general_zarithrian : public CreatureScript
{
case EVENT_SUMMON_ADDS:
{
- if (Creature* stalker1 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHIAN_SPAWN_STALKER_1)))
+ if (Creature* stalker1 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_1)))
stalker1->AI()->DoCast(stalker1, SPELL_SUMMON_FLAMECALLER);
- if (Creature* stalker2 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHIAN_SPAWN_STALKER_2)))
+ if (Creature* stalker2 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_2)))
stalker2->AI()->DoCast(stalker2, SPELL_SUMMON_FLAMECALLER);
Talk(SAY_ADDS);
events.ScheduleEvent(EVENT_SUMMON_ADDS, 42000);
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
new file mode 100644
index 00000000000..c6c57a34922
--- /dev/null
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -0,0 +1,1738 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
+#include "Spell.h"
+#include "Vehicle.h"
+#include "MapManager.h"
+#include "GameObjectAI.h"
+#include "ruby_sanctum.h"
+
+/* ScriptData
+SDName: ruby_sanctum
+SDAuthors: Kaelima, Warpten
+SD%Complete: 90%
+SDComment: Based on Kaelima's initial work (nearly half of it). Corporeality handling is a pure guess, we lack info.
+SDCategory: Chamber of Aspects
+EndScriptData */
+
+enum Texts
+{
+ // Shared
+ SAY_REGENERATE = 0, // Without pressure in both realms, %s begins to regenerate.
+
+ // Halion
+ SAY_INTRO = 1, // Meddlesome insects! You are too late. The Ruby Sanctum is lost!
+ SAY_AGGRO = 2, // Your world teeters on the brink of annihilation. You will ALL bear witness to the coming of a new age of DESTRUCTION!
+ SAY_METEOR_STRIKE = 3, // The heavens burn!
+ SAY_PHASE_TWO = 4, // You will find only suffering within the realm of twilight! Enter if you dare!
+ SAY_DEATH = 5, // Relish this victory, mortals, for it will be your last! This world will burn with the master's return!
+ SAY_KILL = 6, // Another "hero" falls.
+ SAY_BERSERK = 7, // Not good enough.
+ EMOTE_CORPOREALITY_POT = 8, // Your efforts force %s further out of the physical realm!
+ EMOTE_CORPOREALITY_PIP = 9, // Your companions' efforts force %s further into the physical realm!
+
+ // Twilight Halion
+ SAY_SPHERE_PULSE = 1, // Beware the shadow!
+ SAY_PHASE_THREE = 2, // I am the light and the darkness! Cower, mortals, before the herald of Deathwing!
+ EMOTE_CORPOREALITY_TIT = 3, // Your companions' efforts force %s further into the twilight realm!
+ EMOTE_CORPOREALITY_TOT = 4, // Your efforts force %s further out of the twilight realm!
+
+ EMOTE_WARN_LASER = 0, // The orbiting spheres pulse with dark energy!
+};
+
+enum Spells
+{
+ // Halion
+ SPELL_FLAME_BREATH = 74525,
+ SPELL_CLEAVE = 74524,
+ SPELL_METEOR_STRIKE = 74637,
+ SPELL_TAIL_LASH = 74531,
+
+ SPELL_FIERY_COMBUSTION = 74562,
+ SPELL_MARK_OF_COMBUSTION = 74567,
+ SPELL_FIERY_COMBUSTION_EXPLOSION = 74607,
+ SPELL_FIERY_COMBUSTION_SUMMON = 74610,
+
+ // Combustion & Consumption
+ SPELL_SCALE_AURA = 70507, // Aura created in spell_dbc.
+ SPELL_COMBUSTION_DAMAGE_AURA = 74629,
+ SPELL_CONSUMPTION_DAMAGE_AURA = 74803,
+
+ // Twilight Halion
+ SPELL_DARK_BREATH = 74806,
+
+ SPELL_MARK_OF_CONSUMPTION = 74795,
+ SPELL_SOUL_CONSUMPTION = 74792,
+ SPELL_SOUL_CONSUMPTION_EXPLOSION = 74799,
+ SPELL_SOUL_CONSUMPTION_SUMMON = 74800,
+
+ // Living Inferno
+ SPELL_BLAZING_AURA = 75885,
+
+ // Halion Controller
+ SPELL_COSMETIC_FIRE_PILLAR = 76006,
+ SPELL_FIERY_EXPLOSION = 76010,
+ SPELL_CLEAR_DEBUFFS = 75396,
+
+ // Meteor Strike
+ SPELL_METEOR_STRIKE_COUNTDOWN = 74641,
+ SPELL_METEOR_STRIKE_AOE_DAMAGE = 74648,
+ SPELL_METEOR_STRIKE_FIRE_AURA_1 = 74713,
+ SPELL_METEOR_STRIKE_FIRE_AURA_2 = 74718,
+ SPELL_BIRTH_NO_VISUAL = 40031,
+
+ // Shadow Orb
+ SPELL_TWILIGHT_CUTTER = 74768, // Unknown dummy effect (EFFECT_0)
+ SPELL_TWILIGHT_CUTTER_TRIGGERED = 74769,
+ SPELL_TWILIGHT_PULSE_PERIODIC = 78861,
+ SPELL_TRACK_ROTATION = 74758,
+
+ // Misc
+ SPELL_TWILIGHT_DIVISION = 75063, // Phase spell from phase 2 to phase 3
+ SPELL_LEAVE_TWILIGHT_REALM = 74812,
+ SPELL_TWILIGHT_PHASING = 74808, // Phase spell from phase 1 to phase 2
+ SPELL_SUMMON_TWILIGHT_PORTAL = 74809, // Summons go 202794
+ SPELL_SUMMON_EXIT_PORTALS = 74805, // Custom spell created in spell_dbc.
+ SPELL_TWILIGHT_MENDING = 75509,
+ SPELL_TWILIGHT_REALM = 74807,
+ SPELL_COPY_DAMAGE = 74810 // Aura not found in DBCs.
+};
+
+enum Events
+{
+ // Halion
+ EVENT_ACTIVATE_FIREWALL = 1,
+ EVENT_CLEAVE = 2,
+ EVENT_FLAME_BREATH = 3,
+ EVENT_METEOR_STRIKE = 4,
+ EVENT_FIERY_COMBUSTION = 5,
+ EVENT_TAIL_LASH = 6,
+
+ // Twilight Halion
+ EVENT_DARK_BREATH = 7,
+ EVENT_SOUL_CONSUMPTION = 8,
+
+ // Meteor Strike
+ EVENT_SPAWN_METEOR_FLAME = 9,
+
+ // Halion Controller
+ EVENT_START_INTRO = 10,
+ EVENT_INTRO_PROGRESS_1 = 11,
+ EVENT_INTRO_PROGRESS_2 = 12,
+ EVENT_INTRO_PROGRESS_3 = 13,
+ EVENT_CHECK_CORPOREALITY = 14,
+ EVENT_SHADOW_PULSARS_SHOOT = 15,
+ EVENT_TRIGGER_BERSERK = 16,
+ EVENT_TWILIGHT_MENDING = 17
+};
+
+enum Actions
+{
+ // Meteor Strike
+ ACTION_METEOR_STRIKE_BURN = 1,
+ ACTION_METEOR_STRIKE_AOE = 2,
+
+ // Halion Controller
+ ACTION_PHASE_TWO = 3,
+ ACTION_PHASE_THREE = 4,
+ ACTION_CLEANUP = 5,
+
+ // Orb Carrier
+ ACTION_SHOOT = 6
+};
+
+enum Phases
+{
+ PHASE_ALL = 0,
+ PHASE_INTRO = 1,
+ PHASE_ONE = 2,
+ PHASE_TWO = 3,
+ PHASE_THREE = 4,
+
+ PHASE_INTRO_MASK = 1 << PHASE_INTRO,
+ PHASE_ONE_MASK = 1 << PHASE_ONE,
+ PHASE_TWO_MASK = 1 << PHASE_TWO,
+ PHASE_THREE_MASK = 1 << PHASE_THREE
+};
+
+enum Misc
+{
+ DATA_TWILIGHT_DAMAGE_TAKEN = 1,
+ DATA_MATERIAL_DAMAGE_TAKEN = 2,
+ DATA_STACKS_DISPELLED = 3,
+ DATA_FIGHT_PHASE = 4,
+ DATA_EVADE_METHOD = 5
+};
+
+enum OrbCarrierSeats
+{
+ SEAT_NORTH = 0,
+ SEAT_SOUTH = 1,
+ SEAT_EAST = 2,
+ SEAT_WEST = 3
+};
+
+enum CorporealityEvent
+{
+ CORPOREALITY_NONE = 0,
+ CORPOREALITY_TWILIGHT_MENDING = 1,
+ CORPOREALITY_INCREASE = 2,
+ CORPOREALITY_DECREASE = 3
+};
+
+Position const HalionSpawnPos = {3156.67f, 533.8108f, 72.98822f, 3.159046f};
+
+uint8 const MAX_CORPOREALITY_STATE = 11;
+
+struct CorporealityEntry
+{
+ uint32 materialRealmSpell;
+ uint32 twilightRealmSpell;
+};
+
+CorporealityEntry const _corporealityReference[MAX_CORPOREALITY_STATE] = {
+ {74836, 74831},
+ {74835, 74830},
+ {74834, 74829},
+ {74833, 74828},
+ {74832, 74827},
+ {74826, 74826},
+ {74827, 74832},
+ {74828, 74833},
+ {74829, 74834},
+ {74830, 74835},
+ {74831, 74836}
+};
+
+struct generic_halionAI : public BossAI
+{
+ generic_halionAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _canEvade(false) { }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ _canEvade = false;
+ events.Reset();
+ events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
+ }
+
+ void EnterEvadeMode()
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ _EnterEvadeMode();
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000));
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ ExecuteEvent(eventId);
+
+ DoMeleeAttackIfReady();
+ }
+
+ void SetData(uint32 index, uint32 dataValue)
+ {
+ switch (index)
+ {
+ case DATA_EVADE_METHOD:
+ _canEvade = (dataValue == 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void SpellHit(Unit* /*who*/, SpellInfo const* spellInfo)
+ {
+ if (spellInfo->Id == SPELL_TWILIGHT_MENDING)
+ Talk(SAY_REGENERATE);
+ }
+
+protected:
+ bool _canEvade;
+};
+
+class boss_halion : public CreatureScript
+{
+ public:
+ boss_halion() : CreatureScript("boss_halion") { }
+
+ struct boss_halionAI : public generic_halionAI
+ {
+ boss_halionAI(Creature* creature) : generic_halionAI(creature, DATA_HALION) { }
+
+ void Reset()
+ {
+ generic_halionAI::Reset();
+ me->SetReactState(REACT_DEFENSIVE);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ me->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ void EnterEvadeMode()
+ {
+ // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to.
+ // Controller has absolute priority over the phasemask.
+ if ((events.GetPhaseMask() & PHASE_ONE_MASK) || _canEvade)
+ generic_halionAI::EnterEvadeMode();
+ }
+
+ void EnterCombat(Unit* who)
+ {
+ generic_halionAI::EnterCombat(who);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ instance->SetBossState(DATA_HALION, IN_PROGRESS);
+
+ events.SetPhase(PHASE_ONE);
+ events.ScheduleEvent(EVENT_ACTIVATE_FIREWALL, 10000);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 12000));
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, urand(20000, 25000));
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, urand(15000, 18000));
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE);
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _JustDied();
+
+ Talk(SAY_DEATH);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ me->Kill(controller);
+ }
+
+ Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; }
+
+ void DamageTaken(Unit* attacker, uint32& damage)
+ {
+ if (me->HealthBelowPctDamaged(75, damage) && (events.GetPhaseMask() & PHASE_ONE_MASK))
+ {
+ events.SetPhase(PHASE_TWO);
+ Talk(SAY_PHASE_TWO);
+
+ me->CastStop();
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ DoCast(me, SPELL_TWILIGHT_PHASING);
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_TWO);
+ return;
+ }
+
+ if (events.GetPhaseMask() & PHASE_THREE_MASK)
+ {
+ // Don't consider copied damage.
+ if (!me->InSamePhase(attacker))
+ return;
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_MATERIAL_DAMAGE_TAKEN, damage);
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (events.GetPhaseMask() & PHASE_TWO_MASK)
+ return;
+
+ generic_halionAI::UpdateAI(diff);
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_ACTIVATE_FIREWALL:
+ {
+ // Flame ring is activated 10 seconds after starting encounter, DOOR_TYPE_ROOM is only instant.
+ for (uint8 i = DATA_FLAME_RING; i <= DATA_TWILIGHT_FLAME_RING; ++i)
+ if (GameObject* flameRing = ObjectAccessor::GetGameObject(*me, instance->GetData64(i)))
+ instance->HandleGameObject(instance->GetData64(DATA_FLAME_RING), false, flameRing);
+ break;
+ }
+ case EVENT_FLAME_BREATH:
+ DoCast(me, SPELL_FLAME_BREATH);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, 25000);
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ break;
+ case EVENT_METEOR_STRIKE:
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ {
+ target->GetPosition(&_meteorStrikePos);
+ me->CastSpell(_meteorStrikePos.GetPositionX(), _meteorStrikePos.GetPositionY(), _meteorStrikePos.GetPositionZ(), SPELL_METEOR_STRIKE, true, NULL, NULL, me->GetGUID());
+ Talk(SAY_METEOR_STRIKE);
+ }
+ events.ScheduleEvent(EVENT_METEOR_STRIKE, 40000);
+ break;
+ }
+ case EVENT_FIERY_COMBUSTION:
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_TWILIGHT_REALM))
+ DoCast(target, SPELL_FIERY_COMBUSTION);
+ events.ScheduleEvent(EVENT_FIERY_COMBUSTION, 25000);
+ break;
+ }
+ default:
+ generic_halionAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+
+ void SetData(uint32 index, uint32 value)
+ {
+ switch (index)
+ {
+ case DATA_FIGHT_PHASE:
+ events.SetPhase(value);
+ break;
+ default:
+ generic_halionAI::SetData(index, value);
+ }
+ }
+
+ private:
+ Position _meteorStrikePos;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<boss_halionAI>(creature);
+ }
+};
+
+typedef boss_halion::boss_halionAI HalionAI;
+
+class boss_twilight_halion : public CreatureScript
+{
+ public:
+ boss_twilight_halion() : CreatureScript("boss_twilight_halion") { }
+
+ struct boss_twilight_halionAI : public generic_halionAI
+ {
+ boss_twilight_halionAI(Creature* creature) : generic_halionAI(creature, DATA_TWILIGHT_HALION)
+ {
+ Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION));
+ if (!halion)
+ return;
+
+ // We use explicit targeting here to avoid conditions + SPELL_ATTR6_CANT_TARGET_SELF.
+ // Using AddAura because no spell cast packet in sniffs.
+ halion->AddAura(SPELL_COPY_DAMAGE, me);
+ me->AddAura(SPELL_COPY_DAMAGE, halion);
+
+ me->SetHealth(halion->GetHealth());
+ me->SetPhaseMask(0x20, true);
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2);
+
+ events.Reset();
+ events.SetPhase(PHASE_TWO);
+ events.ScheduleEvent(EVENT_DARK_BREATH, urand(10000, 15000));
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ }
+
+ void EnterEvadeMode()
+ {
+ // We don't care about evading, we will be despawned.
+ }
+
+ void KilledUnit(Unit* victim)
+ {
+ 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)
+ {
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION)))
+ {
+ // Ensure looting
+ if (me->IsDamageEnoughForLootingAndReward())
+ halion->LowerPlayerDamageReq(halion->GetMaxHealth());
+
+ if (halion->isAlive())
+ killer->Kill(halion);
+ }
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->Kill(controller);
+
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage)
+ {
+ if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_TWO_MASK))
+ {
+ events.SetPhase(PHASE_THREE);
+ me->CastStop();
+ DoCast(me, SPELL_TWILIGHT_DIVISION);
+ Talk(SAY_PHASE_THREE);
+ return;
+ }
+
+ if (events.GetPhaseMask() & PHASE_THREE_MASK)
+ {
+ // Don't consider copied damage.
+ if (!me->InSamePhase(attacker))
+ return;
+
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_TWILIGHT_DAMAGE_TAKEN, damage);
+ }
+ }
+
+ void SpellHit(Unit* who, SpellInfo const* spell)
+ {
+ switch (spell->Id)
+ {
+ case SPELL_TWILIGHT_DIVISION:
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE);
+ break;
+ default:
+ generic_halionAI::SpellHit(who, spell);
+ break;
+ }
+ }
+
+ void ExecuteEvent(uint32 const eventId)
+ {
+ switch (eventId)
+ {
+ case EVENT_DARK_BREATH:
+ DoCast(me, SPELL_DARK_BREATH);
+ events.ScheduleEvent(EVENT_DARK_BREATH, urand(10000, 15000));
+ break;
+ case EVENT_SOUL_CONSUMPTION:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, SPELL_TWILIGHT_REALM))
+ DoCast(target, SPELL_SOUL_CONSUMPTION);
+ events.ScheduleEvent(EVENT_SOUL_CONSUMPTION, 20000);
+ break;
+ case EVENT_TAIL_LASH:
+ DoCastAOE(SPELL_TAIL_LASH);
+ events.ScheduleEvent(EVENT_TAIL_LASH, 10000);
+ break;
+ default:
+ generic_halionAI::ExecuteEvent(eventId);
+ break;
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<boss_twilight_halionAI>(creature);
+ }
+};
+
+class npc_halion_controller : public CreatureScript
+{
+ public:
+ npc_halion_controller() : CreatureScript("npc_halion_controller") { }
+
+ struct npc_halion_controllerAI : public ScriptedAI
+ {
+ npc_halion_controllerAI(Creature* creature) : ScriptedAI(creature),
+ _instance(creature->GetInstanceScript()), _summons(me)
+ {
+ me->SetPhaseMask(me->GetPhaseMask() | 0x20, true);
+ _events.SetPhase(PHASE_INTRO);
+ }
+
+ void Reset()
+ {
+ _summons.DespawnAll();
+ _events.Reset();
+ _materialCorporealityValue = 5;
+
+ DoCast(me, SPELL_CLEAR_DEBUFFS);
+ }
+
+ void JustSummoned(Creature* who)
+ {
+ _summons.Summon(who);
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ _events.Reset();
+ _summons.DespawnAll();
+
+ DoCast(me, SPELL_CLEAR_DEBUFFS);
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ _twilightDamageTaken = 0;
+ _materialDamageTaken = 0;
+
+ _events.ScheduleEvent(EVENT_TRIGGER_BERSERK, 8 * MINUTE * IN_MILLISECONDS);
+ }
+
+ void JustReachedHome()
+ {
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->DespawnOrUnsummon();
+
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION)))
+ {
+ halion->AI()->SetData(DATA_EVADE_METHOD, 1);
+ halion->AI()->EnterEvadeMode();
+ }
+
+ _instance->SetBossState(DATA_HALION, FAIL);
+ }
+
+ void DoAction(int32 const action)
+ {
+ switch (action)
+ {
+ case ACTION_INTRO_HALION:
+ _events.Reset();
+ _events.SetPhase(PHASE_INTRO);
+ _events.ScheduleEvent(EVENT_START_INTRO, 2000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ // The isInCombat() 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 (!(_events.GetPhaseMask() & PHASE_INTRO_MASK) && me->isInCombat() && !UpdateVictim())
+ {
+ EnterEvadeMode();
+ return;
+ }
+
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_START_INTRO:
+ DoCast(me, SPELL_COSMETIC_FIRE_PILLAR, true);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_1, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_1:
+ for (uint8 i = DATA_BURNING_TREE_3; i <= DATA_BURNING_TREE_4; ++i)
+ if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetData64(i)))
+ _instance->HandleGameObject(_instance->GetData64(i), true, tree);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_2, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_2:
+ for (uint8 i = DATA_BURNING_TREE_1; i <= DATA_BURNING_TREE_2; ++i)
+ if (GameObject* tree = ObjectAccessor::GetGameObject(*me, _instance->GetData64(i)))
+ _instance->HandleGameObject(_instance->GetData64(i), true, tree);
+ _events.ScheduleEvent(EVENT_INTRO_PROGRESS_3, 4000);
+ break;
+ case EVENT_INTRO_PROGRESS_3:
+ DoCast(me, SPELL_FIERY_EXPLOSION);
+ if (Creature* halion = me->GetMap()->SummonCreature(NPC_HALION, HalionSpawnPos))
+ halion->AI()->Talk(SAY_INTRO);
+ break;
+ case EVENT_TWILIGHT_MENDING:
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION)))
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->CastSpell((Unit*)NULL, SPELL_TWILIGHT_MENDING, true);
+ break;
+ case EVENT_TRIGGER_BERSERK:
+ for (uint8 i = DATA_HALION; i <= DATA_TWILIGHT_HALION; i++)
+ if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(i)))
+ halion->CastSpell(halion, SPELL_BERSERK, true);
+ break;
+ case EVENT_SHADOW_PULSARS_SHOOT:
+ if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TWILIGHT_HALION)))
+ twilightHalion->AI()->Talk(SAY_SPHERE_PULSE);
+
+ if (Creature* orbCarrier = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_ORB_CARRIER)))
+ orbCarrier->AI()->DoAction(ACTION_SHOOT);
+
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ break;
+ case EVENT_CHECK_CORPOREALITY:
+ UpdateCorporeality();
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void SetData(uint32 id, uint32 value)
+ {
+ 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:
+ // Timer taken from a 4.3.4 solo video and confirmed by TankSpot's 3.3.5 guide. http://www.tankspot.com/showthread.php?67195-Halion-Encounter-Guide-Live
+ _events.ScheduleEvent(EVENT_SHADOW_PULSARS_SHOOT, 29000);
+ break;
+ case PHASE_THREE:
+ _events.ScheduleEvent(EVENT_CHECK_CORPOREALITY, 5000);
+ // Load up corporeality data.
+ for (uint8 itr = DATA_HALION; itr <= DATA_TWILIGHT_HALION; itr++)
+ {
+ Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr));
+ if (!halion)
+ continue;
+
+ halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), false);
+ halion->AI()->SetData(DATA_FIGHT_PHASE, PHASE_THREE);
+
+ if (itr == DATA_TWILIGHT_HALION)
+ continue;
+
+ halion->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING);
+ halion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ // Summon Twilight portals
+ DoCast(me, 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);
+ 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, 100);
+ _twilightDamageTaken = 0;
+ _materialDamageTaken = 0;
+ return;
+ }
+
+ 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.0f) // ]0.99, 1.01[: Twilight Mending
+ action = CORPOREALITY_TWILIGHT_MENDING;
+ else if (1.02f < damageRatio) // ]1.02, +oo [: Corporeality goes up
+ action = CORPOREALITY_INCREASE;
+
+ switch (action)
+ {
+ case CORPOREALITY_NONE:
+ 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, 100);
+ _materialDamageTaken = 0;
+ _twilightDamageTaken = 0;
+ return;
+ }
+ default:
+ break;
+ }
+
+ _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 = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr)))
+ {
+ RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION);
+ 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->GetGUID());
+ else // if (itr == DATA_HALION)
+ halion->AI()->Talk(oldValue > _materialCorporealityValue ? EMOTE_CORPOREALITY_POT : EMOTE_CORPOREALITY_PIP, halion->GetGUID());
+ }
+ }
+ }
+
+ void RemoveCorporeality(Creature* who, bool isTwilight = false)
+ {
+ for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++)
+ {
+ uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell);
+ if (who->HasAura(spellID))
+ {
+ who->RemoveAurasDueToSpell(spellID);
+ break;
+ }
+ }
+ }
+
+ uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const
+ {
+ CorporealityEntry entry = _corporealityReference[pctValue];
+ return isTwilight ? entry.twilightRealmSpell : entry.materialRealmSpell;
+ }
+
+ EventMap _events;
+ InstanceScript* _instance;
+ SummonList _summons;
+
+ bool _corporealityCheck;
+
+ uint32 _twilightDamageTaken;
+ uint32 _materialDamageTaken;
+ uint8 _materialCorporealityValue;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_halion_controllerAI>(creature);
+ }
+};
+
+typedef npc_halion_controller::npc_halion_controllerAI controllerAI;
+
+class npc_orb_carrier : public CreatureScript
+{
+ public:
+ npc_orb_carrier() : CreatureScript("npc_orb_carrier") { }
+
+ struct npc_orb_carrierAI : public ScriptedAI
+ {
+ npc_orb_carrierAI(Creature* creature) : ScriptedAI(creature),
+ instance(creature->GetInstanceScript())
+ {
+ ASSERT(creature->GetVehicleKit());
+ }
+
+ void UpdateAI(uint32 const /*diff*/)
+ {
+ /// According to sniffs this spell is cast every 1 or 2 seconds.
+ /// However, refreshing it looks bad, so just cast the spell if
+ /// we are not channeling it.
+ if (!me->HasUnitState(UNIT_STATE_CASTING))
+ me->CastSpell((Unit*)NULL, SPELL_TRACK_ROTATION, false);
+
+ /// Workaround: This is here because even though the above spell has SPELL_ATTR1_CHANNEL_TRACK_TARGET,
+ /// we are having two creatures involded here. This attribute is handled clientside, meaning the client
+ /// sends orientation update itself. Here, no packet is sent, and the creature does not rotate. By
+ /// forcing the carrier to always be facing the rotation focus, we ensure everything works as it should.
+ if (Creature* rotationFocus = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ORB_ROTATION_FOCUS)))
+ me->SetFacingToObject(rotationFocus); // setInFront
+ }
+
+ void DoAction(int32 const action)
+ {
+ if (action == ACTION_SHOOT)
+ {
+ Vehicle* vehicle = me->GetVehicleKit();
+ Unit* southOrb = vehicle->GetPassenger(SEAT_SOUTH);
+ Unit* northOrb = vehicle->GetPassenger(SEAT_NORTH);
+ if (southOrb && northOrb)
+ {
+ if (northOrb->GetTypeId() == TYPEID_UNIT)
+ northOrb->ToCreature()->AI()->Talk(EMOTE_WARN_LASER);
+ TriggerCutter(northOrb, southOrb);
+ }
+
+ if (!IsHeroic())
+ return;
+
+ Unit* eastOrb = vehicle->GetPassenger(SEAT_EAST);
+ Unit* westOrb = vehicle->GetPassenger(SEAT_WEST);
+ if (eastOrb && westOrb)
+ TriggerCutter(eastOrb, westOrb);
+ }
+ }
+ private:
+ InstanceScript* instance;
+
+ 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
+ {
+ return GetRubySanctumAI<npc_orb_carrierAI>(creature);
+ }
+};
+
+class npc_meteor_strike_initial : public CreatureScript
+{
+ public:
+ npc_meteor_strike_initial() : CreatureScript("npc_meteor_strike_initial") { }
+
+ struct npc_meteor_strike_initialAI : public Scripted_NoMovementAI
+ {
+ npc_meteor_strike_initialAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _instance(creature->GetInstanceScript())
+ { }
+
+ void DoAction(int32 const action)
+ {
+ switch (action)
+ {
+ case ACTION_METEOR_STRIKE_AOE:
+ DoCast(me, SPELL_METEOR_STRIKE_AOE_DAMAGE, true);
+ DoCast(me, 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;
+ }
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ Creature* owner = summoner->ToCreature();
+ if (!owner)
+ return;
+
+ // Let Halion Controller count as summoner
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+
+ DoCast(me, SPELL_METEOR_STRIKE_COUNTDOWN);
+ DoCast(me, SPELL_BIRTH_NO_VISUAL); // Unknown purpose
+
+ if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI()))
+ {
+ Position const* ownerPos = halionAI->GetMeteorStrikePosition();
+ Position newPos;
+ float angle[4];
+ angle[0] = me->GetAngle(ownerPos);
+ angle[1] = me->GetAngle(ownerPos) - static_cast<float>(M_PI/2);
+ angle[2] = me->GetAngle(ownerPos) - static_cast<float>(-M_PI/2);
+ angle[3] = me->GetAngle(ownerPos) - static_cast<float>(M_PI);
+
+ _meteorList.clear();
+ for (uint8 i = 0; i < 4; i++)
+ {
+ angle[i] = MapManager::NormalizeOrientation(angle[i]);
+ me->SetOrientation(angle[i]);
+ me->GetNearPosition(newPos, 10.0f, 0.0f); // Exact distance
+ if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000))
+ _meteorList.push_back(meteor);
+ }
+ }
+ }
+
+ void UpdateAI(uint32 const /*diff*/) { }
+ void EnterEvadeMode() { }
+ private:
+ InstanceScript* _instance;
+ std::list<Creature*> _meteorList;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ 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 Scripted_NoMovementAI
+ {
+ npc_meteor_strikeAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _instance(creature->GetInstanceScript())
+ {
+ _range = 5.0f;
+ _spawnCount = 0;
+ }
+
+ void DoAction(int32 const action)
+ {
+ if (action == ACTION_METEOR_STRIKE_BURN)
+ {
+ DoCast(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
+ me->setActive(true);
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 500);
+ }
+ }
+
+ void IsSummonedBy(Unit* /*summoner*/)
+ {
+ // Let Halion Controller count as summoner.
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (_spawnCount > 5)
+ return;
+
+ _events.Update(diff);
+
+ if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME)
+ {
+ Position pos;
+ me->GetNearPosition(pos, _range, 0.0f);
+
+ if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000))
+ {
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(flame);
+
+ flame->CastSpell(flame, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
+ ++_spawnCount;
+ }
+ _range += 5.0f;
+ _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800);
+ }
+ }
+
+ private:
+ InstanceScript* _instance;
+ EventMap _events;
+ float _range;
+ uint8 _spawnCount;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_meteor_strikeAI>(creature);
+ }
+};
+
+class npc_combustion_consumption : public CreatureScript
+{
+ public:
+ npc_combustion_consumption() : CreatureScript("npc_combustion_consumption") { }
+
+ struct npc_combustion_consumptionAI : public Scripted_NoMovementAI
+ {
+ npc_combustion_consumptionAI(Creature* creature) : Scripted_NoMovementAI(creature),
+ _summonerGuid(0), _instance(creature->GetInstanceScript())
+ {
+ switch (me->GetEntry())
+ {
+ case NPC_COMBUSTION:
+ _explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION;
+ _damageSpell = SPELL_COMBUSTION_DAMAGE_AURA;
+ me->SetPhaseMask(0x01, true);
+ break;
+ case NPC_CONSUMPTION:
+ _explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION;
+ _damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA;
+ me->SetPhaseMask(0x20, true);
+ break;
+ default: // Should never happen
+ _explosionSpell = 0;
+ _damageSpell = 0;
+ break;
+ }
+
+ if (IsHeroic())
+ me->SetPhaseMask(0x01 | 0x20, true);
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ // Let Halion Controller count as summoner
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+
+ _summonerGuid = summoner->GetGUID();
+ }
+
+ void SetData(uint32 type, uint32 stackAmount)
+ {
+ Unit* summoner = ObjectAccessor::GetUnit(*me, _summonerGuid);
+
+ if (type != DATA_STACKS_DISPELLED || !_damageSpell || !_explosionSpell || !summoner)
+ return;
+
+ me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me);
+ DoCast(me, _damageSpell);
+
+ int32 damage = 1200 + (stackAmount * 1290); // Needs more researches.
+ summoner->CastCustomSpell(_explosionSpell, SPELLVALUE_BASE_POINT0, damage, summoner);
+ }
+
+ void UpdateAI(uint32 const /*diff*/) { }
+
+ private:
+ InstanceScript* _instance;
+ uint32 _explosionSpell;
+ uint32 _damageSpell;
+ uint64 _summonerGuid;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_combustion_consumptionAI>(creature);
+ }
+};
+
+class npc_living_inferno : public CreatureScript
+{
+ public:
+ npc_living_inferno() : CreatureScript("npc_living_inferno") { }
+
+ struct npc_living_infernoAI : public ScriptedAI
+ {
+ npc_living_infernoAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void JustSummoned(Creature* /*summoner*/)
+ {
+ me->SetInCombatWithZone();
+ DoCast(me, SPELL_BLAZING_AURA);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_living_infernoAI>(creature);
+ }
+};
+
+//! Need sniff data
+class npc_living_ember : public CreatureScript
+{
+ public:
+ npc_living_ember() : CreatureScript("npc_living_ember") { }
+
+ struct npc_living_emberAI : public ScriptedAI
+ {
+ npc_living_emberAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset()
+ {
+ _hasEnraged = false;
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ _enrageTimer = 20000;
+ _hasEnraged = false;
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (!_hasEnraged && _enrageTimer <= diff)
+ {
+ _hasEnraged = true;
+ DoCast(me, SPELL_BERSERK);
+ }
+ else _enrageTimer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ uint32 _enrageTimer;
+ bool _hasEnraged;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return GetRubySanctumAI<npc_living_emberAI>(creature);
+ }
+};
+
+class go_twilight_portal : public GameObjectScript
+{
+ public:
+ go_twilight_portal() : GameObjectScript("go_twilight_portal") { }
+
+ 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: // Not used, not seen in sniffs. Just in case.
+ 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;
+ }
+ }
+
+ bool GossipHello(Player* player)
+ {
+ if (_spellId != 0)
+ player->CastSpell(player, _spellId, true);
+ return true;
+ }
+
+ void UpdateAI(uint32 /*diff*/)
+ {
+ if (_instance->GetBossState(DATA_HALION) == IN_PROGRESS)
+ return;
+
+ if (!_deleted)
+ {
+ _deleted = true;
+ go->Delete();
+ }
+ }
+
+ private:
+ InstanceScript* _instance;
+ uint32 _spellId;
+ bool _deleted;
+ };
+
+ GameObjectAI* GetAI(GameObject* gameobject) const
+ {
+ return GetRubySanctumAI<go_twilight_portalAI>(gameobject);
+ }
+};
+
+class spell_halion_meteor_strike_marker : public SpellScriptLoader
+{
+ public:
+ spell_halion_meteor_strike_marker() : SpellScriptLoader("spell_halion_meteor_strike_marker") { }
+
+ class spell_halion_meteor_strike_marker_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_halion_meteor_strike_marker_AuraScript);
+
+ 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()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_halion_meteor_strike_marker_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_halion_meteor_strike_marker_AuraScript();
+ }
+};
+
+class spell_halion_combustion_consumption : public SpellScriptLoader
+{
+ 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) { }
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_markSpell))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH)
+ return;
+
+ if (GetTarget()->HasAura(_markSpell))
+ GetTarget()->RemoveAurasDueToSpell(_markSpell, 0, 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()
+ {
+ 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
+ {
+ return new spell_halion_combustion_consumption_AuraScript(_spellID);
+ }
+
+ private:
+ uint32 _spellID;
+};
+
+class spell_halion_marks : public SpellScriptLoader
+{
+ 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) { }
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_summonSpellId))
+ return false;
+ return true;
+ }
+
+ /// 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, 0, 0, AURA_REMOVE_BY_EXPIRE);
+ }
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+ return;
+
+ // Stacks marker
+ GetTarget()->CastCustomSpell(_summonSpellId, SPELLVALUE_BASE_POINT1, aurEff->GetBase()->GetStackAmount(), GetTarget(), TRIGGERED_FULL_MASK, NULL, NULL, GetCasterGUID());
+ }
+
+ void Register()
+ {
+ 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
+ {
+ return new spell_halion_marks_AuraScript(_summonSpell, _removeSpell);
+ }
+
+ private:
+ uint32 _summonSpell;
+ uint32 _removeSpell;
+};
+
+class spell_halion_damage_aoe_summon : public SpellScriptLoader
+{
+ 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(GetSpellInfo()->Effects[effIndex].MiscValue);
+ SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetSpellInfo()->Effects[effIndex].MiscValueB));
+ uint32 duration = uint32(GetSpellInfo()->GetDuration());
+
+ Position pos;
+ caster->GetPosition(&pos);
+ 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()
+ {
+ OnEffectHit += SpellEffectFn(spell_halion_damage_aoe_summon_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_damage_aoe_summon_SpellScript();
+ }
+};
+
+class spell_halion_twilight_realm_handlers : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_realm_handlers(const char* 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_AuraScript);
+
+ public:
+ spell_halion_twilight_realm_handlers_AuraScript(uint32 beforeHitSpell, bool isApplyHandler) : AuraScript(),
+ _isApply(isApplyHandler), _beforeHitSpellId(beforeHitSpell)
+ { }
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(_beforeHitSpellId))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/)
+ {
+ GetTarget()->RemoveAurasDueToSpell(SPELL_TWILIGHT_REALM);
+ if (InstanceScript* instance = GetTarget()->GetInstanceScript())
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_UNK7);
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*handle*/)
+ {
+ Unit* target = GetTarget();
+ if (!target)
+ return;
+
+ target->RemoveAurasDueToSpell(_beforeHitSpellId, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL);
+ if (InstanceScript* instance = target->GetInstanceScript())
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_UNK7);
+ }
+
+ void Register()
+ {
+ 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
+ {
+ return new spell_halion_twilight_realm_handlers_AuraScript(_beforeHitSpell, _isApplyHandler);
+ }
+
+ private:
+ uint32 _beforeHitSpell;
+ bool _isApplyHandler;
+};
+
+class spell_halion_clear_debuffs : public SpellScriptLoader
+{
+ 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*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CLEAR_DEBUFFS))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_TWILIGHT_REALM))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ if (GetHitUnit()->HasAura(GetSpellInfo()->Effects[effIndex].CalcValue()))
+ GetHitUnit()->RemoveAurasDueToSpell(GetSpellInfo()->Effects[effIndex].CalcValue());
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_halion_clear_debuffs_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_clear_debuffs_SpellScript();
+ }
+};
+
+class TwilightCutterSelector
+{
+ public:
+ TwilightCutterSelector(Unit* caster, Unit* cutterCaster) : _caster(caster), _cutterCaster(cutterCaster) {}
+
+ bool operator()(WorldObject* unit)
+ {
+ return !unit->IsInBetween(_caster, _cutterCaster, 4.0f);
+ }
+
+ private:
+ Unit* _caster;
+ Unit* _cutterCaster;
+};
+
+class spell_halion_twilight_cutter : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_cutter() : SpellScriptLoader("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 (Aura* cutter = caster->GetAura(SPELL_TWILIGHT_CUTTER))
+ {
+ if (Unit* cutterCaster = cutter->GetCaster())
+ {
+ unitList.remove_if(TwilightCutterSelector(caster, cutterCaster));
+ return;
+ }
+ }
+
+ // In case cutter caster werent found for some reason
+ unitList.clear();
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_twilight_cutter_SpellScript::RemoveNotBetween, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_twilight_cutter_SpellScript();
+ }
+};
+
+class spell_halion_twilight_phasing : public SpellScriptLoader
+{
+ public:
+ spell_halion_twilight_phasing() : SpellScriptLoader("spell_halion_twilight_phasing") { }
+
+ class spell_halion_twilight_phasing_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_twilight_phasing_SpellScript);
+
+ void Phase()
+ {
+ Unit* caster = GetCaster();
+ caster->CastSpell(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), SPELL_SUMMON_TWILIGHT_PORTAL, true);
+ caster->GetMap()->SummonCreature(NPC_TWILIGHT_HALION, HalionSpawnPos);
+ }
+
+ void Register()
+ {
+ OnHit += SpellHitFn(spell_halion_twilight_phasing_SpellScript::Phase);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_twilight_phasing_SpellScript();
+ }
+};
+
+class spell_halion_summon_exit_portals : public SpellScriptLoader
+{
+ 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 OnSummon(SpellEffIndex effIndex)
+ {
+ WorldLocation summonPos = *GetExplTargetDest();
+ Position offset = {0.0f, 20.0f, 0.0f, 0.0f};
+ if (effIndex == EFFECT_1)
+ offset.m_positionY = -20.0f;
+
+ summonPos.RelocateOffset(offset);
+
+ SetExplTargetDest(summonPos);
+ GetHitDest()->RelocateOffset(offset);
+ }
+
+ void Register()
+ {
+ OnEffectLaunch += SpellEffectFn(spell_halion_summon_exit_portals_SpellScript::OnSummon, EFFECT_0, SPELL_EFFECT_SUMMON_OBJECT_WILD);
+ OnEffectLaunch += SpellEffectFn(spell_halion_summon_exit_portals_SpellScript::OnSummon, EFFECT_1, SPELL_EFFECT_SUMMON_OBJECT_WILD);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_halion_summon_exit_portals_SpellScript();
+ }
+};
+
+void AddSC_boss_halion()
+{
+ new boss_halion();
+ new boss_twilight_halion();
+
+ new npc_halion_controller();
+ 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_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();
+}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
index 5678bbbeb83..a6b50467538 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp
@@ -37,18 +37,23 @@ class instance_ruby_sanctum : public InstanceMapScript
{
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
- BaltharusTheWarbornGUID = 0;
- GeneralZarithrianGUID = 0;
- SavianaRagefireGUID = 0;
- HalionGUID = 0;
- HalionControllerGUID = 0;
+ BaltharusTheWarbornGUID = 0;
+ GeneralZarithrianGUID = 0;
+ SavianaRagefireGUID = 0;
+ HalionGUID = 0;
+ TwilightHalionGUID = 0;
+ OrbCarrierGUID = 0;
+ OrbRotationFocusGUID = 0;
+ HalionControllerGUID = 0;
+ CombatStalkerGUID = 0;
CrystalChannelTargetGUID = 0;
- XerestraszaGUID = 0;
- BaltharusSharedHealth = 0;
- FlameWallsGUID = 0;
- FlameRingGUID = 0;
- memset(ZarithianSpawnStalkerGUID, 0, 2*sizeof(uint64));
- memset(BurningTreeGUID, 0, 4*sizeof(uint64));
+ XerestraszaGUID = 0;
+ BaltharusSharedHealth = 0;
+ FlameWallsGUID = 0;
+ FlameRingGUID = 0;
+
+ memset(ZarithrianSpawnStalkerGUID, 0, 2 * sizeof(uint64));
+ memset(BurningTreeGUID, 0, 4 * sizeof(uint64));
}
void OnCreatureCreate(Creature* creature)
@@ -67,19 +72,32 @@ class instance_ruby_sanctum : public InstanceMapScript
case NPC_HALION:
HalionGUID = creature->GetGUID();
break;
+ case NPC_TWILIGHT_HALION:
+ TwilightHalionGUID = creature->GetGUID();
+ break;
case NPC_HALION_CONTROLLER:
HalionControllerGUID = creature->GetGUID();
+ break;
+ case NPC_ORB_CARRIER:
+ OrbCarrierGUID = creature->GetGUID();
+ break;
+ case NPC_ORB_ROTATION_FOCUS:
+ OrbRotationFocusGUID = creature->GetGUID();
+ break;
+ case NPC_COMBAT_STALKER:
+ CombatStalkerGUID = creature->GetGUID();
+ break;
case NPC_BALTHARUS_TARGET:
CrystalChannelTargetGUID = creature->GetGUID();
break;
case NPC_XERESTRASZA:
XerestraszaGUID = creature->GetGUID();
break;
- case NPC_ZARITHIAN_SPAWN_STALKER:
- if (!ZarithianSpawnStalkerGUID[0])
- ZarithianSpawnStalkerGUID[0] = creature->GetGUID();
+ case NPC_ZARITHRIAN_SPAWN_STALKER:
+ if (!ZarithrianSpawnStalkerGUID[0])
+ ZarithrianSpawnStalkerGUID[0] = creature->GetGUID();
else
- ZarithianSpawnStalkerGUID[1] = creature->GetGUID();
+ ZarithrianSpawnStalkerGUID[1] = creature->GetGUID();
break;
default:
break;
@@ -101,6 +119,9 @@ class instance_ruby_sanctum : public InstanceMapScript
case GO_FLAME_RING:
FlameRingGUID = go->GetGUID();
break;
+ case GO_TWILIGHT_FLAME_RING:
+ TwilightFlameRingGUID = go->GetGUID();
+ break;
case GO_BURNING_TREE_1:
BurningTreeGUID[0] = go->GetGUID();
if (GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
@@ -152,24 +173,30 @@ class instance_ruby_sanctum : public InstanceMapScript
return SavianaRagefireGUID;
case DATA_GENERAL_ZARITHRIAN:
return GeneralZarithrianGUID;
- case DATA_ZARITHIAN_SPAWN_STALKER_1:
- return ZarithianSpawnStalkerGUID[0];
- case DATA_ZARITHIAN_SPAWN_STALKER_2:
- return ZarithianSpawnStalkerGUID[1];
+ case DATA_ZARITHRIAN_SPAWN_STALKER_1:
+ case DATA_ZARITHRIAN_SPAWN_STALKER_2:
+ return ZarithrianSpawnStalkerGUID[type - DATA_ZARITHRIAN_SPAWN_STALKER_1];
case DATA_HALION:
return HalionGUID;
+ case DATA_TWILIGHT_HALION:
+ return TwilightHalionGUID;
+ case DATA_ORB_CARRIER:
+ return OrbCarrierGUID;
+ case DATA_ORB_ROTATION_FOCUS:
+ return OrbRotationFocusGUID;
case DATA_HALION_CONTROLLER:
return HalionControllerGUID;
case DATA_BURNING_TREE_1:
- return BurningTreeGUID[0];
case DATA_BURNING_TREE_2:
- return BurningTreeGUID[1];
case DATA_BURNING_TREE_3:
- return BurningTreeGUID[2];
case DATA_BURNING_TREE_4:
- return BurningTreeGUID[3];
+ return BurningTreeGUID[type - DATA_BURNING_TREE_1];
case DATA_FLAME_RING:
return FlameRingGUID;
+ case DATA_TWILIGHT_FLAME_RING:
+ return TwilightFlameRingGUID;
+ case DATA_COMBAT_STALKER:
+ return CombatStalkerGUID;
default:
break;
}
@@ -180,7 +207,14 @@ class instance_ruby_sanctum : public InstanceMapScript
bool SetBossState(uint32 type, EncounterState state)
{
if (!InstanceScript::SetBossState(type, state))
+ {
+ // Summon Halion on instance loading if conditions are met. Without those lines,
+ // InstanceScript::SetBossState returns false, thus preventing the switch from being called.
+ if (type == DATA_HALION && state != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE && !GetData64(DATA_HALION_CONTROLLER))
+ if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
+ halionController->AI()->DoAction(ACTION_INTRO_HALION);
return false;
+ }
switch (type)
{
@@ -205,20 +239,30 @@ class instance_ruby_sanctum : public InstanceMapScript
break;
}
case DATA_GENERAL_ZARITHRIAN:
+ {
if (GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE)
HandleGameObject(FlameWallsGUID, state != IN_PROGRESS);
- /*
- if (state == DONE)
+
+ // Not called at instance loading, no big deal.
+ if (state == DONE && GetBossState(DATA_HALION) != DONE)
if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos))
halionController->AI()->DoAction(ACTION_INTRO_HALION);
- */
break;
+ }
case DATA_HALION:
- /*
- if (state != IN_PROGRESS)
+ {
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TOGGLE, 0);
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_TWILIGHT, 0);
+ DoUpdateWorldState(WORLDSTATE_CORPOREALITY_MATERIAL, 0);
+
+ // Reopen rings on wipe or success
+ if (state == DONE || state == FAIL)
+ {
HandleGameObject(FlameRingGUID, true);
- */
+ HandleGameObject(TwilightFlameRingGUID, true);
+ }
break;
+ }
default:
break;
}
@@ -228,25 +272,18 @@ class instance_ruby_sanctum : public InstanceMapScript
void SetData(uint32 type, uint32 data)
{
- switch (type)
- {
- case DATA_BALTHARUS_SHARED_HEALTH:
- BaltharusSharedHealth = data;
- break;
- }
+ if (type != DATA_BALTHARUS_SHARED_HEALTH)
+ return;
+
+ BaltharusSharedHealth = data;
}
uint32 GetData(uint32 type)
{
- switch (type)
- {
- case DATA_BALTHARUS_SHARED_HEALTH:
- return BaltharusSharedHealth;
- default:
- break;
- }
+ if (type != DATA_BALTHARUS_SHARED_HEALTH)
+ return 0;
- return 0;
+ return BaltharusSharedHealth;
}
std::string GetSaveData()
@@ -260,6 +297,13 @@ class instance_ruby_sanctum : public InstanceMapScript
return saveStream.str();
}
+ void FillInitialWorldStates(WorldPacket& data)
+ {
+ data << uint32(WORLDSTATE_CORPOREALITY_MATERIAL) << uint32(50);
+ data << uint32(WORLDSTATE_CORPOREALITY_TWILIGHT) << uint32(50);
+ data << uint32(WORLDSTATE_CORPOREALITY_TOGGLE) << uint32(0);
+ }
+
void Load(char const* str)
{
if (!str)
@@ -298,13 +342,19 @@ class instance_ruby_sanctum : public InstanceMapScript
uint64 GeneralZarithrianGUID;
uint64 SavianaRagefireGUID;
uint64 HalionGUID;
+ uint64 TwilightHalionGUID;
uint64 HalionControllerGUID;
+ uint64 OrbCarrierGUID;
+ uint64 OrbRotationFocusGUID;
uint64 CrystalChannelTargetGUID;
uint64 XerestraszaGUID;
uint64 FlameWallsGUID;
- uint64 ZarithianSpawnStalkerGUID[2];
+ uint64 ZarithrianSpawnStalkerGUID[2];
uint64 BurningTreeGUID[4];
uint64 FlameRingGUID;
+ uint64 TwilightFlameRingGUID;
+ uint64 CombatStalkerGUID;
+
uint32 BaltharusSharedHealth;
};
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
index 02ade2ff3e7..215a1f6185b 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h
@@ -21,6 +21,7 @@
#include "SpellScript.h"
#include "Map.h"
#include "Creature.h"
+#include "GameObjectAI.h"
#define RSScriptName "instance_ruby_sanctum"
uint32 const EncounterCount = 4;
@@ -36,17 +37,22 @@ enum DataTypes
DATA_HALION = 3,
// Etc
- DATA_XERESTRASZA = 4,
- DATA_CRYSTAL_CHANNEL_TARGET = 5,
- DATA_BALTHARUS_SHARED_HEALTH = 6,
- DATA_ZARITHIAN_SPAWN_STALKER_1 = 7,
- DATA_ZARITHIAN_SPAWN_STALKER_2 = 8,
- DATA_HALION_CONTROLLER = 9,
- DATA_BURNING_TREE_1 = 10,
- DATA_BURNING_TREE_2 = 11,
- DATA_BURNING_TREE_3 = 12,
- DATA_BURNING_TREE_4 = 13,
- DATA_FLAME_RING = 14,
+ DATA_TWILIGHT_HALION = 4,
+ DATA_XERESTRASZA = 5,
+ DATA_CRYSTAL_CHANNEL_TARGET = 6,
+ DATA_BALTHARUS_SHARED_HEALTH = 7,
+ DATA_ZARITHRIAN_SPAWN_STALKER_1 = 8,
+ DATA_ZARITHRIAN_SPAWN_STALKER_2 = 9,
+ DATA_HALION_CONTROLLER = 10,
+ DATA_ORB_CARRIER = 11,
+ DATA_ORB_ROTATION_FOCUS = 12,
+ DATA_BURNING_TREE_1 = 13,
+ DATA_BURNING_TREE_2 = 14,
+ DATA_BURNING_TREE_3 = 15,
+ DATA_BURNING_TREE_4 = 16,
+ DATA_FLAME_RING = 17,
+ DATA_TWILIGHT_FLAME_RING = 18,
+ DATA_COMBAT_STALKER = 19,
};
enum SharedActions
@@ -66,14 +72,14 @@ enum CreaturesIds
// General Zarithrian
NPC_GENERAL_ZARITHRIAN = 39746,
NPC_ONYX_FLAMECALLER = 39814,
- NPC_ZARITHIAN_SPAWN_STALKER = 39794,
+ NPC_ZARITHRIAN_SPAWN_STALKER = 39794,
// Saviana Ragefire
NPC_SAVIANA_RAGEFIRE = 39747,
// Halion
NPC_HALION = 39863,
- NPC_HALION_TWILIGHT = 40142,
+ NPC_TWILIGHT_HALION = 40142,
NPC_HALION_CONTROLLER = 40146,
NPC_LIVING_INFERNO = 40681,
NPC_LIVING_EMBER = 40683,
@@ -81,6 +87,8 @@ enum CreaturesIds
NPC_ORB_ROTATION_FOCUS = 40091,
NPC_SHADOW_ORB_N = 40083,
NPC_SHADOW_ORB_S = 40100,
+ NPC_SHADOW_ORB_E = 40468, // Not sure which entry is east and west.
+ NPC_SHADOW_ORB_W = 40469,
NPC_METEOR_STRIKE_MARK = 40029,
NPC_METEOR_STRIKE_NORTH = 40041,
NPC_METEOR_STRIKE_EAST = 40042,
@@ -88,6 +96,8 @@ enum CreaturesIds
NPC_METEOR_STRIKE_SOUTH = 40044,
NPC_METEOR_STRIKE_FLAME = 40055,
NPC_COMBUSTION = 40001,
+ NPC_CONSUMPTION = 40135,
+ NPC_COMBAT_STALKER = 40151,
// Xerestrasza
NPC_XERESTRASZA = 40429,
@@ -101,6 +111,7 @@ enum GameObjectsIds
GO_FIRE_FIELD = 203005,
GO_FLAME_WALLS = 203006,
GO_FLAME_RING = 203007,
+ GO_TWILIGHT_FLAME_RING = 203624,
GO_BURNING_TREE_1 = 203034,
GO_BURNING_TREE_2 = 203035,
GO_BURNING_TREE_3 = 203036,
@@ -114,6 +125,11 @@ enum WorldStatesRS
WORLDSTATE_CORPOREALITY_TOGGLE = 5051,
};
+enum InstanceSpell
+{
+ SPELL_BERSERK = 26662,
+};
+
template<class AI>
CreatureAI* GetRubySanctumAI(Creature* creature)
{
@@ -124,4 +140,15 @@ CreatureAI* GetRubySanctumAI(Creature* creature)
return NULL;
}
+template<class AI>
+GameObjectAI* GetRubySanctumAI(GameObject* go)
+{
+ if (InstanceMap* instance = go->GetMap()->ToInstanceMap())
+ if (instance->GetInstanceScript())
+ if (instance->GetScriptId() == sObjectMgr->GetScriptId(RSScriptName))
+ return new AI(go);
+
+ return NULL;
+}
+
#endif // RUBY_SANCTUM_H_