diff options
5 files changed, 1173 insertions, 1156 deletions
diff --git a/sql/updates/world/master/2021_10_23_07_world_2018_09_01_00_world.sql b/sql/updates/world/master/2021_10_23_07_world_2018_09_01_00_world.sql new file mode 100644 index 00000000000..94e1a15a3d3 --- /dev/null +++ b/sql/updates/world/master/2021_10_23_07_world_2018_09_01_00_world.sql @@ -0,0 +1,165 @@ +-- Algalon +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_algalon_arcane_barrage', +'spell_algalon_phase_constellation', +'spell_algalon_black_hole_phase_shifts'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(65508,'spell_algalon_phase_constellation'), +(62168,'spell_algalon_black_hole_phase_shifts'), +(65250,'spell_algalon_black_hole_phase_shifts'), +(64417,'spell_algalon_black_hole_phase_shifts'); + +UPDATE `creature_template` SET `ScriptName`='npc_black_hole' WHERE `entry`=32953; +UPDATE `creature` SET `spawntimesecs`=15 WHERE `id`=33089; -- Dark Matters should respawn faster (is always full present in each black hole travel) + +DELETE FROM `creature_template_movement` WHERE `CreatureId`=34131; -- Stalker Asteroid Target 2 (25 man) +INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`) VALUES +(34131,0,0,1,0); + +-- Living Constellation immune mask +UPDATE `creature_template` SET `mechanic_immune_mask` = +1| -- charm +2| -- disorient +4| -- disarm +16| -- fear +512| -- sleep +2048| -- stun +4096| -- freeze +8192| -- knockout +65536| -- polymorph +131072| -- banish +524288| -- shackle +1048576| -- mount +4194304| -- turn +8388608| -- horror +536870912 -- sapped +WHERE `entry` IN (33052,33116); + +-- Brann Bronzebeard +UPDATE `creature_text` SET `Emote`=19 WHERE `CreatureID`=34064 AND `GroupID`=1 AND `ID`=0; + +-- Movement stuffs + +-- Before Door (Intro) +DELETE FROM `script_spline_chain_meta` WHERE `entry`=34064 AND `chainId`=1; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(34064, 1, 0, 4584, 3641), +(34064, 1, 1, 1881, 1234), +(34064, 1, 2, 1279, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=34064 AND `chainId`=1; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(34064, 1, 0, 0, 1677.3630, -162.35140, 427.33200), +(34064, 1, 0, 1, 1680.0880, -162.26590, 427.33260), +(34064, 1, 0, 2, 1679.0880, -162.26590, 427.33260), +(34064, 1, 0, 3, 1663.3630, -163.04570, 427.32710), +(34064, 1, 0, 4, 1660.9440, -163.16570, 427.27290), +(34064, 1, 0, 5, 1656.7000, -163.37610, 427.27290), +(34064, 1, 0, 6, 1653.5710, -163.53130, 427.34070), +(34064, 1, 0, 7, 1642.4820, -164.08120, 427.26020), +(34064, 1, 0, 8, 1642.4820, -164.08120, 427.26020), +(34064, 1, 1, 0, 1648.2720, -163.79410, 427.30220), +(34064, 1, 1, 1, 1642.3860, -164.15430, 427.52730), +(34064, 1, 1, 2, 1635.0000, -169.51450, 427.25230), +(34064, 1, 2, 0, 1639.2800, -166.40650, 427.25680), +(34064, 1, 2, 1, 1635.2970, -169.42000, 427.50950), +(34064, 1, 2, 2, 1633.2970, -172.92000, 427.50950), +(34064, 1, 2, 3, 1632.8140, -173.93340, 427.26210); + +-- Algalon Room (Intro) +DELETE FROM `script_spline_chain_meta` WHERE `entry`=34064 AND `chainId`=2; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(34064, 2, 0, 21837, 20656), +(34064, 2, 1, 20274, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=34064 AND `chainId`=2; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(34064, 2, 0, 0, 1632.8140, -173.93340, 427.26210), +(34064, 2, 0, 1, 1632.8260, -175.36180, 427.54690), +(34064, 2, 0, 2, 1632.8260, -176.36180, 427.54690), +(34064, 2, 0, 3, 1632.5760, -178.11180, 427.54690), +(34064, 2, 0, 4, 1632.5760, -186.86180, 427.54690), +(34064, 2, 0, 5, 1632.3260, -191.11180, 427.54690), +(34064, 2, 0, 6, 1632.0760, -211.36180, 419.79690), +(34064, 2, 0, 7, 1632.0760, -213.61180, 418.79690), +(34064, 2, 0, 8, 1631.8260, -219.86180, 418.79690), +(34064, 2, 0, 9, 1631.5760, -222.86180, 418.79690), +(34064, 2, 0, 10, 1631.5760, -226.11180, 418.79690), +(34064, 2, 0, 11, 1631.3390, -226.79030, 418.33180), +(34064, 2, 1, 0, 1631.4220, -223.79560, 418.40920), +(34064, 2, 1, 1, 1631.4580, -226.29390, 418.61520), +(34064, 2, 1, 2, 1631.4580, -226.79390, 418.61520), +(34064, 2, 1, 3, 1631.9580, -227.79390, 418.36520), +(34064, 2, 1, 4, 1631.9580, -229.79390, 417.86520), +(34064, 2, 1, 5, 1631.7080, -232.04390, 417.86520), +(34064, 2, 1, 6, 1631.7080, -234.04390, 417.86520), +(34064, 2, 1, 7, 1637.2080, -266.79390, 417.61520), +(34064, 2, 1, 8, 1630.4940, -267.29210, 417.32110); + +-- Outro 1 +DELETE FROM `script_spline_chain_meta` WHERE `entry`=34064 AND `chainId`=3; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(34064, 3, 0, 13940, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=34064 AND `chainId`=3; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(34064, 3, 0, 0, 1631.9890, -221.54390, 418.40910), +(34064, 3, 0, 1, 1631.9910, -222.44830, 418.40910), +(34064, 3, 0, 2, 1632.0610, -269.03790, 417.32100), +(34064, 3, 0, 3, 1631.9860, -297.78310, 417.32100), +(34064, 3, 0, 4, 1631.9860, -297.78310, 417.32100); + +-- Outro 2 +DELETE FROM `script_spline_chain_meta` WHERE `entry`=34064 AND `chainId`=4; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(34064, 4, 0, 26675, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=34064 AND `chainId`=4; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(34064, 4, 0, 0, 1631.9860, -297.78310, 417.32100), +(34064, 4, 0, 1, 1632.5820, -289.54480, 417.79630), +(34064, 4, 0, 2, 1633.0820, -267.29480, 417.79630), +(34064, 4, 0, 3, 1631.8320, -227.29480, 418.54630), +(34064, 4, 0, 4, 1632.5820, -217.79480, 418.79630), +(34064, 4, 0, 5, 1632.3320, -203.04480, 423.04630), +(34064, 4, 0, 6, 1633.0820, -188.79480, 427.54630), +(34064, 4, 0, 7, 1631.5820, -164.04480, 427.29630), +(34064, 4, 0, 8, 1656.8320, -164.79480, 427.54630), +(34064, 4, 0, 9, 1681.3320, -164.29480, 427.54630), +(34064, 4, 0, 10, 1682.3320, -154.54480, 427.54630), +(34064, 4, 0, 11, 1683.1770, -136.30650, 427.27150); + +-- Despawn Point Intro +DELETE FROM `script_spline_chain_meta` WHERE `entry`=34064 AND `chainId`=5; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(34064, 5, 0, 29711, 28875), +(34064, 5, 1, 12977, 12141), +(34064, 5, 2, 7479, 6437), +(34064, 5, 3, 5117, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=34064 AND `chainId`=5; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(34064, 5, 0, 0, 1630.4940, -267.29210, 417.32110), +(34064, 5, 0, 1, 1637.0400, -266.68800, 417.84810), +(34064, 5, 0, 2, 1634.5400, -233.93800, 417.84810), +(34064, 5, 0, 3, 1634.2900, -231.68800, 417.84810), +(34064, 5, 0, 4, 1634.2900, -229.93800, 417.84810), +(34064, 5, 0, 5, 1632.0400, -227.68800, 418.59810), +(34064, 5, 0, 6, 1632.0400, -226.18800, 418.84810), +(34064, 5, 0, 7, 1632.0400, -223.18800, 418.84810), +(34064, 5, 0, 8, 1632.0400, -220.18800, 418.84810), +(34064, 5, 0, 9, 1632.0400, -213.68800, 418.84810), +(34064, 5, 0, 10, 1632.0400, -211.68800, 419.84810), +(34064, 5, 0, 11, 1632.0850, -201.58390, 423.37500), +(34064, 5, 1, 0, 1632.0770, -203.61940, 422.59170), +(34064, 5, 1, 1, 1632.1190, -201.36540, 423.66990), +(34064, 5, 1, 2, 1631.6190, -190.86540, 427.66990), +(34064, 5, 1, 3, 1631.3690, -186.86540, 427.41990), +(34064, 5, 1, 4, 1631.1190, -178.11540, 427.41990), +(34064, 5, 1, 5, 1631.1190, -176.36540, 427.41990), +(34064, 5, 1, 6, 1631.1190, -175.36540, 427.41990), +(34064, 5, 1, 7, 1630.8690, -173.11540, 427.41990), +(34064, 5, 1, 8, 1630.6600, -172.11150, 427.24800), +(34064, 5, 2, 0, 1630.7620, -174.22000, 427.26550), +(34064, 5, 2, 1, 1630.8760, -173.00420, 427.51350), +(34064, 5, 2, 2, 1630.8760, -171.75420, 427.51350), +(34064, 5, 2, 3, 1645.9900, -165.78850, 427.26160), +(34064, 5, 3, 0, 1642.4200, -167.26120, 427.25840), +(34064, 5, 3, 1, 1646.1510, -165.89170, 427.54380), +(34064, 5, 3, 2, 1654.4010, -165.14170, 427.54380), +(34064, 5, 3, 3, 1654.8810, -165.02210, 427.32920); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 3ae31465448..455ab86e36e 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -4351,6 +4351,7 @@ bool _isPositiveEffectImpl(SpellInfo const* spellInfo, SpellEffectInfo const& ef case 40268: // Spiritual Vengeance, Teron Gorefiend, Black Temple case 61987: // Avenging Wrath Marker case 61988: // Divine Shield exclude aura + case 64412: // Phase Punch, Algalon the Observer, Ulduar case 72410: // Rune of Blood, Saurfang, Icecrown Citadel case 71204: // Touch of Insignificance, Lady Deathwhisper, Icecrown Citadel return false; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index b9aafbedd2d..977d211b1f7 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -23,7 +23,6 @@ #include "MapManager.h" #include "MotionMaster.h" #include "MoveSplineInit.h" -#include "ObjectAccessor.h" #include "PassiveAI.h" #include "Player.h" #include "ScriptedCreature.h" @@ -60,6 +59,9 @@ enum Texts SAY_ALGALON_DESPAWN_2 = 18, SAY_ALGALON_DESPAWN_3 = 19, SAY_ALGALON_KILL = 20, + + // Direct Sound + ENGAGE_MUSIC_ID = 15878 }; enum Spells @@ -86,6 +88,7 @@ enum Spells // Living Constellation SPELL_ARCANE_BARRAGE = 64599, + SPELL_DESPAWN_BLACK_HOLE = 64391, // Collapsing Star SPELL_COLLAPSE = 62018, @@ -100,10 +103,11 @@ enum Spells SPELL_SUMMON_VOID_ZONE_VISUAL = 64470, SPELL_VOID_ZONE_VISUAL = 64469, SPELL_BLACK_HOLE_CREDIT = 65312, + SPELL_BLACK_HOLE_DOT = 62169, // Worm Hole SPELL_WORM_HOLE_TRIGGER = 65251, - SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450, + SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450 }; uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417}; @@ -111,104 +115,91 @@ uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417}; enum Events { // Celestial Planetarium Access - EVENT_DESPAWN_CONSOLE = 1, + EVENT_DESPAWN_CONSOLE = 1, // Brann Bronzebeard - EVENT_BRANN_MOVE_INTRO = 2, - EVENT_SUMMON_ALGALON = 3, - EVENT_BRANN_OUTRO_1 = 4, - EVENT_BRANN_OUTRO_2 = 5, + EVENT_BRANN_MOVE_INTRO, + EVENT_BRANN_SAY_INTRO_1, + EVENT_SUMMON_ALGALON, + EVENT_BRANN_OUTRO_1, + EVENT_BRANN_OUTRO_2, // Algalon the Observer - EVENT_INTRO_1 = 6, - EVENT_INTRO_2 = 7, - EVENT_INTRO_3 = 8, - EVENT_INTRO_FINISH = 9, - EVENT_START_COMBAT = 10, - EVENT_INTRO_TIMER_DONE = 11, - EVENT_QUANTUM_STRIKE = 12, - EVENT_PHASE_PUNCH = 13, - EVENT_SUMMON_COLLAPSING_STAR = 14, - EVENT_BIG_BANG = 15, - EVENT_RESUME_UPDATING = 16, - EVENT_ASCEND_TO_THE_HEAVENS = 17, - EVENT_EVADE = 18, - EVENT_COSMIC_SMASH = 19, - EVENT_UNLOCK_YELL = 20, - EVENT_OUTRO_START = 21, - EVENT_OUTRO_1 = 22, - EVENT_OUTRO_2 = 23, - EVENT_OUTRO_3 = 24, - EVENT_OUTRO_4 = 25, - EVENT_OUTRO_5 = 26, - EVENT_OUTRO_6 = 27, - EVENT_OUTRO_7 = 28, - EVENT_OUTRO_8 = 29, - EVENT_OUTRO_9 = 30, - EVENT_OUTRO_10 = 31, - EVENT_OUTRO_11 = 32, - EVENT_OUTRO_12 = 33, - EVENT_OUTRO_13 = 34, - EVENT_OUTRO_14 = 35, - EVENT_DESPAWN_ALGALON_1 = 36, - EVENT_DESPAWN_ALGALON_2 = 37, - EVENT_DESPAWN_ALGALON_3 = 38, + EVENT_INTRO_1, + EVENT_INTRO_2, + EVENT_SUMMON_AZEROTH, + EVENT_INTRO_3, + EVENT_INTRO_FINISH, + EVENT_START_COMBAT, + EVENT_INTRO_TIMER_DONE, + EVENT_QUANTUM_STRIKE, + EVENT_PHASE_PUNCH, + EVENT_SUMMON_COLLAPSING_STAR, + EVENT_BIG_BANG, + EVENT_RESUME_UPDATING, + EVENT_ASCEND_TO_THE_HEAVENS, + EVENT_EVADE, + EVENT_COSMIC_SMASH, + EVENT_UNLOCK_YELL, + EVENT_OUTRO_START, + EVENT_OUTRO_1, + EVENT_OUTRO_2, + EVENT_OUTRO_3, + EVENT_OUTRO_4, + EVENT_OUTRO_5, + EVENT_OUTRO_6, + EVENT_OUTRO_7, + EVENT_OUTRO_8, + EVENT_OUTRO_9, + EVENT_OUTRO_10, + EVENT_OUTRO_11, + EVENT_DESPAWN_ALGALON_1, + EVENT_DESPAWN_ALGALON_2, + EVENT_DESPAWN_ALGALON_3, // Living Constellation - EVENT_ARCANE_BARRAGE = 39, + EVENT_ARCANE_BARRAGE }; enum Actions { - ACTION_START_INTRO = 0, - ACTION_FINISH_INTRO = 1, - ACTION_ACTIVATE_STAR = 2, - ACTION_BIG_BANG = 3, - ACTION_ASCEND = 4, - ACTION_OUTRO = 5, -}; - -enum Points -{ - POINT_BRANN_INTRO = 0, - MAX_BRANN_WAYPOINTS_INTRO = 10, - POINT_BRANN_OUTRO = 10, - POINT_BRANN_OUTRO_END = 11, - - POINT_ALGALON_LAND = 1, - POINT_ALGALON_OUTRO = 2, + ACTION_START_INTRO = 0, + ACTION_ACTIVATE_STAR, + ACTION_BIG_BANG, + ACTION_ASCEND, + ACTION_OUTRO, + ACTION_INTRO_2, }; enum EncounterPhases { - PHASE_NORMAL = 0, - PHASE_ROLE_PLAY = 1, - PHASE_BIG_BANG = 2 + PHASE_NORMAL = 0, + PHASE_ROLE_PLAY, + PHASE_BIG_BANG }; enum AchievmentInfo { EVENT_ID_SUPERMASSIVE_START = 21697, - DATA_HAS_FED_ON_TEARS = 30043005, + DATA_HAS_FED_ON_TEARS = 30043005 }; +enum AlgalonSplineMovements +{ + SPLINE_INITIAL_MOVE = 1, + SPLINE_ALGALON_ROOM = 2, + SPLINE_OUTRO_1 = 3, + SPLINE_OUTRO_2 = 4, + SPLINE_DESPAWN_INTRO_1 = 5 +}; -Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f}; -Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] = +enum AlgalonMovePoints { - {1642.482f, -164.0812f, 427.2602f, 0.0f}, - {1635.000f, -169.5145f, 427.2523f, 0.0f}, - {1632.814f, -173.9334f, 427.2621f, 0.0f}, - {1632.676f, -190.5927f, 425.8831f, 0.0f}, - {1631.497f, -214.2221f, 418.1152f, 0.0f}, - {1624.717f, -224.6876f, 418.1152f, 0.0f}, - {1631.497f, -214.2221f, 418.1152f, 0.0f}, - {1632.676f, -190.5927f, 425.8831f, 0.0f}, - {1632.814f, -173.9334f, 427.2621f, 0.0f}, - {1635.000f, -169.5145f, 427.2523f, 0.0f}, + POINT_INITIAL_MOVE = 1, + POINT_ALGALON_ROOM, + POINT_DESPAWN, + POINT_ALGALON_OUTRO }; -Position const AlgalonSummonPos = {1632.531f, -304.8516f, 450.1123f, 1.530165f}; -Position const AlgalonLandPos = {1632.668f, -302.7656f, 417.3211f, 1.530165f}; #define LIVING_CONSTELLATION_COUNT 11 Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] = @@ -223,7 +214,7 @@ Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] = {1592.242f, -325.5323f, 446.9508f, 0.226893f}, {1635.821f, -363.3442f, 424.3459f, 1.466077f}, {1672.188f, -357.2484f, 436.7337f, 2.338741f}, - {1615.800f, -348.0065f, 442.9586f, 1.134464f}, + {1615.800f, -348.0065f, 442.9586f, 1.134464f} }; #define COLLAPSING_STAR_COUNT 4 @@ -232,22 +223,19 @@ Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] = {1649.438f, -319.8127f, 418.3941f, 1.082104f}, {1647.005f, -288.6790f, 417.3955f, 3.490659f}, {1622.451f, -321.1563f, 417.6188f, 4.677482f}, - {1615.060f, -291.6816f, 417.7796f, 3.490659f}, + {1615.060f, -291.6816f, 417.7796f, 3.490659f} }; + +Position const BrannIntroSpawnPos = { 1677.363f, -162.3514f, 427.332f, 3.191144f }; +Position const AlgalonSummonPos = { 1632.531f, -304.8516f, 450.1123f, 1.530165f }; +Position const AlgalonLandPos = { 1632.668f, -302.7656f, 417.3211f, 1.530165f }; Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f}; -Position const BrannOutroPos[3] = -{ - {1632.023f, -243.7434f, 417.9118f, 0.0f}, - {1631.986f, -297.7831f, 417.3210f, 0.0f}, - {1633.832f, -216.2948f, 417.0463f, 0.0f}, -}; +Position const BrannOutroPos = { 1631.989f, -221.5439f, 418.4091f, 4.714909f }; class ActivateLivingConstellation : public BasicEvent { public: - ActivateLivingConstellation(Unit* owner) : _owner(owner), _instance(owner->GetInstanceScript()) - { - } + ActivateLivingConstellation(Unit* owner) : _owner(owner), _instance(owner->GetInstanceScript()) { } bool Execute(uint64 execTime, uint32 /*diff*/) override { @@ -267,9 +255,7 @@ class ActivateLivingConstellation : public BasicEvent class CosmicSmashDamageEvent : public BasicEvent { public: - CosmicSmashDamageEvent(Unit* caster) : _caster(caster) - { - } + CosmicSmashDamageEvent(Unit* caster) : _caster(caster) { } bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override { @@ -284,9 +270,7 @@ class CosmicSmashDamageEvent : public BasicEvent class SummonUnleashedDarkMatter : public BasicEvent { public: - SummonUnleashedDarkMatter(Unit* caster) : _caster(caster) - { - } + SummonUnleashedDarkMatter(Unit* caster) : _caster(caster) { } bool Execute(uint64 execTime, uint32 /*diff*/) override { @@ -299,1097 +283,1002 @@ class SummonUnleashedDarkMatter : public BasicEvent Unit* _caster; }; -class boss_algalon_the_observer : public CreatureScript +struct boss_algalon_the_observer : public BossAI { - public: - boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") { } - - struct boss_algalon_the_observerAI : public BossAI + boss_algalon_the_observer(Creature* creature) : BossAI(creature, BOSS_ALGALON) + { + Initialize(); + _firstPull = true; + _fedOnTears = false; + } + + void Initialize() + { + _phaseTwo = false; + _fightWon = false; + _hasYelled = false; + } + + void Reset() override + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + Initialize(); + } + + void DoAction(int32 action) override + { + switch (action) { - boss_algalon_the_observerAI(Creature* creature) : BossAI(creature, BOSS_ALGALON) + case ACTION_START_INTRO: { - Initialize(); - _firstPull = true; - _fedOnTears = false; - } + me->AddUnitFlag2(UNIT_FLAG2_INSTANTLY_APPEAR_MODEL); + me->SetDisableGravity(true); + DoCastSelf(SPELL_ARRIVAL, true); + DoCastSelf(SPELL_RIDE_THE_LIGHTNING, true); + me->SetHomePosition(AlgalonLandPos); - void Initialize() - { - _phaseTwo = false; - _fightWon = false; - _hasYelled = false; - } + Movement::MoveSplineInit init(me); + init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ(), false); + init.SetOrientationFixed(true); + me->GetMotionMaster()->LaunchMoveSpline(std::move(init), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); - void Reset() override - { - _Reset(); - me->SetReactState(REACT_PASSIVE); - Initialize(); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - { - _fedOnTears = true; - if (!_hasYelled) - { - _hasYelled = true; - events.ScheduleEvent(EVENT_UNLOCK_YELL, 1000); - Talk(SAY_ALGALON_KILL); - } - } - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_START_INTRO: - { - me->AddUnitFlag2(UNIT_FLAG2_INSTANTLY_APPEAR_MODEL); - me->SetDisableGravity(true); - DoCast(me, SPELL_ARRIVAL, true); - DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); - - me->SetHomePosition(AlgalonLandPos); - - Movement::MoveSplineInit init(me); - init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ(), false); - init.SetOrientationFixed(true); - me->GetMotionMaster()->LaunchMoveSpline(std::move(init), POINT_ALGALON_LAND, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); - - events.Reset(); - events.SetPhase(PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_1, 5000, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_2, 15000, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_3, 23000, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_FINISH, 36000, 0, PHASE_ROLE_PLAY); - break; - } - case ACTION_ASCEND: - events.SetPhase(PHASE_BIG_BANG); - events.CancelEvent(EVENT_RESUME_UPDATING); - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500); - break; - case EVENT_DESPAWN_ALGALON: - events.Reset(); - events.SetPhase(PHASE_ROLE_PLAY); - if (me->IsInCombat()) - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5000); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17000); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26000); - me->DespawnOrUnsummon(34000); - me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToNPC(true); - break; - case ACTION_INIT_ALGALON: - _firstPull = false; - me->SetImmuneToPC(false); - break; - } - } - - uint32 GetData(uint32 type) const override - { - return type == DATA_HAS_FED_ON_TEARS ? _fedOnTears : 1; - } - - void JustEngagedWith(Unit* /*target*/) override - { - uint32 introDelay = 0; - me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToNPC(true); events.Reset(); events.SetPhase(PHASE_ROLE_PLAY); - - if (!_firstPull) - { - Talk(SAY_ALGALON_AGGRO); - _JustEngagedWith(); - introDelay = 8000; - } - else - { - _firstPull = false; - Talk(SAY_ALGALON_START_TIMER); - if (Creature* brann = instance->GetCreature(DATA_BRANN_BRONZEBEARD_ALG)) - brann->AI()->DoAction(ACTION_FINISH_INTRO); - - me->setActive(true); - me->SetFarVisible(true); - DoZoneInCombat(); - introDelay = 26000; - summons.DespawnEntry(NPC_AZEROTH); - instance->SetData(EVENT_DESPAWN_ALGALON, 0); - events.ScheduleEvent(EVENT_START_COMBAT, 18000); - } - - events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); - events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay); - events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay); - events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 18000 + introDelay); - events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay); - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay); - events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay); - - std::list<Creature*> stalkers; - me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); - for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) - (*itr)->m_Events.KillAllEvents(true); - } - - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; - - if (pointId == POINT_ALGALON_LAND) - me->SetDisableGravity(false); - else if (pointId == POINT_ALGALON_OUTRO) - { - me->SetFacingTo(1.605703f); - events.ScheduleEvent(EVENT_OUTRO_3, 1200); - events.ScheduleEvent(EVENT_OUTRO_4, 2400); - events.ScheduleEvent(EVENT_OUTRO_5, 8500); - events.ScheduleEvent(EVENT_OUTRO_6, 15500); - events.ScheduleEvent(EVENT_OUTRO_7, 55500); - events.ScheduleEvent(EVENT_OUTRO_8, 73500); - events.ScheduleEvent(EVENT_OUTRO_9, 85500); - events.ScheduleEvent(EVENT_OUTRO_10, 108500); - events.ScheduleEvent(EVENT_OUTRO_11, 123500); - } - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - switch (summon->GetEntry()) - { - case NPC_AZEROTH: - DoCastAOE(SPELL_REORIGINATION, true); - break; - case NPC_COLLAPSING_STAR: - summon->SetReactState(REACT_PASSIVE); - summon->GetMotionMaster()->MoveRandom(20.0f); - summon->CastSpell(summon, SPELL_COLLAPSE, TRIGGERED_FULL_MASK); - break; - case NPC_BLACK_HOLE: - summon->SetReactState(REACT_PASSIVE); - summon->CastSpell(nullptr, SPELL_BLACK_HOLE_TRIGGER, TRIGGERED_FULL_MASK); - summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, TRIGGERED_FULL_MASK); - summon->CastSpell(nullptr, SPELL_BLACK_HOLE_EXPLOSION); - summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); - break; - case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: - summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); - break; - case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: - summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, TRIGGERED_FULL_MASK); - break; - case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: - summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(3250)); - break; - case NPC_WORM_HOLE: - summon->SetReactState(REACT_PASSIVE); - summon->CastSpell(summon, SPELL_WORM_HOLE_TRIGGER, TRIGGERED_FULL_MASK); - summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); - break; - case NPC_UNLEASHED_DARK_MATTER: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) - if (summon->Attack(target, true)) - summon->GetMotionMaster()->MoveChase(target); - break; - } + events.ScheduleEvent(EVENT_INTRO_1, 3s + 500ms, 0, PHASE_ROLE_PLAY); + break; } - - void EnterEvadeMode(EvadeReason why) override - { - instance->SetBossState(BOSS_ALGALON, FAIL); - BossAI::EnterEvadeMode(why); + case ACTION_ASCEND: + events.SetPhase(PHASE_BIG_BANG); + events.CancelEvent(EVENT_RESUME_UPDATING); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1s + 500ms); + break; + case EVENT_DESPAWN_ALGALON: + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + if (me->IsInCombat()) + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5s); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17s); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26s); + me->DespawnOrUnsummon(34s); + me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(true); + break; + case ACTION_INIT_ALGALON: + _firstPull = false; me->SetImmuneToPC(false); - me->SetSheath(SHEATH_STATE_UNARMED); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (_fightWon) - { - damage = 0; - return; - } - - if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) - { - _phaseTwo = true; - Talk(SAY_ALGALON_PHASE_TWO); - summons.DespawnEntry(NPC_LIVING_CONSTELLATION); - summons.DespawnEntry(NPC_COLLAPSING_STAR); - summons.DespawnEntry(NPC_BLACK_HOLE); - summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER); - events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR); - std::list<Creature*> stalkers; - me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); - for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) - (*itr)->m_Events.KillAllEvents(true); - for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) - if (Creature* wormHole = DoSummon(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN)) - wormHole->m_Events.AddEvent(new SummonUnleashedDarkMatter(wormHole), wormHole->m_Events.CalculateTime(i >= 2 ? 8000 : 6000)); - } - else if ((int32(me->GetHealth()) - int32(damage)) < CalculatePct<int32>(int32(me->GetMaxHealth()), 2.5f) && !_fightWon) - { - _fightWon = true; - damage = 0; - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetFaction(FACTION_FRIENDLY); - me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - DoCast(me, SPELL_SELF_STUN); - events.Reset(); - summons.DespawnAll(); - events.SetPhase(PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_OUTRO_START, 1500); - events.ScheduleEvent(EVENT_OUTRO_1, 7200); - events.ScheduleEvent(EVENT_OUTRO_2, 8700); - } - } - - void UpdateAI(uint32 diff) override - { - if (!(events.IsInPhase(PHASE_ROLE_PLAY) || events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) - return; - - events.Update(diff); - - if (!events.IsInPhase(PHASE_ROLE_PLAY)) - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_INTRO_1: - me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING); - Talk(SAY_ALGALON_INTRO_1); - break; - case EVENT_INTRO_2: - DoCastAOE(SPELL_SUMMON_AZEROTH, true); - Talk(SAY_ALGALON_INTRO_2); - break; - case EVENT_INTRO_3: - Talk(SAY_ALGALON_INTRO_3); - break; - case EVENT_INTRO_FINISH: - events.Reset(); - me->SetImmuneToPC(false); - break; - case EVENT_START_COMBAT: - instance->SetBossState(BOSS_ALGALON, IN_PROGRESS); - break; - case EVENT_INTRO_TIMER_DONE: - { - events.SetPhase(PHASE_NORMAL); - me->SetSheath(SHEATH_STATE_MELEE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToNPC(false); - me->SetReactState(REACT_DEFENSIVE); - DoCastAOE(SPELL_SUPERMASSIVE_FAIL, true); - //! Workaround for Creature::_IsTargetAcceptable returning false - //! for creatures that start combat in REACT_PASSIVE and UNIT_FLAG_NOT_SELECTABLE - //! causing them to immediately evade - if (!me->GetThreatManager().IsThreatListEmpty()) - AttackStart(me->GetThreatManager().GetCurrentVictim()); - for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i) - if (Creature* summon = DoSummon(NPC_LIVING_CONSTELLATION, ConstellationPos[i], 0, TEMPSUMMON_DEAD_DESPAWN)) - summon->SetReactState(REACT_PASSIVE); - - std::list<Creature*> stalkers; - me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); - if (!stalkers.empty()) - { - Unit* stalker = Trinity::Containers::SelectRandomContainerElement(stalkers); - stalker->m_Events.AddEvent(new ActivateLivingConstellation(stalker), stalker->m_Events.CalculateTime(urand(45000, 50000))); - } - break; - } - case EVENT_QUANTUM_STRIKE: - DoCastVictim(SPELL_QUANTUM_STRIKE); - events.ScheduleEvent(EVENT_QUANTUM_STRIKE, urand(3000, 5000)); - break; - case EVENT_PHASE_PUNCH: - DoCastVictim(SPELL_PHASE_PUNCH); - events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500); - break; - case EVENT_SUMMON_COLLAPSING_STAR: - Talk(SAY_ALGALON_COLLAPSING_STAR); - Talk(EMOTE_ALGALON_COLLAPSING_STAR); - for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) - me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_DESPAWN); - events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 60000); - break; - case EVENT_BIG_BANG: - { - Talk(SAY_ALGALON_BIG_BANG); - Talk(EMOTE_ALGALON_BIG_BANG); - events.SetPhase(PHASE_BIG_BANG); - std::list<Creature*> constellations; - me->GetCreatureListWithEntryInGrid(constellations, NPC_LIVING_CONSTELLATION, 200.0f); - for (std::list<Creature*>::iterator itr = constellations.begin(); itr != constellations.end(); ++itr) - (*itr)->AI()->DoAction(ACTION_BIG_BANG); - DoCastAOE(SPELL_BIG_BANG); - events.ScheduleEvent(EVENT_BIG_BANG, 90500); - events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500); - break; - } - case EVENT_RESUME_UPDATING: - events.SetPhase(0); - break; - case EVENT_ASCEND_TO_THE_HEAVENS: - Talk(SAY_ALGALON_ASCEND); - DoCastAOE(SPELL_ASCEND_TO_THE_HEAVENS); - events.ScheduleEvent(EVENT_EVADE, 2500); - break; - case EVENT_EVADE: - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_COSMIC_SMASH: - Talk(EMOTE_ALGALON_COSMIC_SMASH); - DoCastAOE(SPELL_COSMIC_SMASH); - events.ScheduleEvent(EVENT_COSMIC_SMASH, 25500); - break; - case EVENT_UNLOCK_YELL: - _hasYelled = false; - break; - case EVENT_OUTRO_START: - instance->SetBossState(BOSS_ALGALON, DONE); - break; - case EVENT_OUTRO_1: - me->RemoveAllAuras(); - me->AddUnitFlag(UNIT_FLAG_RENAME); - break; - case EVENT_OUTRO_2: - _EnterEvadeMode(); - me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); - break; - case EVENT_OUTRO_3: - DoCastAOE(SPELL_KILL_CREDIT); - break; - case EVENT_OUTRO_4: - DoCastAOE(SPELL_SUPERMASSIVE_FAIL); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_OUTRO_5: - if (Creature* brann = DoSummon(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], 131500, TEMPSUMMON_TIMED_DESPAWN)) - brann->AI()->DoAction(ACTION_OUTRO); - break; - case EVENT_OUTRO_6: - Talk(SAY_ALGALON_OUTRO_1); - me->SetStandState(UNIT_STAND_STATE_KNEEL); - break; - case EVENT_OUTRO_7: - Talk(SAY_ALGALON_OUTRO_2); - break; - case EVENT_OUTRO_8: - Talk(SAY_ALGALON_OUTRO_3); - break; - case EVENT_OUTRO_9: - Talk(SAY_ALGALON_OUTRO_4); - break; - case EVENT_OUTRO_10: - Talk(SAY_ALGALON_OUTRO_5); - break; - case EVENT_OUTRO_11: - me->SetStandState(UNIT_STAND_STATE_STAND); - DoCast(me, SPELL_TELEPORT); - me->DespawnOrUnsummon(1500); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_ROLE_PLAY)) - return; - } - - DoMeleeAttackIfReady(); - } - - private: - bool _firstPull; - bool _fedOnTears; - bool _phaseTwo; - bool _fightWon; - bool _hasYelled; - }; - - CreatureAI* GetAI(Creature* creature) const override + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + return type == DATA_HAS_FED_ON_TEARS ? _fedOnTears : 1; + } + + void JustEngagedWith(Unit* /*target*/) override + { + uint32 introDelay = 0; + me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(true); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + + if (!_firstPull) { - return GetUlduarAI<boss_algalon_the_observerAI>(creature); + Talk(SAY_ALGALON_AGGRO); + me->PlayDirectMusic(ENGAGE_MUSIC_ID); + _JustEngagedWith(); + introDelay = 8000; } -}; - -class npc_living_constellation : public CreatureScript -{ - public: - npc_living_constellation() : CreatureScript("npc_living_constellation") { } - - struct npc_living_constellationAI : public CreatureAI + else { - npc_living_constellationAI(Creature* creature) : CreatureAI(creature) - { - Initialize(); - } - - void Initialize() - { - _isActive = false; - } - - void Reset() override - { - _events.Reset(); - _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500); - Initialize(); - } - - uint32 GetData(uint32 /*type*/) const override - { - return _isActive ? 1 : 0; - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_ACTIVATE_STAR: - if (Creature* algalon = me->FindNearestCreature(NPC_ALGALON, 200.0f)) - { - if (Unit* target = algalon->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(algalon))) - { - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - AttackStart(target); - DoZoneInCombat(); - _isActive = true; - } - } - break; - case ACTION_BIG_BANG: - _events.SetPhase(PHASE_BIG_BANG); - _events.DelayEvents(9500); - _events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500); - break; - } - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT) - return; - - me->DespawnOrUnsummon(1); - if (InstanceScript* instance = me->GetInstanceScript()) - instance->DoStartCriteriaTimer(CriteriaStartEvent::SendEvent, EVENT_ID_SUPERMASSIVE_START); - caster->CastSpell(nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); - caster->ToCreature()->DespawnOrUnsummon(1); - } - - void UpdateAI(uint32 diff) override - { - if (!(_events.IsInPhase(PHASE_ROLE_PLAY) || _events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ARCANE_BARRAGE: - DoCastAOE(SPELL_ARCANE_BARRAGE); - _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500); - break; - case EVENT_RESUME_UPDATING: - _events.SetPhase(0); - break; - } - } - } - - private: - EventMap _events; - bool _isActive; - }; + _firstPull = false; + Talk(SAY_ALGALON_START_TIMER); + me->InterruptNonMeleeSpells(false); + me->setActive(true); + me->SetFarVisible(true); + DoZoneInCombat(); + introDelay = 26500; + summons.DespawnEntry(NPC_AZEROTH); + instance->SetData(EVENT_DESPAWN_ALGALON, 0); + events.ScheduleEvent(EVENT_START_COMBAT, 16s); + } - CreatureAI* GetAI(Creature* creature) const override + events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); + events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay); + events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay); + events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 18000 + introDelay); + events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay); + events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay); + + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) + (*itr)->m_Events.KillAllEvents(true); + } + + void MovementInform(uint32 movementType, uint32 pointId) override + { + if (movementType != POINT_MOTION_TYPE) + return; + + if (pointId == POINT_ALGALON_OUTRO) { - return GetUlduarAI<npc_living_constellationAI>(creature); + me->SetFacingTo(1.605703f); + events.ScheduleEvent(EVENT_OUTRO_3, 1s); } -}; + } -class npc_collapsing_star : public CreatureScript -{ - public: - npc_collapsing_star() : CreatureScript("npc_collapsing_star") { } - - struct npc_collapsing_starAI : public PassiveAI + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + switch (summon->GetEntry()) { - npc_collapsing_starAI(Creature* creature) : PassiveAI(creature) - { - _dying = false; - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() != NPC_BLACK_HOLE) - return; - - if (TempSummon* summ = me->ToTempSummon()) - if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) - algalon->AI()->JustSummoned(summon); - - me->DespawnOrUnsummon(1); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (_dying) - { - damage = 0; - return; - } - - if (damage >= me->GetHealth()) - { - _dying = true; - damage = 0; - DoCast(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); - DoCast(me, SPELL_SUMMON_BLACK_HOLE, true); - } - } - - bool _dying; - }; - - CreatureAI* GetAI(Creature* creature) const override + case NPC_COLLAPSING_STAR: + summon->SetReactState(REACT_PASSIVE); + summon->GetMotionMaster()->MoveRandom(20.0f); + summon->CastSpell(summon, SPELL_COLLAPSE, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: + summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: + summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, TRIGGERED_FULL_MASK); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: + summon->m_Events.AddEventAtOffset(new CosmicSmashDamageEvent(summon), 3s + 250ms); + break; + case NPC_WORM_HOLE: + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_WORM_HOLE_TRIGGER, TRIGGERED_FULL_MASK); + summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + break; + case NPC_UNLEASHED_DARK_MATTER: + DoZoneInCombat(summon); + break; + default: + break; + } + } + + void EnterEvadeMode(EvadeReason why) override + { + instance->SetBossState(BOSS_ALGALON, FAIL); + BossAI::EnterEvadeMode(why); + me->SetImmuneToPC(false); + me->SetSheath(SHEATH_STATE_UNARMED); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (_fightWon) { - return GetUlduarAI<npc_collapsing_starAI>(creature); + damage = 0; + return; } -}; -class npc_brann_bronzebeard_algalon : public CreatureScript -{ - public: - npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { } - - struct npc_brann_bronzebeard_algalonAI : public CreatureAI + if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) { - npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature) - { - _currentPoint = 0; - } + _phaseTwo = true; + Talk(SAY_ALGALON_PHASE_TWO); + summons.DespawnEntry(NPC_LIVING_CONSTELLATION); + summons.DespawnEntry(NPC_COLLAPSING_STAR); + summons.DespawnEntry(NPC_BLACK_HOLE); + summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER); + events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR); + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr) + (*itr)->m_Events.KillAllEvents(true); + for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + if (Creature* wormHole = DoSummon(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN)) + wormHole->m_Events.AddEventAtOffset(new SummonUnleashedDarkMatter(wormHole), i >= 2 ? 8s : 6s); + } + else if ((int32(me->GetHealth()) - int32(damage)) < CalculatePct<int32>(int32(me->GetMaxHealth()), 2.5f) && !_fightWon) + { + _fightWon = true; + damage = 0; + events.SetPhase(PHASE_ROLE_PLAY); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + DoCastSelf(SPELL_SELF_STUN); + events.Reset(); + summons.DespawnAll(); + events.ScheduleEvent(EVENT_OUTRO_START, 1s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_1, 7s); + } + } - void DoAction(int32 action) override + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + { + _fedOnTears = true; + if (!_hasYelled) { - switch (action) - { - case ACTION_START_INTRO: - _currentPoint = 0; - _events.Reset(); - me->SetWalk(false); - _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1); - break; - case ACTION_FINISH_INTRO: - Talk(SAY_BRANN_ALGALON_INTRO_2); - _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1); - break; - case ACTION_OUTRO: - me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]); - _events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 89500); - _events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116500); - break; - } + _hasYelled = true; + events.ScheduleEvent(EVENT_UNLOCK_YELL, 1s); + Talk(SAY_ALGALON_KILL); } + } + } - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; + void UpdateAI(uint32 diff) override + { + if (!(events.IsInPhase(PHASE_ROLE_PLAY) || events.IsInPhase(PHASE_BIG_BANG) || _fightWon) && !UpdateVictim()) + return; - uint32 delay = 1; - _currentPoint = pointId + 1; - switch (pointId) - { - case 2: - delay = 8000; - me->SetWalk(true); - break; - case 5: - me->SetWalk(false); - Talk(SAY_BRANN_ALGALON_INTRO_1); - _events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500); - return; - case 9: - me->DespawnOrUnsummon(1); - return; - case POINT_BRANN_OUTRO: - case POINT_BRANN_OUTRO_END: - return; - } + events.Update(diff); - _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); - } + if (!events.IsInPhase(PHASE_ROLE_PLAY)) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void UpdateAI(uint32 diff) override + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - UpdateVictim(); - - if (_events.Empty()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) + case EVENT_INTRO_1: + me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING); + Talk(SAY_ALGALON_INTRO_1); + events.ScheduleEvent(EVENT_SUMMON_AZEROTH, 6s, 0, PHASE_ROLE_PLAY); + break; + case EVENT_SUMMON_AZEROTH: + DoCastAOE(SPELL_SUMMON_AZEROTH, true); + if (Creature* azeroth = instance->GetCreature(DATA_AZEROTH)) + if (TempSummon* summon = azeroth->ToTempSummon()) + summon->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); + events.ScheduleEvent(EVENT_INTRO_2, 4s, 0, PHASE_ROLE_PLAY); + break; + case EVENT_INTRO_2: + me->SetDisableGravity(false); + Talk(SAY_ALGALON_INTRO_2); + DoCastAOE(SPELL_REORIGINATION, true); + events.ScheduleEvent(EVENT_INTRO_3, 8s + 500ms, 0, PHASE_ROLE_PLAY); + break; + case EVENT_INTRO_3: + Talk(SAY_ALGALON_INTRO_3); + events.ScheduleEvent(EVENT_INTRO_FINISH, 11s + 500ms, 0, PHASE_ROLE_PLAY); + break; + case EVENT_INTRO_FINISH: + events.Reset(); + me->SetImmuneToPC(false); + if (Creature* brann = instance->GetCreature(DATA_BRANN_BRONZEBEARD_ALG)) + brann->AI()->DoAction(ACTION_INTRO_2); + break; + case EVENT_START_COMBAT: + Talk(SAY_ALGALON_AGGRO); + me->PlayDirectMusic(ENGAGE_MUSIC_ID); + instance->SetBossState(BOSS_ALGALON, IN_PROGRESS); + break; + case EVENT_INTRO_TIMER_DONE: { - switch (eventId) + events.SetPhase(PHASE_NORMAL); + me->SetSheath(SHEATH_STATE_MELEE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(false); + me->SetReactState(REACT_DEFENSIVE); + DoCastAOE(SPELL_SUPERMASSIVE_FAIL, true); + //! Workaround for Creature::_IsTargetAcceptable returning false + //! for creatures that start combat in REACT_PASSIVE and UNIT_FLAG_NOT_SELECTABLE + //! causing them to immediately evade + if (!me->GetThreatManager().IsThreatListEmpty()) + AttackStart(me->GetThreatManager().GetCurrentVictim()); + for (uint8 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i) + if (Creature* summon = DoSummon(NPC_LIVING_CONSTELLATION, ConstellationPos[i], 0, TEMPSUMMON_DEAD_DESPAWN)) + summon->SetReactState(REACT_PASSIVE); + + std::list<Creature*> stalkers; + me->GetCreatureListWithEntryInGrid(stalkers, NPC_ALGALON_STALKER, 200.0f); + if (!stalkers.empty()) { - case EVENT_BRANN_MOVE_INTRO: - if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO) - me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]); - break; - case EVENT_SUMMON_ALGALON: - if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos)) - algalon->AI()->DoAction(ACTION_START_INTRO); - break; - case EVENT_BRANN_OUTRO_1: - Talk(SAY_BRANN_ALGALON_OUTRO); - break; - case EVENT_BRANN_OUTRO_2: - me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]); - break; + Unit* stalker = Trinity::Containers::SelectRandomContainerElement(stalkers); + stalker->m_Events.AddEventAtOffset(new ActivateLivingConstellation(stalker), 45s, 50s); } + break; } + case EVENT_QUANTUM_STRIKE: + DoCastVictim(SPELL_QUANTUM_STRIKE); + events.Repeat(3s, 5s); + break; + case EVENT_PHASE_PUNCH: + DoCastVictim(SPELL_PHASE_PUNCH); + events.Repeat(15s + 500ms); + break; + case EVENT_SUMMON_COLLAPSING_STAR: + Talk(SAY_ALGALON_COLLAPSING_STAR); + Talk(EMOTE_ALGALON_COLLAPSING_STAR); + for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_DESPAWN); + events.Repeat(60s); + break; + case EVENT_BIG_BANG: + { + Talk(SAY_ALGALON_BIG_BANG); + Talk(EMOTE_ALGALON_BIG_BANG); + events.SetPhase(PHASE_BIG_BANG); + std::list<Creature*> constellations; + me->GetCreatureListWithEntryInGrid(constellations, NPC_LIVING_CONSTELLATION, 200.0f); + for (std::list<Creature*>::iterator itr = constellations.begin(); itr != constellations.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_BIG_BANG); + DoCastAOE(SPELL_BIG_BANG); + events.Repeat(1min + 30s + 500ms); + events.ScheduleEvent(EVENT_RESUME_UPDATING, 9s + 500ms); + break; + } + case EVENT_RESUME_UPDATING: + events.SetPhase(PHASE_NORMAL); + break; + case EVENT_ASCEND_TO_THE_HEAVENS: + Talk(SAY_ALGALON_ASCEND); + DoCastAOE(SPELL_ASCEND_TO_THE_HEAVENS); + events.ScheduleEvent(EVENT_EVADE, 2s + 500ms); + break; + case EVENT_EVADE: + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_COSMIC_SMASH: + Talk(EMOTE_ALGALON_COSMIC_SMASH); + DoCastAOE(SPELL_COSMIC_SMASH); + events.Repeat(25s + 500ms); + break; + case EVENT_UNLOCK_YELL: + _hasYelled = false; + break; + case EVENT_OUTRO_START: + instance->SetBossState(BOSS_ALGALON, DONE); + break; + case EVENT_OUTRO_1: + me->RemoveAllAuras(); + ResetThreatList(); + me->SetFaction(FACTION_FRIENDLY); + me->AddUnitFlag(UNIT_FLAG_RENAME); + events.ScheduleEvent(EVENT_OUTRO_2, 2s); + break; + case EVENT_OUTRO_2: + me->SetRegenerateHealth(false); + me->CombatStop(); + me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); + break; + case EVENT_OUTRO_3: + DoCastAOE(SPELL_KILL_CREDIT); + events.ScheduleEvent(EVENT_OUTRO_4, 1s + 400ms); + events.ScheduleEvent(EVENT_OUTRO_5, 4s + 500ms); + break; + case EVENT_OUTRO_4: + DoCastAOE(SPELL_SUPERMASSIVE_FAIL); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_OUTRO_5: + if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos)) + brann->AI()->DoAction(ACTION_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_6, 10s); + break; + case EVENT_OUTRO_6: + Talk(SAY_ALGALON_OUTRO_1); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + events.ScheduleEvent(EVENT_OUTRO_7, 39s); + break; + case EVENT_OUTRO_7: + Talk(SAY_ALGALON_OUTRO_2); + events.ScheduleEvent(EVENT_OUTRO_8, 18s); + break; + case EVENT_OUTRO_8: + Talk(SAY_ALGALON_OUTRO_3); + events.ScheduleEvent(EVENT_OUTRO_9, 12s); + break; + case EVENT_OUTRO_9: + Talk(SAY_ALGALON_OUTRO_4); + events.ScheduleEvent(EVENT_OUTRO_10, 24s); + break; + case EVENT_OUTRO_10: + Talk(SAY_ALGALON_OUTRO_5); + events.ScheduleEvent(EVENT_OUTRO_11, 15s); + break; + case EVENT_OUTRO_11: + me->SetStandState(UNIT_STAND_STATE_STAND); + DoCastSelf(SPELL_TELEPORT); + me->DespawnOrUnsummon(1s + 200ms); + break; + case EVENT_DESPAWN_ALGALON_1: + Talk(SAY_ALGALON_DESPAWN_1); + break; + case EVENT_DESPAWN_ALGALON_2: + Talk(SAY_ALGALON_DESPAWN_2); + break; + case EVENT_DESPAWN_ALGALON_3: + Talk(SAY_ALGALON_DESPAWN_3); + break; + default: + break; } - private: - EventMap _events; - uint32 _currentPoint; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_brann_bronzebeard_algalonAI>(creature); + if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_ROLE_PLAY)) + return; } + + DoMeleeAttackIfReady(); + } + +private: + bool _firstPull; + bool _fedOnTears; + bool _phaseTwo; + bool _fightWon; + bool _hasYelled; }; -class go_celestial_planetarium_access : public GameObjectScript +struct npc_living_constellation : public CreatureAI { - public: - go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") { } - - struct go_celestial_planetarium_accessAI : public GameObjectAI + npc_living_constellation(Creature* creature) : CreatureAI(creature), _instance(creature->GetInstanceScript()) + { + Initialize(); + } + + void Initialize() + { + _isActive = false; + } + + void Reset() override + { + _events.Reset(); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2s + 500ms); + Initialize(); + } + + uint32 GetData(uint32 /*type*/) const override + { + return _isActive ? 1 : 0; + } + + void DoAction(int32 action) override + { + switch (action) { - go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } - - InstanceScript* instance; - - bool OnReportUse(Player* player) override - { - if (me->HasFlag(GO_FLAG_IN_USE)) - return true; - - bool hasKey = true; - if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->GetLockId())) + case ACTION_ACTIVATE_STAR: + if (Creature* algalon = _instance->GetCreature(BOSS_ALGALON)) { - hasKey = false; - for (uint32 i = 0; i < MAX_LOCK_CASE; ++i) + if (Unit* target = algalon->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(algalon))) { - if (!lock->Index[i]) - continue; - - if (player->HasItemCount(lock->Index[i])) - { - hasKey = true; - break; - } + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + AttackStart(target); + DoZoneInCombat(); + _isActive = true; } } + break; + case ACTION_BIG_BANG: + _events.SetPhase(PHASE_BIG_BANG); + _events.DelayEvents(9s + 500ms); + _events.ScheduleEvent(EVENT_RESUME_UPDATING, 9s + 500ms); + break; + default: + break; + } + } - if (!hasKey) - return false; + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT) + return; - // Start Algalon event - me->AddFlag(GO_FLAG_IN_USE); - _events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000); - if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos)) - brann->AI()->DoAction(ACTION_START_INTRO); + _instance->DoStartCriteriaTimer(CriteriaStartEvent::SendEvent, EVENT_ID_SUPERMASSIVE_START); + caster->CastSpell(nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); + DoCast(caster, SPELL_DESPAWN_BLACK_HOLE, TRIGGERED_FULL_MASK); + me->DespawnOrUnsummon(500ms); + } - instance->SetData(DATA_ALGALON_SUMMON_STATE, 1); - if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SIGILDOOR_01))) - sigil->SetGoState(GO_STATE_ACTIVE); + void UpdateAI(uint32 diff) override + { + if (!(_events.IsInPhase(PHASE_ROLE_PLAY) || _events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) + return; - if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SIGILDOOR_02))) - sigil->SetGoState(GO_STATE_ACTIVE); + _events.Update(diff); - return false; - } - - void UpdateAI(uint32 diff) override + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - if (_events.Empty()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) + case EVENT_ARCANE_BARRAGE: { - switch (eventId) - { - case EVENT_DESPAWN_CONSOLE: - me->Delete(); - break; - } + DoCastAOE(SPELL_ARCANE_BARRAGE, { SPELLVALUE_MAX_TARGETS, 1 }); + me->ClearUnitState(UNIT_STATE_CASTING); + _events.Repeat(4s, 5s); + break; } + case EVENT_RESUME_UPDATING: + _events.SetPhase(PHASE_NORMAL); + break; } - - EventMap _events; - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetUlduarAI<go_celestial_planetarium_accessAI>(go); } -}; + } -class spell_algalon_phase_punch : public SpellScriptLoader -{ - public: - spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { } - - class spell_algalon_phase_punch_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_phase_punch_AuraScript); - - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - if (GetStackAmount() != 1) - GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]); - GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK); - if (GetStackAmount() == 5) - Remove(AURA_REMOVE_BY_DEFAULT); - } - - void OnRemove(AuraEffect const*, AuraEffectHandleModes) - { - if (GetStackAmount() != 5) - GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_phase_punch_AuraScript(); - } +private: + EventMap _events; + bool _isActive; + InstanceScript* _instance; }; -class NotVictimFilter +struct npc_black_hole : public ScriptedAI { - public: - NotVictimFilter(Unit* caster) : _victim(caster->GetVictim()) + npc_black_hole(Creature* creature) : ScriptedAI(creature), _summons(creature) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + DoCastAOE(SPELL_BLACK_HOLE_TRIGGER, TRIGGERED_FULL_MASK); + DoCastSelf(SPELL_CONSTELLATION_PHASE_TRIGGER, TRIGGERED_FULL_MASK); + DoCastAOE(SPELL_BLACK_HOLE_EXPLOSION, TRIGGERED_FULL_MASK); + DoCastSelf(SPELL_SUMMON_VOID_ZONE_VISUAL, TRIGGERED_FULL_MASK); + } + + void JustSummoned(Creature* summon) override + { + _summons.Summon(summon); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_DESPAWN_BLACK_HOLE) { + _summons.DespawnAll(); + me->DespawnOrUnsummon(1); } + } - bool operator()(WorldObject* target) - { - return target != _victim; - } + void EnterEvadeMode(EvadeReason /*why*/) override { } - private: - Unit* _victim; +private: + SummonList _summons; }; -class spell_algalon_arcane_barrage : public SpellScriptLoader +struct npc_collapsing_star : public PassiveAI { - public: - spell_algalon_arcane_barrage() : SpellScriptLoader("spell_algalon_arcane_barrage") { } + npc_collapsing_star(Creature* creature) : PassiveAI(creature), _dying(false), _instance(creature->GetInstanceScript()) { } - class spell_algalon_arcane_barrage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_arcane_barrage_SpellScript); + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_BLACK_HOLE) + return; - void SelectTarget(std::list<WorldObject*>& targets) - { - targets.remove_if(NotVictimFilter(GetCaster())); - } + if (Creature* algalon = _instance->GetCreature(BOSS_ALGALON)) + algalon->AI()->JustSummoned(summon); - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_arcane_barrage_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; + me->DespawnOrUnsummon(1); + } - SpellScript* GetSpellScript() const override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (_dying) { - return new spell_algalon_arcane_barrage_SpellScript(); + damage = 0; + return; } -}; -class ActiveConstellationFilter -{ - public: - bool operator()(WorldObject* target) const + if (damage >= me->GetHealth()) { - return target->ToUnit() && target->ToUnit()->GetAI() && target->ToUnit()->GetAI()->GetData(0); + _dying = true; + damage = 0; + DoCastSelf(SPELL_BLACK_HOLE_SPAWN_VISUAL, true); + DoCastSelf(SPELL_SUMMON_BLACK_HOLE, true); } + } + +private: + bool _dying; + InstanceScript* _instance; }; -class spell_algalon_trigger_3_adds : public SpellScriptLoader +struct npc_brann_bronzebeard_algalon : public CreatureAI { - public: - spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { } + npc_brann_bronzebeard_algalon(Creature* creature) : CreatureAI(creature) { } - class spell_algalon_trigger_3_adds_SpellScript : public SpellScript + void DoAction(int32 action) override + { + switch (action) { - PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript); - - void SelectTarget(std::list<WorldObject*>& targets) - { - targets.remove_if(ActiveConstellationFilter()); - } - - void HandleDummy(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Creature* target = GetHitCreature(); - if (!target) - return; - - target->AI()->DoAction(ACTION_ACTIVATE_STAR); - } + case ACTION_START_INTRO: + _events.Reset(); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_INITIAL_MOVE, SPLINE_INITIAL_MOVE, false); + break; + case ACTION_OUTRO: + me->GetMotionMaster()->MoveAlongSplineChain(0, SPLINE_OUTRO_1, false); + _events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 1min + 32s + 200ms); + _events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 2min); + break; + case ACTION_INTRO_2: + Talk(SAY_BRANN_ALGALON_INTRO_2); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_DESPAWN, SPLINE_DESPAWN_INTRO_1, true); + break; + default: + break; + } + } - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE) + return; - SpellScript* GetSpellScript() const override + switch (pointId) { - return new spell_algalon_trigger_3_adds_SpellScript(); + case POINT_INITIAL_MOVE: + _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 4s); + break; + case POINT_ALGALON_ROOM: + me->SetFacingTo(4.714909f); + _events.ScheduleEvent(EVENT_BRANN_SAY_INTRO_1, 500ms); + break; + case POINT_DESPAWN: + me->DespawnOrUnsummon(); + break; + default: + break; } -}; + } -class spell_algalon_collapse : public SpellScriptLoader -{ - public: - spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { } - - class spell_algalon_collapse_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_collapse_AuraScript); + void UpdateAI(uint32 diff) override + { + if (_events.Empty()) + return; - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); - } + _events.Update(diff); - void Register() override + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + case EVENT_BRANN_MOVE_INTRO: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_ALGALON_ROOM, SPLINE_ALGALON_ROOM, true); + break; + case EVENT_BRANN_SAY_INTRO_1: + Talk(SAY_BRANN_ALGALON_INTRO_1); + _events.ScheduleEvent(EVENT_SUMMON_ALGALON, 8s + 300ms); + break; + case EVENT_SUMMON_ALGALON: + if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos)) + algalon->AI()->DoAction(ACTION_START_INTRO); + break; + case EVENT_BRANN_OUTRO_1: + Talk(SAY_BRANN_ALGALON_OUTRO); + break; + case EVENT_BRANN_OUTRO_2: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_DESPAWN, SPLINE_OUTRO_2, false); + break; + default: + break; } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_collapse_AuraScript(); } + } + +private: + EventMap _events; }; -class spell_algalon_big_bang : public SpellScriptLoader +struct go_celestial_planetarium_access : public GameObjectAI { - public: - spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { } + go_celestial_planetarium_access(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { } - class spell_algalon_big_bang_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_big_bang_SpellScript); + bool OnReportUse(Player* player) override + { + if (me->HasFlag(GO_FLAG_IN_USE)) + return true; - public: - spell_algalon_big_bang_SpellScript() + bool hasKey = true; + if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->GetLockId())) + { + hasKey = false; + for (uint8 i = 0; i < MAX_LOCK_CASE; ++i) { - _targetCount = 0; - } + if (!lock->Index[i]) + continue; - private: - bool Load() override - { - return GetCaster()->GetTypeId() == TYPEID_UNIT; - } - - void CountTargets(std::list<WorldObject*>& targets) - { - _targetCount = targets.size(); + if (player->HasItemCount(lock->Index[i])) + { + hasKey = true; + break; + } } + } - void CheckTargets() - { - if (!_targetCount) - GetCaster()->GetAI()->DoAction(ACTION_ASCEND); - } + if (!hasKey) + return false; - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets); - } + // Start Algalon event + me->AddFlag(GO_FLAG_IN_USE); + _events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000); + if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos)) + brann->AI()->DoAction(ACTION_START_INTRO); - uint32 _targetCount; - }; + _instance->SetData(DATA_ALGALON_SUMMON_STATE, 1); + if (GameObject* sigil = _instance->GetGameObject(DATA_SIGILDOOR_01)) + sigil->SetGoState(GO_STATE_ACTIVE); - SpellScript* GetSpellScript() const override - { - return new spell_algalon_big_bang_SpellScript(); - } -}; + if (GameObject* sigil = _instance->GetGameObject(DATA_SIGILDOOR_02)) + sigil->SetGoState(GO_STATE_ACTIVE); -class spell_algalon_remove_phase : public SpellScriptLoader -{ - public: - spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { } + return false; + } - class spell_algalon_remove_phase_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_remove_phase_AuraScript); + void UpdateAI(uint32 diff) override + { + if (_events.Empty()) + return; - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE); - } + _events.Update(diff); - void Register() override + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + case EVENT_DESPAWN_CONSOLE: + me->Delete(); + break; + default: + break; } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_remove_phase_AuraScript(); } + } + +private: + EventMap _events; + InstanceScript* _instance; }; -// 62295 - Cosmic Smash -class spell_algalon_cosmic_smash : public SpellScriptLoader +// 64412 - Phase Punch +class spell_algalon_phase_punch : public AuraScript { - public: - spell_algalon_cosmic_smash() : SpellScriptLoader("spell_algalon_cosmic_smash") { } - - class spell_algalon_cosmic_smash_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_cosmic_smash_SpellScript); - - void ModDestHeight(SpellDestination& dest) - { - Position const offset = { 0.0f, 0.0f, 65.0f, 0.0f }; - dest.RelocateOffset(offset); - } - - void Register() override - { - OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_algalon_cosmic_smash_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_SUMMON); - } - }; + PrepareAuraScript(spell_algalon_phase_punch); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (GetStackAmount() != 1) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]); + GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK); + if (GetStackAmount() == 5) + Remove(AURA_REMOVE_BY_DEFAULT); + } + + void OnRemove(AuraEffect const*, AuraEffectHandleModes) + { + if (GetStackAmount() != 5) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; - SpellScript* GetSpellScript() const override - { - return new spell_algalon_cosmic_smash_SpellScript(); - } +// 65508 - Constellation Phase Trigger +class spell_algalon_phase_constellation : public AuraScript +{ + PrepareAuraScript(spell_algalon_phase_constellation); + + bool Validate(SpellInfo const* spellInfo) override + { + return !spellInfo->GetEffects().empty() && ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + } + + void HandlePeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + CastSpellExtraArgs args(aurEff); + args.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); + // Phase Effect should only 1 target. Avoid 1 black hole despawn multiple Living Constellation + GetTarget()->CastSpell(nullptr, GetSpellInfo()->GetEffect(EFFECT_0).TriggerSpell, args); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_constellation::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; -class spell_algalon_cosmic_smash_damage : public SpellScriptLoader +// 62266 - Trigger 3 Adds +class spell_algalon_trigger_3_adds : public SpellScript { - public: - spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { } + PrepareSpellScript(spell_algalon_trigger_3_adds); - class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript + void SelectTarget(std::list<WorldObject*>& targets) + { + // Remove Living Constellation already actived + targets.remove_if([](WorldObject* target) -> bool { - PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript); - - void RecalculateDamage() - { - if (!GetExplTargetDest() || !GetHitUnit()) - return; - - float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY()); - if (distance > 6.0f) - SetHitDamage(int32(float(GetHitDamage()) / distance) * 2); - } - - void Register() override - { - OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage); - } - }; + return target->ToUnit() && target->ToUnit()->GetAI() && target->ToUnit()->GetAI()->GetData(0); + }); + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Creature* target = GetHitCreature()) + target->AI()->DoAction(ACTION_ACTIVATE_STAR); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; - SpellScript* GetSpellScript() const override - { - return new spell_algalon_cosmic_smash_damage_SpellScript(); - } +// 62018 - Collapse +class spell_algalon_collapse : public AuraScript +{ + PrepareAuraScript(spell_algalon_collapse); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } }; -class spell_algalon_supermassive_fail : public SpellScriptLoader +// 64443, 64584 - Big Bang +class spell_algalon_big_bang : public SpellScript { - public: - spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { } + PrepareSpellScript(spell_algalon_big_bang); + + bool Load() override + { + _targetCount = 0; + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void CountTargets(std::list<WorldObject*>& targets) + { + _targetCount = targets.size(); + } + + void CheckTargets() + { + if (!_targetCount) + GetCaster()->GetAI()->DoAction(ACTION_ASCEND); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + AfterCast += SpellCastFn(spell_algalon_big_bang::CheckTargets); + } +private: + uint32 _targetCount; +}; - class spell_algalon_supermassive_fail_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript); +// 64445 - Remove Player from Phase +class spell_algalon_remove_phase : public AuraScript +{ + PrepareAuraScript(spell_algalon_remove_phase); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; - void RecalculateDamage() - { - if (!GetHitPlayer()) - return; +// 62295 - Cosmic Smash +class spell_algalon_cosmic_smash : public SpellScript +{ + PrepareSpellScript(spell_algalon_cosmic_smash); + + void ModDestHeight(SpellDestination& dest) + { + // Meteor should spawn below the platform + Position const offset = { 0.0f, 0.0f, -36.1325f, 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_algalon_cosmic_smash::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_SUMMON); + } +}; - GetHitPlayer()->ResetCriteria(CriteriaFailEvent::BeSpellTarget, GetSpellInfo()->Id, true); - } +// 62311, 64596 - Cosmic Smash +class spell_algalon_cosmic_smash_damage : public SpellScript +{ + PrepareSpellScript(spell_algalon_cosmic_smash_damage); + + void RecalculateDamage() + { + if (!GetExplTargetDest() || !GetHitUnit()) + return; + + float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY()); + if (distance > 6.0f) + SetHitDamage(int32(float(GetHitDamage()) / distance) * 2); + } + + void Register() override + { + OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage::RecalculateDamage); + } +}; - void Register() override - { - OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage); - } - }; +// 65311 - Supermassive Fail +class spell_algalon_supermassive_fail : public SpellScript +{ + PrepareSpellScript(spell_algalon_supermassive_fail); + + void RecalculateDamage() + { + if (Player* player = GetHitPlayer()) + player->ResetCriteria(CriteriaFailEvent::BeSpellTarget, GetSpellInfo()->Id, true); + } + + void Register() override + { + OnHit += SpellHitFn(spell_algalon_supermassive_fail::RecalculateDamage); + } +}; - SpellScript* GetSpellScript() const override - { - return new spell_algalon_supermassive_fail_SpellScript(); - } +// 62168 - Black Hole (Phase Shifts) +// 65250 - Worm Hole (Phase Shifts) +// 64417 - Phase Punch (Phase Shifts) +class spell_algalon_black_hole_phase_shifts : public AuraScript +{ + PrepareAuraScript(spell_algalon_black_hole_phase_shifts); + + bool Load() override + { + return GetUnitOwner()->GetTypeId() == TYPEID_PLAYER; + } + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLACK_HOLE_DOT }); + } + + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_BLACK_HOLE_DOT, true); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_algalon_black_hole_phase_shifts::HandleEffectApply, EFFECT_0, SPELL_AURA_PHASE, AURA_EFFECT_HANDLE_REAL); + } }; void AddSC_boss_algalon_the_observer() { - new boss_algalon_the_observer(); - new npc_living_constellation(); - new npc_collapsing_star(); - new npc_brann_bronzebeard_algalon(); - new go_celestial_planetarium_access(); - new spell_algalon_phase_punch(); - new spell_algalon_arcane_barrage(); - new spell_algalon_trigger_3_adds(); - new spell_algalon_collapse(); - new spell_algalon_big_bang(); - new spell_algalon_remove_phase(); - new spell_algalon_cosmic_smash(); - new spell_algalon_cosmic_smash_damage(); - new spell_algalon_supermassive_fail(); + RegisterUlduarCreatureAI(boss_algalon_the_observer); + RegisterUlduarCreatureAI(npc_living_constellation); + RegisterUlduarCreatureAI(npc_black_hole); + RegisterUlduarCreatureAI(npc_collapsing_star); + RegisterUlduarCreatureAI(npc_brann_bronzebeard_algalon); + RegisterGameObjectAI(go_celestial_planetarium_access); + RegisterAuraScript(spell_algalon_phase_punch); + RegisterAuraScript(spell_algalon_phase_constellation); + RegisterSpellScript(spell_algalon_trigger_3_adds); + RegisterAuraScript(spell_algalon_collapse); + RegisterSpellScript(spell_algalon_big_bang); + RegisterAuraScript(spell_algalon_remove_phase); + RegisterSpellScript(spell_algalon_cosmic_smash); + RegisterSpellScript(spell_algalon_cosmic_smash_damage); + RegisterSpellScript(spell_algalon_supermassive_fail); + RegisterAuraScript(spell_algalon_black_hole_phase_shifts); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index c34a889f1d4..5d064f9b2ed 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -116,23 +116,31 @@ ObjectData const creatureData[] = { NPC_HIGH_EXPLORER_DELLORAH, DATA_DELLORAH }, { NPC_BRONZEBEARD_RADIO, DATA_BRONZEBEARD_RADIO }, { NPC_HEART_OF_DECONSTRUCTOR, DATA_XT002_HEART }, + { NPC_AZEROTH, DATA_AZEROTH }, { 0, 0, } }; ObjectData const objectData[] = { - { GO_MIMIRON_ELEVATOR, DATA_MIMIRON_ELEVATOR }, - { GO_MIMIRON_BUTTON, DATA_MIMIRON_BUTTON }, - { GO_DOODAD_UL_UNIVERSEGLOBE01, DATA_UNIVERSE_GLOBE }, - { GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, DATA_ALGALON_TRAPDOOR }, - { GO_RAZOR_HARPOON_1, GO_RAZOR_HARPOON_1 }, - { GO_RAZOR_HARPOON_2, GO_RAZOR_HARPOON_2 }, - { GO_RAZOR_HARPOON_3, GO_RAZOR_HARPOON_3 }, - { GO_RAZOR_HARPOON_4, GO_RAZOR_HARPOON_4 }, - { GO_THORIM_LEVER, DATA_THORIM_LEVER }, - { GO_THORIM_STONE_DOOR, DATA_STONE_DOOR }, - { GO_THORIM_RUNIC_DOOR, DATA_RUNIC_DOOR }, - { 0, 0 } + { GO_MIMIRON_ELEVATOR, DATA_MIMIRON_ELEVATOR }, + { GO_MIMIRON_BUTTON, DATA_MIMIRON_BUTTON }, + { GO_DOODAD_UL_UNIVERSEGLOBE01, DATA_UNIVERSE_GLOBE }, + { GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, DATA_ALGALON_TRAPDOOR }, + { GO_RAZOR_HARPOON_1, GO_RAZOR_HARPOON_1 }, + { GO_RAZOR_HARPOON_2, GO_RAZOR_HARPOON_2 }, + { GO_RAZOR_HARPOON_3, GO_RAZOR_HARPOON_3 }, + { GO_RAZOR_HARPOON_4, GO_RAZOR_HARPOON_4 }, + { GO_THORIM_LEVER, DATA_THORIM_LEVER }, + { GO_THORIM_STONE_DOOR, DATA_STONE_DOOR }, + { GO_THORIM_RUNIC_DOOR, DATA_RUNIC_DOOR }, + { GO_DOODAD_UL_SIGILDOOR_01, DATA_SIGILDOOR_01 }, + { GO_DOODAD_UL_SIGILDOOR_02, DATA_SIGILDOOR_02 }, + { GO_DOODAD_UL_SIGILDOOR_03, DATA_SIGILDOOR_03 }, + { GO_DOODAD_UL_UNIVERSEFLOOR_01, DATA_UNIVERSE_FLOOR_01 }, + { GO_DOODAD_UL_UNIVERSEFLOOR_02, DATA_UNIVERSE_FLOOR_02 }, + { GO_GIFT_OF_THE_OBSERVER_10, DATA_GIFT_OF_THE_OBSERVER }, + { GO_GIFT_OF_THE_OBSERVER_25, DATA_GIFT_OF_THE_OBSERVER }, + { 0, 0 } }; class instance_ulduar : public InstanceMapScript @@ -195,10 +203,6 @@ class instance_ulduar : public InstanceMapScript ObjectGuid MimironTramGUID; ObjectGuid BrainRoomDoorGUIDs[3]; - ObjectGuid AlgalonSigilDoorGUID[3]; - ObjectGuid AlgalonFloorGUID[2]; - - ObjectGuid GiftOfTheObserverGUID; // Miscellaneous uint32 TeamInInstance; @@ -270,14 +274,6 @@ class instance_ulduar : public InstanceMapScript { InstanceScript::OnCreatureCreate(creature); - if (!TeamInInstance) - { - Map::PlayerList const& Players = instance->GetPlayers(); - if (!Players.isEmpty()) - if (Player* player = Players.begin()->GetSource()) - TeamInInstance = player->GetTeam(); - } - switch (creature->GetEntry()) { case NPC_SALVAGED_DEMOLISHER: @@ -315,50 +311,6 @@ class instance_ulduar : public InstanceMapScript AddMinion(creature, true); break; - // Hodir - case NPC_EIVI_NIGHTFEATHER: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_TOR_GREYCLOUD); - break; - case NPC_ELLIE_NIGHTFEATHER: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_KAR_GREYCLOUD); - break; - case NPC_ELEMENTALIST_MAHFUUN: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_SPIRITWALKER_TARA); - break; - case NPC_ELEMENTALIST_AVUUN: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_SPIRITWALKER_YONA); - break; - case NPC_MISSY_FLAMECUFFS: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_AMIRA_BLAZEWEAVER); - break; - case NPC_SISSY_FLAMECUFFS: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_VEESHA_BLAZEWEAVER); - break; - case NPC_FIELD_MEDIC_PENNY: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_BATTLE_PRIEST_ELIZA); - break; - case NPC_FIELD_MEDIC_JESSI: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA); - break; - - // Thorim - case NPC_MERCENARY_CAPTAIN_H: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_MERCENARY_CAPTAIN_A); - break; - case NPC_MERCENARY_SOLDIER_H: - if (TeamInInstance == HORDE) - creature->UpdateEntry(NPC_MERCENARY_SOLDIER_A); - break; - // Freya case NPC_IRONBRANCH: ElderGUIDs[0] = creature->GetGUID(); @@ -435,6 +387,44 @@ class instance_ulduar : public InstanceMapScript InstanceScript::OnCreatureCreate(creature); } + uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override + { + if (!TeamInInstance) + { + Map::PlayerList const& Players = instance->GetPlayers(); + if (!Players.isEmpty()) + if (Player* player = Players.begin()->GetSource()) + TeamInInstance = player->GetTeam(); + } + + uint32 entry = data->id; + switch (entry) + { + case NPC_EIVI_NIGHTFEATHER: + return TeamInInstance == HORDE ? NPC_TOR_GREYCLOUD : NPC_EIVI_NIGHTFEATHER; + case NPC_ELLIE_NIGHTFEATHER: + return TeamInInstance == HORDE ? NPC_KAR_GREYCLOUD : NPC_ELLIE_NIGHTFEATHER; + case NPC_ELEMENTALIST_MAHFUUN: + return TeamInInstance == HORDE ? NPC_SPIRITWALKER_TARA : NPC_ELEMENTALIST_MAHFUUN; + case NPC_ELEMENTALIST_AVUUN: + return TeamInInstance == HORDE ? NPC_SPIRITWALKER_YONA : NPC_ELEMENTALIST_AVUUN; + case NPC_MISSY_FLAMECUFFS: + return TeamInInstance == HORDE ? NPC_AMIRA_BLAZEWEAVER : NPC_MISSY_FLAMECUFFS; + case NPC_SISSY_FLAMECUFFS: + return TeamInInstance == HORDE ? NPC_VEESHA_BLAZEWEAVER : NPC_SISSY_FLAMECUFFS; + case NPC_FIELD_MEDIC_PENNY: + return TeamInInstance == HORDE ? NPC_BATTLE_PRIEST_ELIZA : NPC_FIELD_MEDIC_PENNY; + case NPC_FIELD_MEDIC_JESSI: + return TeamInInstance == HORDE ? NPC_BATTLE_PRIEST_GINA : NPC_FIELD_MEDIC_JESSI; + case NPC_MERCENARY_CAPTAIN_H: + return TeamInInstance == HORDE ? NPC_MERCENARY_CAPTAIN_A : NPC_MERCENARY_CAPTAIN_H; + case NPC_MERCENARY_SOLDIER_H: + return TeamInInstance == HORDE ? NPC_MERCENARY_SOLDIER_A : NPC_MERCENARY_SOLDIER_H; + default: + return entry; + } + } + void OnCreatureRemove(Creature* creature) override { InstanceScript::OnCreatureRemove(creature); @@ -518,28 +508,10 @@ class instance_ulduar : public InstanceMapScript gameObject->AddFlag(GO_FLAG_IN_USE); break; case GO_DOODAD_UL_SIGILDOOR_01: - AlgalonSigilDoorGUID[0] = gameObject->GetGUID(); - if (_algalonSummoned) - gameObject->SetGoState(GO_STATE_ACTIVE); - break; case GO_DOODAD_UL_SIGILDOOR_02: - AlgalonSigilDoorGUID[1] = gameObject->GetGUID(); if (_algalonSummoned) gameObject->SetGoState(GO_STATE_ACTIVE); break; - case GO_DOODAD_UL_SIGILDOOR_03: - AlgalonSigilDoorGUID[2] = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_UNIVERSEFLOOR_01: - AlgalonFloorGUID[0] = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_UNIVERSEFLOOR_02: - AlgalonFloorGUID[1] = gameObject->GetGUID(); - break; - case GO_GIFT_OF_THE_OBSERVER_10: - case GO_GIFT_OF_THE_OBSERVER_25: - GiftOfTheObserverGUID = gameObject->GetGUID(); - break; default: break; } @@ -715,8 +687,8 @@ class instance_ulduar : public InstanceMapScript _events.CancelEvent(EVENT_DESPAWN_ALGALON); DoUpdateWorldState(WORLD_STATE_ALGALON_TIMER_ENABLED, 0); _algalonTimer = 61; - if (GameObject* gameObject = instance->GetGameObject(GiftOfTheObserverGUID)) - gameObject->SetRespawnTime(gameObject->GetRespawnDelay()); + if (GameObject* gift = GetGameObject(DATA_GIFT_OF_THE_OBSERVER)) + gift->SetRespawnTime(gift->GetRespawnDelay()); // get item level (recheck weapons) Map::PlayerList const& players = instance->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) @@ -858,18 +830,6 @@ class instance_ulduar : public InstanceMapScript return KeeperGUIDs[2]; case DATA_MIMIRON_YS: return KeeperGUIDs[3]; - - // Algalon - case DATA_SIGILDOOR_01: - return AlgalonSigilDoorGUID[0]; - case DATA_SIGILDOOR_02: - return AlgalonSigilDoorGUID[1]; - case DATA_SIGILDOOR_03: - return AlgalonSigilDoorGUID[2]; - case DATA_UNIVERSE_FLOOR_01: - return AlgalonFloorGUID[0]; - case DATA_UNIVERSE_FLOOR_02: - return AlgalonFloorGUID[1]; } return InstanceScript::GetGuidData(data); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 1e6e77b6c71..d332dad74a4 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -452,6 +452,8 @@ enum UlduarData DATA_UNIVERSE_GLOBE, DATA_ALGALON_TRAPDOOR, DATA_BRANN_BRONZEBEARD_ALG, + DATA_GIFT_OF_THE_OBSERVER, + DATA_AZEROTH, // Thorim DATA_SIF, |