From 3b2ef0ec457dd6eccdc58fe63cc399b4ef268534 Mon Sep 17 00:00:00 2001 From: Keader Date: Thu, 5 Nov 2020 17:42:33 +0100 Subject: [PATCH] Scripts/BT: full instance rewrite --- .../world/4.3.4/2020_11_05_00_world.sql | 892 ++++ src/server/game/Spells/SpellInfo.cpp | 2 + src/server/game/Spells/SpellMgr.cpp | 12 + .../Outland/BlackTemple/black_temple.cpp | 392 +- .../Outland/BlackTemple/black_temple.h | 12 +- .../BlackTemple/boss_gurtogg_bloodboil.cpp | 499 ++- .../Outland/BlackTemple/boss_illidan.cpp | 3574 ++++++++--------- .../BlackTemple/boss_illidari_council.cpp | 1161 +++--- .../BlackTemple/boss_mother_shahraz.cpp | 427 +- .../BlackTemple/boss_reliquary_of_souls.cpp | 1309 +++--- .../BlackTemple/boss_shade_of_akama.cpp | 1819 ++++----- .../Outland/BlackTemple/boss_supremus.cpp | 281 +- .../BlackTemple/boss_teron_gorefiend.cpp | 616 ++- .../BlackTemple/boss_warlord_najentus.cpp | 351 +- .../BlackTemple/instance_black_temple.cpp | 1 + 15 files changed, 5754 insertions(+), 5594 deletions(-) create mode 100644 sql/updates/world/4.3.4/2020_11_05_00_world.sql diff --git a/sql/updates/world/4.3.4/2020_11_05_00_world.sql b/sql/updates/world/4.3.4/2020_11_05_00_world.sql new file mode 100644 index 0000000000..f02273adbf --- /dev/null +++ b/sql/updates/world/4.3.4/2020_11_05_00_world.sql @@ -0,0 +1,892 @@ +-- +DELETE FROM `creature_summon_groups` WHERE `summonerId`=22841; -- Shade of Akama +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(22841,0,1,23421,443.495,413.973,118.621,5.13127 ,6,6000),-- Ashtongue Channeler +(22841,0,1,23421,456.694,414.117,118.621,4.2586 ,6,6000), +(22841,0,1,23421,457.763,390.117,118.621,2.25148 ,6,6000), +(22841,0,1,23421,444.153,389.214,118.621,1.0821 ,6,6000), +(22841,0,1,23421,438.279,401.258,118.621,0.017453,6,6000), +(22841,0,1,23421,463.186,401.64 ,118.621,3.19395 ,6,6000), +(22841,0,1,23191,547.186,400.534,112.867,3.12414 ,8, 0); -- Akama + +DELETE FROM `creature` WHERE `id` IN (23191,23421); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_shade_soul_channel_serverside','spell_shade_soul_channel'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(40401,'spell_shade_soul_channel_serverside'), +(40520,'spell_shade_soul_channel'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40902; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,2,40902,0,1,31,0,3,22841,0,0,0,0,'','Effect_1 - Hits Shade of Akama'), +(13,4,40902,0,2,31,0,3,23351,0,0,0,0,'','Effect_2 - Hits Trigger'); + +UPDATE `creature_template` SET `mechanic_immune_mask`=618610687 WHERE `entry`=23215; -- Ashtongue Sorcerer Immunity +UPDATE `creature_template` SET `ScriptName`='npc_ashtongue_broken' WHERE `entry`=23319; +UPDATE `creature_template` SET `speed_run`=0.571429 WHERE `entry`=22841; + +DELETE FROM `creature_text` WHERE `CreatureID`=23191 AND `groupid` IN (3,4); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23191,3,0,'I will not last much longer!',14,0,100,0,0,11385,21784,0,'Akama SAY_LOW_HEALTH'), +(23191,4,0,'No! Not yet!',14,0,100,0,0,11386,21785,0,'Akama SAY_DEAD'); + +-- Waypoints + +-- Middle Creatures +SET @NPC := 12806; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=489.6115,`position_y`=407.0968,`position_z`=112.7839 WHERE `guid`=@NPC; +UPDATE `creature` SET `MovementType`=0, `spawndist`=0 WHERE `guid`=12805; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`waypointPathId`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES +(@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,489.6115,407.0968,112.7839,0,0,0,0,100,0), +(@PATH,2,521.2068,407.0993,112.7837,0,0,0,0,100,0); +DELETE FROM `creature_formations` WHERE `LeaderGUID`=@NPC; +INSERT INTO `creature_formations` (`LeaderGUID`, `MemberGUID`, `FollowDistance`, `FollowAngle`, `GroupAI`, `InversionPoint1`, `InversionPoint2`) VALUES +(@NPC,@NPC ,0, 0,1,-1,-1), +(@NPC,12805,6,90,2,1,2); + +-- Side Creatures +SET @NPC := 12780; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=528.3928,`position_y`=429.879,`position_z`=113.0337 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`waypointPathId`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES +(@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,528.3928, 429.879,113.0337,0,0,0,0,100,0), +(@PATH,2, 506.946,432.0048,113.0337,0,0,0,0,100,0), +(@PATH,3,500.5693,414.4586,113.0338,0,0,0,0,100,0), +(@PATH,4, 506.946,432.0048,113.0337,0,0,0,0,100,0); + +SET @NPC := 12782; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=516.83,`position_y`=368.9177,`position_z`=113.0337 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`waypointPathId`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES +(@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1, 501.718,381.9136,113.0337,0,0,0,0,100,0), +(@PATH,2, 507.699,369.5598,113.0337,0,0,0,0,100,0), +(@PATH,3,527.0941,372.4955,113.0337,0,0,0,0,100,0), +(@PATH,4, 507.699,369.5598,113.0337,0,0,0,0,100,0); + +UPDATE `creature` SET `MovementType`=0, `spawndist`=0 WHERE `guid` IN (12804,12814,12791,12807,12815,12793); +DELETE FROM `creature_formations` WHERE `LeaderGUID` IN (12780,12782); +INSERT INTO `creature_formations` (`LeaderGUID`, `MemberGUID`, `FollowDistance`, `FollowAngle`, `GroupAI`, `InversionPoint1`, `InversionPoint2`) VALUES +(12780,12780,0, 0,1,-1,-1), +(12780,12804,5, 30,1,3,1), +(12780,12814,8, 45,1,3,1), +(12780,12791,5,315,1,3,1), +(12782,12782,0, 0,1,-1,-1), +(12782,12807,5,290,1,1,3), +(12782,12815,8,315,1,1,3), +(12782,12793,5, 45,1,1,3); + +UPDATE `creature_template_addon` SET `auras`='39839' WHERE `entry`=22853; +UPDATE `creature_template_addon` SET `auras`='41191 34189' WHERE `entry`=23374; + +-- Add Ashtongue Stalker's +SET @CGUID := 86283; +DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+8; +INSERT INTO `creature` (`guid`, `id`, `map`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `curhealth`) VALUES +(@CGUID+0, 23374, 564, 656.2982, 387.9902, 112.7728, 2.478368, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) (possible waypoints or random movement) +(@CGUID+1, 23374, 564, 707.5325, 352.4765, 125.2653, 1.32645, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+2, 23374, 564, 769.7925, 370.5881, 112.8415, 0.6128875, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+3, 23374, 564, 702.7503, 352.3887, 125.2664, 1.972222, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+4, 23374, 564, 666.9014, 290.3525, 125.2559, 3.176499, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+5, 23374, 564, 740.3699, 286.297, 125.2686, 5.113815, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+6, 23374, 564, 669.1512, 286.5623, 125.2573, 4.24115, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) (possible waypoints or random movement) +(@CGUID+7, 23374, 564, 742.5994, 290.4014, 125.2681, 0.05235988, 7200, 0), -- 23374 (Area: 4009) (Auras: 41191 - 41191) +(@CGUID+8, 23374, 564, 631.986, 251.5276, 112.749, 2.80998, 7200, 0); -- 23374 (Area: 0) (Auras: 41191 - 41191, 34189 - 34189) + +DELETE FROM `creature_formations` WHERE `LeaderGUID`=12827; +INSERT INTO `creature_formations` (`LeaderGUID`, `MemberGUID`, `FollowDistance`, `FollowAngle`, `GroupAI`) VALUES +(12827, 12827, 0, 0, 2), +(12827, 12840, 10, 90, 2), +(12827, 12824, 10, 270, 2); + +-- Pathing for Illidari Nightlord Entry: 22855 'TDB FORMAT' +SET @NPC := 12827; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=797.9049,`position_y`=255.5211,`position_z`=113.0057 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`waypointPathId`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,797.9049,255.5211,113.0057,0,0,0,0,100,0), -- 21:33:21 +(@PATH,2,799.5116,265.5505,112.9946,0,0,0,0,100,0), -- 21:34:44 +(@PATH,3,799.6346,277.1103,112.9948,0,0,0,0,100,0), -- 21:33:26 +(@PATH,4,799.4362,303.9547,113.0016,0,0,0,0,100,0), -- 21:33:31 +(@PATH,5,799.0039,333.6956,113.0056,0,0,0,0,100,0), -- 21:34:33 +(@PATH,6,799.1071,339.8928,113.0009,0,0,0,0,100,0), -- 21:33:37 +(@PATH,7,798.9255,345.5464,113.0027,0,0,0,0,100,0), -- 21:33:42 +(@PATH,8,798.3091,375.1995,112.9979,0,0,0,0,100,0), -- 21:33:47 +(@PATH,9,796.5051,380.055,112.9991,0,0,0,0,100,0), -- 21:34:21 +(@PATH,10,790.2986,393.373,113.0041,0,0,0,0,100,0), -- 21:33:49 +(@PATH,11,788.781,396.0202,112.9945,0,0,0,0,100,0), -- 21:33:53 +(@PATH,12,776.2429,410.9937,112.9996,0,0,0,0,100,0), -- 21:34:17 +(@PATH,13,769.3853,414.8633,112.9868,0,0,0,0,100,0), -- 21:34:12 +(@PATH,14,759.0627,420.3231,112.9865,0,0,0,0,100,0), -- 21:33:58 +(@PATH,15,755.8228,421.9212,112.7266,0,0,0,0,100,0), -- 21:34:08 +(@PATH,16,730.3083,422.5441,112.9883,0,0,0,0,100,0), -- 21:34:02 +(@PATH,17,755.8228,421.9212,112.7266,0,0,0,0,100,0), -- 21:34:08 +(@PATH,18,759.0627,420.3231,112.9865,0,0,0,0,100,0), -- 21:33:58 +(@PATH,19,769.3853,414.8633,112.9868,0,0,0,0,100,0), -- 21:34:12 +(@PATH,20,776.2429,410.9937,112.9996,0,0,0,0,100,0), -- 21:34:17 +(@PATH,21,788.781,396.0202,112.9945,0,0,0,0,100,0), -- 21:33:53 +(@PATH,22,790.2986,393.373,113.0041,0,0,0,0,100,0), -- 21:33:49 +(@PATH,23,796.5051,380.055,112.9991,0,0,0,0,100,0), -- 21:34:21 +(@PATH,24,798.2438,374.1577,112.9994,0,0,0,0,100,0), -- 21:34:25 +(@PATH,25,798.8231,345.4242,112.9964,0,0,0,0,100,0), -- 21:34:28 +(@PATH,26,799.1071,339.8928,113.0009,0,0,0,0,100,0), -- 21:33:37 +(@PATH,27,799.0039,333.6956,113.0056,0,0,0,0,100,0), -- 21:34:33 +(@PATH,28,799.4362,303.9547,113.0016,0,0,0,0,100,0), -- 21:33:31 +(@PATH,29,799.7034,286.332,113.0002,0,0,0,0,100,0), -- 21:34:38 +(@PATH,30,799.6346,277.1103,112.9948,0,0,0,0,100,0), -- 21:33:26 +(@PATH,31,799.5116,265.5505,112.9946,0,0,0,0,100,0); -- 21:34:44 +-- 0x1C16F446801651C0006A5B00009D4B4E .go 797.9049 255.5211 113.0057 + +DELETE FROM `creature_formations` WHERE `LeaderGUID`=12826; +INSERT INTO `creature_formations` (`LeaderGUID`, `MemberGUID`, `FollowDistance`, `FollowAngle`, `GroupAI`) VALUES +(12826, 12826, 0, 0, 2), +(12826, 12835, 10, 90, 2), +(12826, 12821, 10, 270, 2); + +-- Pathing for Illidari Nightlord Entry: 22855 'TDB FORMAT' +SET @NPC := 12826; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=671.0103,`position_y`=418.0573,`position_z`=112.9719 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`waypointPathId`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,671.0103,418.0573,112.9719,0,0,0,0,100,0), -- 21:30:49 +(@PATH,2,664.3151,418.1411,112.9714,0,0,0,0,100,0), -- 21:30:58 +(@PATH,3,643.6459,416.9381,112.9693,0,0,0,0,100,0), -- 21:32:19 +(@PATH,4,633.8777,410.9504,112.9694,0,0,0,0,100,0), -- 21:31:04 +(@PATH,5,625.0879,404.1424,112.968,0,0,0,0,100,0), -- 21:31:09 +(@PATH,6,616.4854,383.6906,112.9617,0,0,0,0,100,0), -- 21:32:08 +(@PATH,7,609.0042,357.2156,112.9686,0,0,0,0,100,0), -- 21:31:12 +(@PATH,8,608.3771,346.3979,112.973,0,0,0,0,100,0), -- 21:32:05 +(@PATH,9,608.604,340.5182,112.9734,0,0,0,0,100,0), -- 21:31:20 +(@PATH,10,608.3019,334.7826,112.9586,0,0,0,0,100,0), -- 21:31:23 +(@PATH,11,608.424,297.6053,112.9599,0,0,0,0,100,0), -- 21:31:49 +(@PATH,12,607.9512,258.337,112.967,0,0,0,0,100,0), -- 21:31:29 +(@PATH,13,614.2401,245.8512,112.9672,0,0,0,0,100,0), -- 21:31:39 +(@PATH,14,608.4531,256.4178,112.9667,0,0,0,0,100,0), -- 21:31:45 +(@PATH,15,608.424,297.6053,112.9599,0,0,0,0,100,0), -- 21:31:49 +(@PATH,16,608.3019,334.7826,112.9586,0,0,0,0,100,0), -- 21:31:23 +(@PATH,17,608.604,340.5182,112.9734,0,0,0,0,100,0), -- 21:31:20 +(@PATH,18,608.3771,346.3979,112.973,0,0,0,0,100,0), -- 21:32:05 +(@PATH,19,609.0042,357.2156,112.9686,0,0,0,0,100,0), -- 21:31:12 +(@PATH,20,616.4854,383.6906,112.9617,0,0,0,0,100,0), -- 21:32:08 +(@PATH,21,625.0543,404.2943,112.965,0,0,0,0,100,0), -- 21:32:16 +(@PATH,22,633.8777,410.9504,112.9694,0,0,0,0,100,0), -- 21:31:04 +(@PATH,23,643.6459,416.9381,112.9693,0,0,0,0,100,0), -- 21:32:19 +(@PATH,24,664.3151,418.1411,112.9714,0,0,0,0,100,0); -- 21:30:58 +-- 0x1C16F446801651C0006A5B00001D4B4E .go 671.0103 418.0573 112.9719 + +-- Disable PathFinding for High Warlord Naj'entus +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|536870912 WHERE `entry`=22887; + +UPDATE `creature_addon` SET `auras`=19818 WHERE `guid`=40527; + +DELETE FROM `spell_script_names` WHERE `ScriptName`= 'spell_najentus_needle_spine'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(39992,'spell_najentus_needle_spine'); + +DELETE FROM `creature_text` WHERE `CreatureID`=22887 AND (`GroupID` IN(5,6) OR (`GroupID`=4 AND `ID`=1)); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22887,4,1,'My patience has run out! Die! Die!',14,0,100,0,0,11458,21096,0,"High Warlord Naj'entus SAY_ENRAGE2"), +(22887,5,0,'Lord Illidan will... crush you!',14,0,100,0,0,11459,21093,0,"High Warlord Naj'entus SAY_DEATH"); + +UPDATE `creature_text` SET `Text`='Stick around...',`BroadcastTextId`=21089 WHERE `CreatureID`=22887 AND `GroupID`=1 AND `ID`=0; + +-- Fixed speed for Supremus +UPDATE `creature_template` SET `speed_walk`=2.4, `speed_run`=2.14286 WHERE `entry`=22898; +-- Added unit_flag UNIT_FLAG_NOT_SELECTABLE in Supremus Volcano +UPDATE `creature_template` SET `unit_flags`=`unit_flags`|33554432 WHERE `entry`=23085; +-- Updated script name of creature Molten Flame +UPDATE `creature_template` SET `ScriptName`='npc_molten_flame' WHERE `entry`=23095; + +-- Added aura Acidic Wound on Gurtogg Bloodboil +DELETE FROM `creature_addon` where `guid`=52761; +INSERT INTO `creature_addon` (`guid`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(52761, 0, 0, 0, 0, 0, 40484); + +-- SpellScripts +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_gurtogg_bloodboil_insignificance'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(40618, 'spell_gurtogg_bloodboil_insignificance'); + +-- Added creature script in Fel Geyser creature +UPDATE `creature_template` SET `ScriptName`='npc_fel_geyser' WHERE `entry`=23254; + +-- Conditions for spell Taunt Gurtogg +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40603; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,3,40603,0,0,31,0,3,22948,0,0,0,0,'','Effect_0 and Effect_1 - Hits Gurtogg Bloodboil'); + +-- Fix Texts +UPDATE `creature_text` SET `Text`='I hunger.',`BroadcastTextId`=21744 WHERE `CreatureID`=22948 AND `GroupID`=2 AND `ID`=1; +DELETE FROM `creature_text` WHERE `CreatureID`=22948 AND `GroupID`IN(3,4); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22948,3,0,'I\'ll rip the meat from your bones!',14,0,100,0,0,11438,21745,0,'bloodboil SAY_ENRAGE'); + +DELETE FROM `creature_text` WHERE CreatureID=22984; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22984, 0, 0, 'You hear a loud rumble of metal grinding on stone...', 16, 0, 100, 0, 0, 0, 18600, 2, "Black Temple Trigger - when High Warlord Naj'entus dies - Emote"), +(22984, 1, 0, 'The door to The Den of Mortal Delights has opened.', 16, 0, 100, 0, 0, 0, 21494, 2, 'Black Temple Trigger - when Lower Temple Defeated - Emote'); + +-- Add missing spells to Ghost (Vengeful Spirit) +UPDATE `creature_template` SET `spell1`=40325, `spell3`=40157, `spell4`=40175, `spell5`=40314, `spell7`=40322 WHERE `entry`=23109; +-- Add missing auras in Shadowy Construct +DELETE FROM `creature_template_addon` WHERE `entry`=23111; +INSERT INTO `creature_template_addon` (`entry`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(23111, 0, 0, 0, 0, 0, '40326 40334'); + +-- Teron Gorefiend texts +DELETE FROM `creature_text` where `CreatureID`= 22871; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22871, 0, 0, 'I was the first you know. For me the wheel of death has spun many times. So much time has passed... I have a lot of catching up to do.' , 14, 0, 100, 0, 0, 11512, 21098, 0, 'Teron Gorefiend SAY_INTRO'), +(22871, 1, 0, 'Vengeance is mine!', 14, 0, 100, 0, 0, 11513, 21097, 0, 'Teron Gorefiend SAY_AGGRO'), +(22871, 2, 0, 'I have use for you...', 14, 0, 100, 0, 0, 11514, 21099, 0, 'Teron Gorefiend SAY_SLAY1'), +(22871, 2, 1, 'It gets worse.', 14, 0, 100, 0, 0, 11515, 21100, 0, 'Teron Gorefiend SAY_SLAY2'), +(22871, 3, 0, 'What are you afraid of?', 14, 0, 100, 0, 0, 11517, 21102, 0, 'Teron Gorefiend SAY_INCINERATE1'), +(22871, 3, 1, 'You will show the proper respect!', 14, 0, 100, 0, 0, 11520, 21105, 0, 'Teron Gorefiend SAY_INCINERATE2'), +(22871, 4, 0, "Death really isn't so bad.", 14, 0, 100, 0, 0, 11516, 21101, 0, 'Teron Gorefiend SAY_DOOM_BLOSSOM1'), +(22871, 4, 1, 'I have something for you...', 14, 0, 100, 0, 0, 11519, 21104, 0, 'Teron Gorefiend SAY_DOOM_BLOSSOM2'), +(22871, 5, 0, 'Give in.', 14, 0, 100, 0, 0, 11518, 21103, 0, 'Teron Gorefiend SPELL_CRUSHING_SHADOWS'), +(22871, 6, 0, 'The wheel... spins... again.', 14, 0, 100, 0, 0, 11521, 21106, 0, 'Teron Gorefiend SAY_DEATH'); + +-- Area Trigger +DELETE FROM `areatrigger_scripts` WHERE `entry`=4665; +INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES +(4665,'at_teron_gorefiend_entrance'); + +-- Spell scripts +DELETE FROM `spell_script_names` WHERE `ScriptName` IN('spell_teron_gorefiend_spiritual_vengeance','spell_teron_gorefiend_shadow_of_death','spell_teron_gorefiend_shadow_of_death_remove'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(40268,'spell_teron_gorefiend_spiritual_vengeance'), +(40251,'spell_teron_gorefiend_shadow_of_death'), +(41999,'spell_teron_gorefiend_shadow_of_death_remove'); + +-- Conditions +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40268; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,3,40268,0,0,31,0,3,23109,0,0,0,0,'','Effect_0 and Effect_1 hits Vengeful Spirit'); + +UPDATE `creature_template` SET `AIName`='' WHERE `entry`=23472; + +-- Condition for spell Fixate +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41295; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41295,0,0,31,0,3,23418,0,0,0,0,'','Effect_0 hits Essence of Suffering'); + +DELETE FROM `creature_template_addon` WHERE `entry`=23418; +INSERT INTO `creature_template_addon` (`entry`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(23418, 0, 0, 0, 1, 0,'41296 41623'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN('spell_reliquary_of_souls_aura_of_desire','spell_reliquary_of_souls_submerge','spell_reliquary_of_souls_spite','spell_soul_fragment_anger','spell_reliquary_of_souls_frenzy'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41350,'spell_reliquary_of_souls_aura_of_desire'), +(28819,'spell_reliquary_of_souls_submerge'), +(41376,'spell_reliquary_of_souls_spite'), +(41986,'spell_soul_fragment_anger'), +(41305,'spell_reliquary_of_souls_frenzy'); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=-41376 AND`spell_effect`=41377 AND`type`=0; + +UPDATE `creature_template` SET `modelid1`=11686, `modelid2`=1126, `flags_extra`=0, `ScriptName`='npc_angered_soul_fragment' WHERE `entry`=23398; + +DELETE FROM `spell_proc` WHERE `SpellId`=41350; +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES +(41350, 0, 0, 0x00000000, 0x00000000, 0x00000000, 0, 0x1, 0x2, 0x0, 0x2, 0, 0, 0, 0); + +DELETE FROM `creature_text` WHERE `CreatureID`=23418; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23418,0,0,'Pain and suffering are all that await you!',14,0,100,0,0,11415,21759,0,'SUFF_SAY_AGRO'), +(23418,1,0,'Don\'t leave me alone!',14,0,100,0,0,11416,21760,0,'SUFF_SAY_SLAY'), +(23418,1,1,'Look at what you made me do!',14,0,100,0,0,11417,21761,0,'SUFF_SAY_SLAY2'), +(23418,1,2,'I didn\'t ask for this!',14,0,100,0,0,11418,21762,0,'SUFF_SAY_SLAY3'), +(23418,2,0,'The pain is only beginning...',14,0,100,0,0,11419,21763,0,'SUFF_SAY_ENRAGE'), +(23418,3,0,'I don\'t want to go back!',14,0,100,0,0,11420,21764,0,'SUFF_SAY_RECAP'), +(23418,4,0,'Now what do I do?',14,0,100,0,0,11421,21765,0,'SUFF_SAY_AFTER'), +(23418,5,0,'%s becomes enraged!',41,0,100,0,0,0,24144,0,'SUFF_EMOTE_ENRAGE'); + +DELETE FROM `creature_text` WHERE `CreatureID`=23419; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23419,0,0,'You can have anything you desire... for a price.',14,0,100,0,0,11408,21752,0,'DESI_SAY_FREED'), +(23419,1,0,'Fulfillment is at hand.',14,0,100,0,0,11409,21753,0,'DESI_SAY_SLAY1'), +(23419,1,1,'Yes, you\'ll stay with us now...',14,0,100,0,0,11410,21754,0,'DESI_SAY_SLAY2'), +(23419,1,2,'Your reach exceeds your grasp.',14,0,100,0,0,11412,21756,0,'DESI_SAY_SLAY3'), +(23419,2,0,'Be careful what you wish for.',14,0,100,0,0,11411,21755,0,'DESI_SAY_SPEC'), +(23419,3,0,'I won\'t be far!',14,0,100,0,0,11414,21758,0,'DESI_SAY_RECAP'), +(23419,4,0,'I\'ll be waiting.',14,0,100,0,0,11413,21757,0,'DESI_SAY_AFTER'); + +DELETE FROM `creature_text` WHERE `CreatureID`=23420; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23420,0,0,'Beware: I live!',14,0,100,0,0,11399,21746,0,'ANGER_SAY_FREED'), +(23420,1,0,'So... foolish.',14,0,100,0,0,11400,21747,0,'ANGER_SAY_FREED2'), +(23420,2,0,'Enough! No more!',14,0,100,0,0,11402,21748,0,'ANGER_SAY_SEETHE'), +(23420,3,0,'%s seethes in anger!',14,0,100,0,0,0,21878,0,'ANGER_EMOTE_SEETHE'), +(23420,4,0,'On your knees!',14,0,100,0,0,11403,21749,0,'ANGER_SAY_SPEC'), +(23420,5,0,'Beware, coward!',14,0,100,0,0,11405,21751,0,'ANGER_SAY_SPITE'), +(23420,6,0,'I won\'t... be... ignored!',14,0,100,0,0,11404,21750,0,'ANGER_SAY_DEATH'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ( +'spell_mother_shahraz_fatal_attraction', +'spell_mother_shahraz_fatal_attraction_link', +'spell_mother_shahraz_saber_lash', +'spell_mother_shahraz_generic_periodic', +'spell_mother_shahraz_random_periodic'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(40869,'spell_mother_shahraz_fatal_attraction'), +(40870,'spell_mother_shahraz_fatal_attraction_link'), +(40816,'spell_mother_shahraz_saber_lash'), +(40863,'spell_mother_shahraz_generic_periodic'), +(40865,'spell_mother_shahraz_generic_periodic'), +(40866,'spell_mother_shahraz_generic_periodic'), +(40862,'spell_mother_shahraz_generic_periodic'), +(40867,'spell_mother_shahraz_random_periodic'); + +DELETE FROM `creature_addon` WHERE `guid`=52760; +INSERT INTO `creature_addon` (`guid`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(52760, 0, 0, 0, 0, 0, 40816); + +DELETE FROM `creature_text` WHERE CreatureID=22947 AND `GroupID` IN(6,7); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22947, 6, 0, '%s goes into a frenzy!', 41, 0, 100, 0, 0, 0, 2384, 0, 'shahraz EMOTE_ENRAGE'), +(22947, 7, 0, '%s goes into a berserker rage!', 16, 0, 100, 0, 0, 0, 4428, 0, 'shahraz EMOTE_BERSERK'); + +DELETE FROM `creature_addon` WHERE guid IN(52480,52481); +INSERT INTO `creature_addon` (`guid`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(52480, 0, 0, 8, 1, 0, NULL), +(52481, 0, 0, 8, 1, 0, NULL); + +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_illidari_nightlord_shadow_inferno'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(39645,'spell_illidari_nightlord_shadow_inferno'); + +DELETE FROM `creature` WHERE `id` IN(22952,22950,22949,22951); +DELETE FROM `creature_summon_groups` WHERE `summonerId`=23426; -- Illidari Council Trigger +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(23426,0,1,22952,697.495,310.651,277.527,3.1765 ,6,3600000), -- Veras Darkshadow +(23426,0,1,22950,700.792,307.192,277.526,3.14159,6,3600000), -- High Nethermancer Zerevor +(23426,0,1,22949,700.739,302.722,277.526,3.10669,6,3600000), -- Gathios the Shatterer +(23426,0,1,22951,697.409,299.377,277.526,3.07178,6,3600000); -- Lady Malande + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41333; -- Empyreal Equivalency +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41333,0,0,31,0,3,22950,0,0,0,0,'','Effect_0 hits High Nethermancer Zerevor'), +(13,1,41333,0,1,31,0,3,22949,0,0,0,0,'','Effect_0 hits Gathios the Shatterer'), +(13,1,41333,0,2,31,0,3,22951,0,0,0,0,'','Effect_0 hits Lady Malande'), +(13,1,41333,0,3,31,0,3,22952,0,0,0,0,'','Effect_0 hits Veras Darkshadow'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41499; -- Empyreal Balance +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41499,0,0,31,0,3,22950,0,0,0,0,'','Effect_0 hits High Nethermancer Zerevor'), +(13,1,41499,0,1,31,0,3,22949,0,0,0,0,'','Effect_0 hits Gathios the Shatterer'), +(13,1,41499,0,2,31,0,3,22951,0,0,0,0,'','Effect_0 hits Lady Malande'), +(13,1,41499,0,3,31,0,3,22952,0,0,0,0,'','Effect_0 hits Veras Darkshadow'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=41342; -- Shared Rule +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,41342,0,0,31,0,3,23426,0,0,0,0,'','Effect_0 hits The Illidari Council'); + +UPDATE `linked_respawn` SET `linkedGuid`=52479 WHERE `linkedGuid`=52762; + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128, `ScriptName`='npc_veras_vanish_effect' WHERE `entry`=23451; +UPDATE `creature_template` SET `ScriptName`='boss_illidari_council' WHERE `entry`=23426; +UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23499; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN( +'spell_illidari_council_empyreal_balance', +'spell_illidari_council_empyreal_equivalency', +'spell_illidari_council_balance_of_power', +'spell_illidari_council_deadly_strike', +'spell_illidari_council_deadly_poison', +'spell_illidari_council_judgement', +'spell_illidari_council_seal', +'spell_boss_lady_malande_shield', +'spell_illidari_council_reflective_shield', +'spell_illidari_dampen_magic'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41499,'spell_illidari_council_empyreal_balance'), +(41333,'spell_illidari_council_empyreal_equivalency'), +(41341,'spell_illidari_council_balance_of_power'), +(41480,'spell_illidari_council_deadly_strike'), +(41485,'spell_illidari_council_deadly_poison'), +(41467,'spell_illidari_council_judgement'), +(41469,'spell_illidari_council_seal'), +(41459,'spell_illidari_council_seal'), +(41475,'spell_illidari_council_reflective_shield'), +(41478,'spell_illidari_dampen_magic'); + +DELETE FROM `creature_text` WHERE `CreatureID` IN(22951,22949,22950,22952) AND (`groupid` IN(3,4,5,6) OR (`groupid`=2 AND `id`=1)); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22949,2,1,'You are MINE!',14,0,100,0,0,11427,21739,0,'council gath SPECIAL2'), +(22949,3,0,'Selama am\'oronor!',14,0,100,0,0,11423,21735,0,'council gath SLAY'), +(22949,4,0,'Well done!',14,0,100,0,0,11424,21736,0,'council gath SLAY_COMT'), +(22949,5,0,'Lord Illidan, I...',14,0,100,0,0,11425,21737,0,'council gath DEATH'), +(22951,2,1,'I\'m full of surprises!',14,0,100,0,0,11487,21719,0,'council mala SPECIAL2'), +(22951,3,0,'My work is done.',14,0,100,0,0,11483,21712,0,'council mala SLAY'), +(22951,4,0,'As it should be.',14,0,100,0,0,11484,21713,0,'council mala SLAY_COMT'), +(22951,5,0,'Destiny... awaits.',14,0,100,0,0,11485,21715,0,'council mala DEATH'), +(22950,2,1,'Sha\'amoor ara mashal?',14,0,100,0,0,11445,21731,0,'council zere SPECIAL2'), +(22950,3,0,'Shorel\'aran.',14,0,100,0,0,11441,21725,0,'council zere SLAY'), +(22950,4,0,'Belesa menoor!',14,0,100,0,0,11442,21727,0,'council zere SLAY_COMT'), +(22950,5,0,'Diel ma\'ahn... orindel\'o.',14,0,100,0,0,11443,21729,0,'council zere DEATH'), +(22952,2,1,'Anar\'alah belore!',14,0,100,0,0,11529,21705,0,'council vera SPECIAL2'), +(22952,3,0,'Valiant effort.',14,0,100,0,0,11525,21699,0,'council vera SLAY'), +(22952,4,0,'A glorious kill!',14,0,100,0,0,11526,21701,0,'council vera SLAY_COMT'), +(22952,5,0,'You got... lucky.',14,0,100,0,0,11527,21703,0,'council vera DEATH'); + +DELETE FROM `gossip_menu` WHERE `MenuID`=8713; +INSERT INTO `gossip_menu` (`MenuID`, `TextID`, `VerifiedBuild`) VALUES +(8713, 10960, 0), +(8713, 10835, 0); + +DELETE FROM `gossip_menu_option` WHERE `MenuID`=8713 AND `OptionIndex`=1; +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionIndex`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `VerifiedBuild`) VALUES +(8713, 1, 0, 'We\'re ready to face Illidan.', 20903, 1, 1, 0); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(14,15) AND `SourceGroup`=8713; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(14, 8713, 10960, 0, 0, 13, 0, 10, 1, 0, 0, 0, 0, '', 'Show Gossip if Akama is in Intro State'), +(14, 8713, 10835, 0, 0, 13, 0, 10, 2, 0, 0, 0, 0, '', 'Show Gossip if Akama is in Waiting Fight State'), +(15, 8713, 0, 0, 0, 13, 0, 10, 1, 0, 0, 0, 0, '', 'Show Option if Akama in Intro State'), +(15, 8713, 1, 0, 0, 13, 0, 10, 2, 0, 0, 0, 0, '', 'Show Option if Akama is in Waiting Fight State'); + +-- Illidan Group Summon +DELETE FROM `creature` WHERE `guid`=12776; +DELETE FROM `creature_summon_groups` WHERE `summonerId`=22917; +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(22917,0,1,23089,748.5206,236.6311,353.0794,2.373648,8,0); -- Akama + +-- Akama Group Summon +DELETE FROM `creature_summon_groups` WHERE `summonerId`=23089; +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(23089,0,1,23410,751.4565,311.0107,312.19,0,8,0), -- Spirit of Undalo +(23089,0,1,23411,751.6437,297.2233,312.2083,0,8,0); -- Spirit of Olum + +UPDATE `creature_template` SET `scale`=1 WHERE `entry`=23412; -- Door Trigger +UPDATE `creature_template` SET `speed_walk`=1, `speed_run`=2, `unit_flags2`=2099200, `flags_extra`=`flags_extra` | 512 WHERE `entry`=22917; -- Illidan Stormrage +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128 WHERE `entry`=23336; -- Flame Crash +UPDATE `creature_template` SET `speed_walk`=0.35, `speed_run`=0.992063, `flags_extra`=128, `ScriptName`='npc_illidan_db_target' WHERE `entry`=23070; +UPDATE `creature_template` SET `speed_walk`=1.6, `speed_run`=0.571429 WHERE `entry`=23375; -- Shadow Demon +UPDATE `creature_template` SET `ScriptName`='npc_maiev' WHERE `entry`=23197; + +UPDATE `gameobject_template_addon` SET `faction`=1375, `flags`=32 WHERE `entry`=185916; +UPDATE `gameobject_template` SET `ScriptName`='' WHERE `entry`=185916; + +-- Blaze SAI +SET @ENTRY := 23259; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,25,0,100,1,0,0,0,0,8,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Blaze - On Reset - Set Reactstate Passive (No Repeat)"), +(@ENTRY,0,1,0,25,0,100,0,0,0,0,0,11,40610,2,0,0,0,0,1,0,0,0,0,0,0,0,"Blaze - On Reset - Cast 'Blaze'"), +(@ENTRY,0,3,0,25,0,100,0,0,0,0,0,11,40031,2,0,0,0,0,1,0,0,0,0,0,0,0,"Blaze - On Reset - Cast 'Birth - No Visual (Instant Spawn)'"); + +-- Cage Trap Trigger - 1 SAI +SET @ENTRY := 23292; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40704,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 1 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 2 SAI +SET @ENTRY := 23293; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40707,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 2 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 3 SAI +SET @ENTRY := 23294; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40708,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 3 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 4 SAI +SET @ENTRY := 23295; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40709,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 4 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 5 SAI +SET @ENTRY := 23296; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40710,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 5 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 6 SAI +SET @ENTRY := 23297; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40711,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 6 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 7 SAI +SET @ENTRY := 23298; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40712,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 7 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +-- Cage Trap Trigger - 8 SAI +SET @ENTRY := 23299; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,54,0,100,3,0,0,0,0,11,40713,2,0,0,0,0,1,0,0,0,0,0,0,0,"Cage Trap Trigger - 8 - On Just Summoned - Cast 'Caged' (No Repeat) (Normal Dungeon)"); + +DELETE FROM `creature_addon` WHERE `guid`=52484; -- Illidan +INSERT INTO `creature_addon` (`guid`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(52484, 0, 0, 256, 0, 0, '39656 43689'); + +DELETE FROM `creature_template_addon` WHERE `entry` IN(23069,23336,23498); +INSERT INTO `creature_template_addon` (`entry`, `waypointPathId`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(23069, 0, 0, 256, 0, 0, 40029), +(23336, 0, 0, 256, 0, 0, 40836), +(23498, 0, 0, 16908544, 0, 0, '34429 41913'); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN(-41914,-41917); -- Remove Parasitic hack + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_illidan_akama_teleport', +'spell_illidan_akama_door_channel', +'spell_illidan_draw_soul', +'spell_illidan_parasitic_shadowfiend', +'spell_illidan_throw_warglaive', +'spell_illidan_tear_of_azzinoth_channel', +'spell_illidan_flame_blast', +'spell_illidan_return_glaives', +'spell_illidan_agonizing_flames', +'spell_illidan_demon_transform1', +'spell_illidan_demon_transform2', +'spell_illidan_flame_burst', +'spell_illidan_find_target', +'spell_illidan_eye_blast', +'spell_illidan_cage_trap', +'spell_illidan_caged', +'spell_maiev_down', +'spell_illidan_cage_teleport', +'spell_illidan_despawn_akama'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41077,'spell_illidan_akama_teleport'), +(41268,'spell_illidan_akama_door_channel'), +(40904,'spell_illidan_draw_soul'), +(41917,'spell_illidan_parasitic_shadowfiend'), +(41914,'spell_illidan_parasitic_shadowfiend'), +(39635,'spell_illidan_throw_warglaive'), +(39849,'spell_illidan_throw_warglaive'), +(39857,'spell_illidan_tear_of_azzinoth_channel'), +(40631,'spell_illidan_flame_blast'), +(39873,'spell_illidan_return_glaives'), +(40834,'spell_illidan_agonizing_flames'), +(40511,'spell_illidan_demon_transform1'), +(40398,'spell_illidan_demon_transform2'), +(41126,'spell_illidan_flame_burst'), +(41081,'spell_illidan_find_target'), +(39908,'spell_illidan_eye_blast'), +(40761,'spell_illidan_cage_trap'), +(40760,'spell_illidan_caged'), +(40409,'spell_maiev_down'), +(40693,'spell_illidan_cage_teleport'), +(41242,'spell_illidan_despawn_akama'); + +DELETE FROM `creature_text` WHERE CreatureID IN(23089,23410,23411); -- Akama and Minions +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23089, 0, 0, 'This door is all that stands between us and the Betrayer. Stand aside, friends.', 12, 0, 100, 1, 0, 0, 21563, 0, 'SAY_AKAMA_DOOR'), +(23089, 1, 0, 'I cannot do this alone...', 12, 0, 100, 274, 0, 0, 21548, 0, 'SAY_AKAMA_ALONE'), +(23089, 2, 0, 'I thank you for your aid, brothers. Our people will be redeemed!', 12, 0, 100, 66, 0, 0, 21554, 0, 'SAY_AKAMA_SALUTE'), +(23089, 3, 0, 'Be wary, friends. The Betrayer meditates in the court just beyond.', 12, 0, 100, 0, 0, 11388, 21555, 0, 'SAY_AKAMA_BETRAYER'), +(23089, 4, 0, 'We\'ve come to end your reign, Illidan. My people, and all of Outland, shall be free!', 14, 0, 100, 25, 0, 11389, 20893, 0, 'SAY_AKAMA_FREE'), +(23089, 5, 0, 'The time has come! The moment is at hand!', 14, 0, 100, 22, 0, 11380, 20894, 0, 'SAY_AKAMA_TIME_HAS_COME'), +(23089, 6, 0, 'I will deal with these mongrels! Strike now, friends! Strike at the Betrayer!', 14, 0, 100, 22, 0, 11390, 21250, 0, 'SAY_AKAMA_MINIONS'), +(23089, 7, 0, 'The Light will bless these dismal halls once again.... I swear it.', 14, 0, 100, 1, 0, 11387, 21514, 0, 'SAY_AKAMA_LIGHT'), +(23089, 8, 0, 'Let us finish what we\'ve started. I will lead you to Illidan\'s abode once you\'ve recovered your strength.', 12, 0, 100, 1, 0, 0, 21520, 0, 'SAY_AKAMA_FINISH'), +-- AKAMA MINIONS +(23410, 0, 0, 'You are not alone, Akama.', 12, 0, 100, 0, 0, 0, 21545, 0, 'SAY_SPIRIT_ALONE'), -- Spirit of Udalo +(23411, 0, 0, 'Your people will always be with you!', 12, 0, 100, 0, 0, 0, 21546, 0, 'SAY_SPIRIT_ALONE'); -- Spirit of Olum + +DELETE FROM `creature_text` WHERE CreatureID=22917 AND `GroupID` IN(8,9,10,11,12,13,14); -- Illidan +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(22917, 8, 0, 'Akama. Your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.', 14, 0, 100, 6, 0, 11463, 20867, 0, 'Illidan SAY_ILLIDAN_DUPLICITY'), +(22917, 9, 0, 'Boldly said. But I remain... unconvinced.', 14, 0, 100, 6, 0, 11464, 20868, 0, 'Illidan SAY_ILLIDAN_UNCONVINCED'), +(22917, 10, 0, 'You are not prepared!', 14, 0, 100, 406, 0, 11466, 20884, 0, 'Illidan SAY_ILLIDAN_PREPARED'), +(22917, 11, 0, 'Is this it, mortals? Is this all the fury you can muster?', 14, 0, 100, 0, 0, 11476, 21068, 0, 'Illidan SAY_ILLIDAN_SHADOW_PRISON'), +(22917, 12, 0, 'Maiev... How is it even possible?', 14, 0, 100, 1, 0, 11477, 21069, 0, 'Illidan SAY_ILLIDAN_CONFRONT_MAIEV'), +(22917, 13, 0, 'Feel the hatred of ten thousand years!', 14, 0, 100, 0, 0, 11470, 21501, 0, 'Illidan SAY_ILLIDAN_FRENZY'), +(22917, 14, 0, 'You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me.', 14, 0, 100, 0, 0, 11478, 21506, 0, 'Illidan SAY_ILLIDAN_DEFEATED'); + +DELETE FROM `creature_text` WHERE CreatureID=23197 AND ((`GroupID` IN(1,2,3,4,5,6,7)) OR (`GroupID`=0 AND ID=2)); -- Maiev +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23197, 1, 0, 'Their fury pales before mine, Illidan. We have some unsettled business between us.', 14, 0, 100, 6, 0, 11491, 21070, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_APPEAR'), +(23197, 2, 0, 'My long hunt is finally over. Today, Justice will be done!', 14, 0, 100, 5, 0, 11492, 21071, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_JUSTICE'), +(23197, 3, 0, 'There shall be no prison for you this time!', 14, 0, 100, 0, 0, 11495, 22208, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_TRAP'), +(23197, 4, 0, '%s falls to the floor.', 16, 0, 100, 0, 0, 0, 21317, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_DOWN'), +(23197, 5, 0, 'It is finished. You are beaten.', 14, 0, 100, 0, 0, 11496, 21507, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_FINISHED'), +(23197, 6, 0, 'He\'s right. I feel nothing... I am... nothing.', 14, 0, 100, 0, 0, 11497, 21508, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_OUTRO'), +(23197, 7, 0, 'Farewell, champions.', 14, 0, 100, 0, 0, 11498, 21509, 0, 'Maiev Shadowsong SAY_MAIEV_SHADOWSONG_FAREWELL'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`IN(40704,40707,40708,40709,40710,40711,40712,40713); -- Caged (Visual) +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,40704,0,0,31,0,3,23296,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 5'), +(13,1,40707,0,0,31,0,3,23297,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 6'), +(13,1,40708,0,0,31,0,3,23298,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 7'), +(13,1,40709,0,0,31,0,3,23299,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 8'), +(13,1,40710,0,0,31,0,3,23292,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 1'), +(13,1,40711,0,0,31,0,3,23293,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 2'), +(13,1,40712,0,0,31,0,3,23294,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 3'), +(13,1,40713,0,0,31,0,3,23295,0,0,0,0,'','Effect_0 hits Cage Trap Trigger - 4'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`IN(39849,39635); -- Throw Glaive +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,39849,0,0,31,0,3,23448,52503,0,0,0,'','Effect_0 hits Glaive Target'), +(13,1,39635,0,0,31,0,3,23448,52502,0,0,0,'','Effect_0 hits Glaive Target'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=39873; -- Return Glaive +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,39873,0,0,31,0,3,22917,0,0,0,0,'','Effect_0 hits Illidan Stormrage'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40761; -- Cage Trap +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,40761,0,0,31,0,3,22917,0,0,0,0,'','Effect_0 hits Illidan Stormrage'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40693; -- Cage Trap Teleport +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,40693,0,0,31,0,3,23197,0,0,0,0,'','Effect_0 hits Maiev Shadowsong'); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=1; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 1, 0, 3297, 2391), +(23089, 1, 1, 2744, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=1; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 1, 0, 0, 609.77200, 308.45600, 271.82600), +(23089, 1, 0, 1, 610.93130, 308.29240, 272.00720), +(23089, 1, 0, 2, 625.68130, 307.04240, 271.75720), +(23089, 1, 0, 3, 628.43130, 307.04240, 271.75720), +(23089, 1, 0, 4, 630.18130, 307.04240, 271.75720), +(23089, 1, 0, 5, 631.68130, 306.79240, 271.75720), +(23089, 1, 0, 6, 642.59050, 305.62870, 271.68840), +(23089, 1, 1, 0, 633.37040, 306.42300, 271.66000), +(23089, 1, 1, 1, 642.81750, 305.84460, 271.93120), +(23089, 1, 1, 2, 660.76460, 305.76630, 271.70240); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=2; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 2, 0, 5077, 3297), +(23089, 2, 1, 5259, 3656), +(23089, 2, 2, 4364, 3640), +(23089, 2, 3, 3825, 2422), +(23089, 2, 4, 3466, 2422), +(23089, 2, 5, 2911, 1235), +(23089, 2, 6, 2798, 1203), +(23089, 2, 7, 2172, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=2; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 2, 0, 0, 660.76460, 305.76630, 271.70240), +(23089, 2, 0, 1, 664.95350, 321.87480, 271.94820), +(23089, 2, 0, 2, 665.70350, 324.87480, 271.94820), +(23089, 2, 0, 3, 673.14240, 354.98330, 271.69400), +(23089, 2, 1, 0, 668.70380, 337.33420, 271.68930), +(23089, 2, 1, 1, 673.44130, 355.17200, 271.79190), +(23089, 2, 1, 2, 680.94130, 363.17200, 271.79190), +(23089, 2, 1, 3, 681.94130, 363.92200, 271.79190), +(23089, 2, 1, 4, 691.69130, 374.67200, 271.79190), +(23089, 2, 1, 5, 694.19130, 377.42200, 271.79190), +(23089, 2, 1, 6, 696.67880, 380.00980, 271.89450), +(23089, 2, 2, 0, 685.40080, 368.01770, 271.67940), +(23089, 2, 2, 1, 691.88500, 374.69560, 272.08730), +(23089, 2, 2, 2, 694.38500, 377.19560, 272.08730), +(23089, 2, 2, 3, 696.88500, 379.94560, 272.33730), +(23089, 2, 2, 4, 699.38500, 379.44560, 272.33730), +(23089, 2, 2, 5, 704.13500, 378.44560, 274.58730), +(23089, 2, 2, 6, 714.88500, 375.94560, 277.83730), +(23089, 2, 2, 7, 719.63500, 374.69560, 280.08730), +(23089, 2, 2, 8, 721.36930, 374.37350, 280.99510), +(23089, 2, 3, 0, 715.07500, 375.81030, 277.75200), +(23089, 2, 3, 1, 719.93350, 374.65850, 280.34520), +(23089, 2, 3, 2, 721.68350, 374.40850, 281.34520), +(23089, 2, 3, 3, 725.93350, 368.15850, 284.84520), +(23089, 2, 3, 4, 728.18350, 364.65850, 287.84520), +(23089, 2, 3, 5, 732.68350, 358.65850, 291.84520), +(23089, 2, 3, 6, 736.79190, 352.50670, 296.43850), +(23089, 2, 4, 0, 729.85970, 362.33540, 289.17460), +(23089, 2, 4, 1, 732.96180, 358.54080, 292.23680), +(23089, 2, 4, 2, 736.96180, 352.54080, 296.73680), +(23089, 2, 4, 3, 737.71180, 350.79080, 297.73680), +(23089, 2, 4, 4, 741.71180, 344.04080, 301.73680), +(23089, 2, 4, 5, 745.56390, 336.74620, 306.29910), +(23089, 2, 5, 0, 741.17650, 344.62910, 301.12160), +(23089, 2, 5, 1, 741.90870, 343.92740, 301.90360), +(23089, 2, 5, 2, 745.65870, 336.67740, 306.40360), +(23089, 2, 5, 3, 747.65870, 326.42740, 309.40360), +(23089, 2, 5, 4, 749.14090, 319.22560, 311.68560), +(23089, 2, 6, 0, 745.88320, 335.18240, 306.71790), +(23089, 2, 6, 1, 747.93570, 326.16000, 309.39880), +(23089, 2, 6, 2, 749.18570, 319.41000, 311.89880), +(23089, 2, 6, 3, 749.43570, 318.41000, 312.39880), +(23089, 2, 6, 4, 751.48830, 308.63760, 312.07980), +(23089, 2, 7, 0, 748.24830, 323.59770, 310.07210), +(23089, 2, 7, 1, 749.51420, 319.24910, 311.87080), +(23089, 2, 7, 2, 749.76420, 317.99910, 312.37080), +(23089, 2, 7, 3, 751.76420, 308.99910, 312.37080), +(23089, 2, 7, 4, 755.51420, 304.99910, 312.37080), +(23089, 2, 7, 5, 755.78010, 304.40060, 312.16960); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=3; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 3, 0, 4686, 3640), +(23089, 3, 1, 3261, 2453), +(23089, 3, 2, 3415, 2438), +(23089, 3, 3, 4631, 3641), +(23089, 3, 4, 2627, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=3; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 3, 0, 0, 755.78010, 304.40060, 312.16960), +(23089, 3, 0, 1, 759.85900, 303.60590, 312.72120), +(23089, 3, 0, 2, 770.35900, 301.10590, 312.72120), +(23089, 3, 0, 3, 779.60900, 299.10590, 319.97120), +(23089, 3, 0, 4, 781.35900, 298.60590, 319.97120), +(23089, 3, 0, 5, 786.35900, 297.60590, 319.97120), +(23089, 3, 0, 6, 787.35900, 297.35590, 319.97120), +(23089, 3, 0, 7, 798.93790, 294.31120, 319.77270), +(23089, 3, 1, 0, 788.57950, 296.73280, 319.76110), +(23089, 3, 1, 1, 799.06010, 294.20360, 320.06920), +(23089, 3, 1, 2, 798.56010, 289.20360, 320.31920), +(23089, 3, 1, 3, 797.54060, 276.17450, 330.37730), +(23089, 3, 2, 0, 798.04160, 282.67720, 325.05990), +(23089, 3, 2, 1, 797.59280, 276.20070, 330.76180), +(23089, 3, 2, 2, 795.34280, 262.95070, 341.51180), +(23089, 3, 2, 3, 794.59280, 258.70070, 341.51180), +(23089, 3, 2, 4, 793.64410, 254.72420, 341.46370), +(23089, 3, 3, 0, 795.28610, 263.76330, 340.53130), +(23089, 3, 3, 1, 795.05350, 262.63820, 341.82590), +(23089, 3, 3, 2, 794.30350, 258.38820, 341.82590), +(23089, 3, 3, 3, 793.55350, 254.63820, 341.82590), +(23089, 3, 3, 4, 792.55350, 254.13820, 341.82590), +(23089, 3, 3, 5, 787.80350, 251.38820, 341.82590), +(23089, 3, 3, 6, 783.55350, 249.13820, 341.82590), +(23089, 3, 3, 7, 773.05350, 242.88820, 349.07590), +(23089, 3, 3, 8, 766.30350, 238.88820, 353.82590), +(23089, 3, 3, 9, 764.82070, 238.01300, 353.62060), +(23089, 3, 4, 0, 772.12710, 242.24910, 349.37410), +(23089, 3, 4, 1, 766.03170, 239.02710, 353.95420), +(23089, 3, 4, 2, 764.78170, 238.27710, 353.70420), +(23089, 3, 4, 3, 760.28170, 237.77710, 353.45420), +(23089, 3, 4, 4, 750.28170, 236.27710, 353.20420), +(23089, 3, 4, 5, 748.43620, 235.80510, 353.03430); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=4; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 4, 0, 6925, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=4; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 4, 0, 0, 748.43620, 235.80510, 353.03430), +(23089, 4, 0, 1, 747.83060, 249.37560, 353.26520), +(23089, 4, 0, 2, 747.58060, 252.87560, 353.26520), +(23089, 4, 0, 3, 747.33060, 257.37560, 353.26520), +(23089, 4, 0, 4, 747.33060, 260.87560, 353.26520), +(23089, 4, 0, 5, 746.83060, 277.12560, 353.26520), +(23089, 4, 0, 6, 746.08060, 293.12560, 353.26520), +(23089, 4, 0, 7, 745.58060, 302.87560, 353.26520), +(23089, 4, 0, 8, 745.22500, 304.94600, 352.99600); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=5; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 5, 0, 5893, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=5; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 5, 0, 0, 745.22500, 304.94600, 352.99600), +(23089, 5, 0, 1, 744.74730, 320.38350, 353.25160), +(23089, 5, 0, 2, 744.49730, 331.88350, 353.25160), +(23089, 5, 0, 3, 744.49730, 348.38350, 353.25160), +(23089, 5, 0, 4, 744.24730, 349.63350, 353.25160), +(23089, 5, 0, 5, 744.24730, 352.13350, 353.25160), +(23089, 5, 0, 6, 743.99730, 362.63350, 353.25160), +(23089, 5, 0, 7, 743.76950, 363.82110, 353.00730); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=6; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 6, 0, 9319, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=6; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 6, 0, 0, 752.27710, 369.94010, 353.15840), +(23089, 6, 0, 1, 753.94520, 368.68850, 353.20910), +(23089, 6, 0, 2, 762.69520, 361.68850, 353.70910), +(23089, 6, 0, 3, 763.94520, 360.68850, 353.95910), +(23089, 6, 0, 4, 764.94520, 359.68850, 352.95910), +(23089, 6, 0, 5, 780.19520, 347.18850, 341.70910), +(23089, 6, 0, 6, 780.44520, 346.68850, 341.70910), +(23089, 6, 0, 7, 792.19520, 320.18850, 320.20910), +(23089, 6, 0, 8, 794.69520, 314.93850, 320.20910), +(23089, 6, 0, 9, 796.19520, 311.43850, 320.20910), +(23089, 6, 0, 10, 799.11330, 304.43700, 319.75990); + +DELETE FROM `script_spline_chain_meta` WHERE `entry`=23089 AND `chainId`=7; +INSERT INTO `script_spline_chain_meta` (`entry`,`chainId`,`splineId`,`expectedDuration`,`msUntilNext`) VALUES +(23089, 7, 0, 4704, 0); +DELETE FROM `script_spline_chain_waypoints` WHERE `entry`=23089 AND `chainId`=7; +INSERT INTO `script_spline_chain_waypoints` (`entry`,`chainId`,`splineId`,`wpId`,`x`,`y`,`z`) VALUES +(23089, 7, 0, 0, 753.04650, 369.30210, 353.12700), +(23089, 7, 0, 1, 751.76920, 369.24790, 353.31160), +(23089, 7, 0, 2, 739.51920, 368.74790, 353.06160), +(23089, 7, 0, 3, 723.26920, 367.99790, 353.06160), +(23089, 7, 0, 4, 722.76920, 367.49790, 353.06160), +(23089, 7, 0, 5, 715.76920, 369.49790, 353.06160), +(23089, 7, 0, 6, 714.51920, 368.24790, 353.06160); + +DELETE FROM `gameobject` WHERE guid=44; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES +(44, 185966, 564, 3959, 3959, 1, 1, 706.406006, 302.182373, 353.743744, 0.157961, 0, 0, 0, 0, 7200, 0, 1); + +UPDATE `creature_template` SET `ScriptName`='npc_illidari_elite' WHERE `entry`=23226; + +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_illidan_remove_parasitic_shadowfiend'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41923,'spell_illidan_remove_parasitic_shadowfiend'); + +-- DELETE FROM `spell_dbc` WHERE `Id`=41923; +-- INSERT INTO `spell_dbc` (`Id`,`Dispel`,`Mechanic`,`Attributes`,`AttributesEx`,`AttributesEx2`,`AttributesEx3`,`AttributesEx4`,`AttributesEx5`,`AttributesEx6`,`AttributesEx7`,`Stances`,`StancesNot`,`Targets`,`CastingTimeIndex`,`AuraInterruptFlags`,`ProcFlags`,`ProcChance`,`ProcCharges`,`MaxLevel`,`BaseLevel`,`SpellLevel`,`DurationIndex`,`RangeIndex`,`StackAmount`,`EquippedItemClass`,`EquippedItemSubClassMask`,`EquippedItemInventoryTypeMask`,`Effect1`,`Effect2`,`Effect3`,`EffectDieSides1`,`EffectDieSides2`,`EffectDieSides3`,`EffectRealPointsPerLevel1`,`EffectRealPointsPerLevel2`,`EffectRealPointsPerLevel3`,`EffectBasePoints1`,`EffectBasePoints2`,`EffectBasePoints3`,`EffectMechanic1`,`EffectMechanic2`,`EffectMechanic3`,`EffectImplicitTargetA1`,`EffectImplicitTargetA2`,`EffectImplicitTargetA3`,`EffectImplicitTargetB1`,`EffectImplicitTargetB2`,`EffectImplicitTargetB3`,`EffectRadiusIndex1`,`EffectRadiusIndex2`,`EffectRadiusIndex3`,`EffectApplyAuraName1`,`EffectApplyAuraName2`,`EffectApplyAuraName3`,`EffectAmplitude1`,`EffectAmplitude2`,`EffectAmplitude3`,`EffectMultipleValue1`,`EffectMultipleValue2`,`EffectMultipleValue3`,`EffectItemType1`,`EffectItemType2`,`EffectItemType3`,`EffectMiscValue1`,`EffectMiscValue2`,`EffectMiscValue3`,`EffectMiscValueB1`,`EffectMiscValueB2`,`EffectMiscValueB3`,`EffectTriggerSpell1`,`EffectTriggerSpell2`,`EffectTriggerSpell3`,`EffectSpellClassMaskA1`,`EffectSpellClassMaskA2`,`EffectSpellClassMaskA3`,`EffectSpellClassMaskB1`,`EffectSpellClassMaskB2`,`EffectSpellClassMaskB3`,`EffectSpellClassMaskC1`,`EffectSpellClassMaskC2`,`EffectSpellClassMaskC3`,`MaxTargetLevel`,`SpellFamilyName`,`SpellFamilyFlags1`,`SpellFamilyFlags2`,`SpellFamilyFlags3`,`MaxAffectedTargets`,`DmgClass`,`PreventionType`,`DmgMultiplier1`,`DmgMultiplier2`,`DmgMultiplier3`,`AreaGroupId`,`SchoolMask`,`Comment`) VALUES +-- (41923,0,0,536871296,268435592,4,256,0,8,0,0,0,0,0,1,0,0,0,0,0,0,0,27,1,0,-1,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,15,0,0,28,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,'Remove Parasitic Shadowfiends'); + +DELETE FROM `spelleffect_dbc` WHERE `Id`= 160109; +INSERT INTO `spelleffect_dbc` (`Id`, `Effect`, `EffectAura`, `EffectRadiusIndex`, `EffectImplicitTargetA`, `EffectImplicitTargetB`, `SpellID`, `EffectIndex`, `Comment`) VALUES +(160109, 6, 4, 28, 22, 15, 41923, 0, ''); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_illidari_council_vanish'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41476,'spell_illidari_council_vanish'); + +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_illidan_parasitic_shadowfiend_proc'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(41913,'spell_illidan_parasitic_shadowfiend_proc'); + +-- +DELETE FROM `creature` WHERE `id` IN (22934) AND `guid`=107033; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(107033, 22934, 530, 1, 1, -3565.66, 499.164, 20.2467, 2.54818, 120, 0, 0); + +-- Reliquary of Souls Combat Trigger +UPDATE `creature_template` SET `flags_extra`=`flags_extra`&~128, `ScriptName` = 'npc_reliquary_combat_trigger' WHERE `entry`=23417; + +UPDATE `creature_template` SET `ScriptName`= 'npc_illidan_generic_fire' WHERE `entry`= 23069; + +-- +DELETE FROM `conditions` WHERE `SourceEntry`= 40647 AND `SourceTypeOrReferenceId`= 13; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ScriptName`, `Comment`) VALUES +(13, 4, 40647, 0, 0, 31, 0, 3, 23089, 0, 0, 0, '', 'Shadow Prison - Target Akama'); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 2ac39b18a7..011a46c2f3 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -3743,6 +3743,8 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const case 29214: // Wrath of the Plaguebringer case 34700: // Allergic Reaction case 54836: // Wrath of the Plaguebringer + case 41914: // Parasitic Shadowfiend (Illidan) + case 41917: // Parasitic Shadowfiend (Illidan) return false; case 30877: // Tag Murloc case 61716: // Rabbit Costume diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 96c2931f42..3abb3f3826 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -4849,6 +4849,18 @@ void SpellMgr::LoadSpellInfoCorrections() }); // ENDOF ISLE OF CONQUEST SPELLS + // Deadly Poison - Black Temple + ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; + }); + + // Envenom - Black Temple + ApplySpellFix({ 41487 }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; + }); + // // FIRELANDS SPELLS // diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.cpp b/src/server/scripts/Outland/BlackTemple/black_temple.cpp index 29a03573f6..08aa67d952 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/black_temple.cpp @@ -57,270 +57,222 @@ enum Misc GROUP_OUT_OF_COMBAT = 1 }; -// ######################################################## -// Wrathbone Flayer -// ######################################################## - -class npc_wrathbone_flayer : public CreatureScript +struct npc_wrathbone_flayer : public ScriptedAI { -public: - npc_wrathbone_flayer() : CreatureScript("npc_wrathbone_flayer") { } - - struct npc_wrathbone_flayerAI : public ScriptedAI + npc_wrathbone_flayer(Creature* creature) : ScriptedAI(creature) { - npc_wrathbone_flayerAI(Creature* creature) : ScriptedAI(creature) + Initialize(); + _instance = creature->GetInstanceScript(); + } + + void Initialize() + { + _enteredCombat = false; + } + + void Reset() override + { + _events.ScheduleEvent(EVENT_GET_CHANNELERS, 3s); + Initialize(); + _bloodmageList.clear(); + _deathshaperList.clear(); + } + + void JustDied(Unit* /*killer*/) override { } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_CLEAVE, 5s); + _events.ScheduleEvent(EVENT_IGNORED, 7s); + _enteredCombat = true; + } + + void UpdateAI(uint32 diff) override + { + if (!_enteredCombat) { - Initialize(); - _instance = creature->GetInstanceScript(); - } - - void Initialize() - { - _enteredCombat = false; - } - - void Reset() override - { - _events.ScheduleEvent(EVENT_GET_CHANNELERS, 3000); - Initialize(); - _bloodmageList.clear(); - _deathshaperList.clear(); - } - - void JustDied(Unit* /*killer*/) override { } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_CLEAVE, 5000); - _events.ScheduleEvent(EVENT_IGNORED, 7000); - _enteredCombat = true; - } - - void UpdateAI(uint32 diff) override - { - if (!_enteredCombat) - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_GET_CHANNELERS: - { - std::list BloodMageList; - me->GetCreatureListWithEntryInGrid(BloodMageList, NPC_BLOOD_MAGE, 15.0f); - - if (!BloodMageList.empty()) - for (std::list::const_iterator itr = BloodMageList.begin(); itr != BloodMageList.end(); ++itr) - { - _bloodmageList.push_back((*itr)->GetGUID()); - if ((*itr)->isDead()) - (*itr)->Respawn(); - } - - std::list DeathShaperList; - me->GetCreatureListWithEntryInGrid(DeathShaperList, NPC_DEATHSHAPER, 15.0f); - - if (!DeathShaperList.empty()) - for (std::list::const_iterator itr = DeathShaperList.begin(); itr != DeathShaperList.end(); ++itr) - { - _deathshaperList.push_back((*itr)->GetGUID()); - if ((*itr)->isDead()) - (*itr)->Respawn(); - } - - _events.ScheduleEvent(EVENT_SET_CHANNELERS, 3000); - - break; - } - case EVENT_SET_CHANNELERS: - { - for (ObjectGuid guid : _bloodmageList) - if (Creature* bloodmage = ObjectAccessor::GetCreature(*me, guid)) - bloodmage->CastSpell((Unit*)nullptr, SPELL_SUMMON_CHANNEL); - - for (ObjectGuid guid : _deathshaperList) - if (Creature* deathshaper = ObjectAccessor::GetCreature(*me, guid)) - deathshaper->CastSpell((Unit*)nullptr, SPELL_SUMMON_CHANNEL); - - _events.ScheduleEvent(EVENT_SET_CHANNELERS, 12000); - - break; - } - default: - break; - } - } - } - - if (!UpdateVictim()) - return; - _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - _events.ScheduleEvent(EVENT_CLEAVE, urand (1000, 2000)); + case EVENT_GET_CHANNELERS: + { + std::list BloodMageList; + me->GetCreatureListWithEntryInGrid(BloodMageList, NPC_BLOOD_MAGE, 15.0f); + + if (!BloodMageList.empty()) + for (std::list::const_iterator itr = BloodMageList.begin(); itr != BloodMageList.end(); ++itr) + { + _bloodmageList.push_back((*itr)->GetGUID()); + if ((*itr)->isDead()) + (*itr)->Respawn(); + } + + std::list DeathShaperList; + me->GetCreatureListWithEntryInGrid(DeathShaperList, NPC_DEATHSHAPER, 15.0f); + + if (!DeathShaperList.empty()) + for (std::list::const_iterator itr = DeathShaperList.begin(); itr != DeathShaperList.end(); ++itr) + { + _deathshaperList.push_back((*itr)->GetGUID()); + if ((*itr)->isDead()) + (*itr)->Respawn(); + } + + _events.ScheduleEvent(EVENT_SET_CHANNELERS, 3s); + break; - case EVENT_IGNORED: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_IGNORED); - _events.ScheduleEvent(EVENT_IGNORED, 10000); + } + case EVENT_SET_CHANNELERS: + { + for (ObjectGuid guid : _bloodmageList) + if (Creature* bloodmage = ObjectAccessor::GetCreature(*me, guid)) + bloodmage->CastSpell(nullptr, SPELL_SUMMON_CHANNEL); + + for (ObjectGuid guid : _deathshaperList) + if (Creature* deathshaper = ObjectAccessor::GetCreature(*me, guid)) + deathshaper->CastSpell(nullptr, SPELL_SUMMON_CHANNEL); + + _events.ScheduleEvent(EVENT_SET_CHANNELERS, 12s); + break; + } default: break; } } - DoMeleeAttackIfReady(); } - private: - InstanceScript* _instance; - EventMap _events; - GuidList _bloodmageList; - GuidList _deathshaperList; - bool _enteredCombat; - }; + if (!UpdateVictim()) + return; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + _events.ScheduleEvent(EVENT_CLEAVE, 1s, 2s); + break; + case EVENT_IGNORED: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_IGNORED); + _events.ScheduleEvent(EVENT_IGNORED, 10s); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); } + +private: + InstanceScript* _instance; + EventMap _events; + GuidList _bloodmageList; + GuidList _deathshaperList; + bool _enteredCombat; }; -class npc_angered_soul_fragment : public CreatureScript +struct npc_angered_soul_fragment : public ScriptedAI { -public: - npc_angered_soul_fragment() : CreatureScript("npc_angered_soul_fragment") { } + npc_angered_soul_fragment(Creature* creature) : ScriptedAI(creature) { } - struct npc_angered_soul_fragmentAI : public ScriptedAI + void Reset() override { - npc_angered_soul_fragmentAI(Creature* creature) : ScriptedAI(creature) { } + _scheduler.CancelAll(); - void Reset() override + _scheduler.Schedule(Seconds(1), GROUP_OUT_OF_COMBAT, [this](TaskContext invi) { - _scheduler.CancelAll(); + DoCastSelf(SPELL_GREATER_INVISIBILITY); - _scheduler.Schedule(Seconds(1), GROUP_OUT_OF_COMBAT, [this](TaskContext invi) + /* Workaround - On Retail creature appear and "vanish" again periodically, but i cant find packets + with UPDATE_AURA on sniffs about it */ + _scheduler.Schedule(Seconds(5), Seconds(10), GROUP_OUT_OF_COMBAT, [this](TaskContext /*context*/) { - DoCastSelf(SPELL_GREATER_INVISIBILITY); - - /* Workaround - On Retail creature appear and "vanish" again periodically, but i cant find packets - with UPDATE_AURA on sniffs about it */ - _scheduler.Schedule(Seconds(5), Seconds(10), GROUP_OUT_OF_COMBAT, [this](TaskContext /*context*/) - { - me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); - }); - - invi.Repeat(Seconds(15), Seconds(25)); + me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); }); - } - void JustEngagedWith(Unit* /*who*/) override - { - me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); - - _scheduler.CancelGroup(GROUP_OUT_OF_COMBAT); - _scheduler.Schedule(Seconds(1), [this](TaskContext anger) - { - Unit* target = me->GetVictim(); - if (target && me->IsWithinMeleeRange(target)) - DoCastSelf(SPELL_ANGER); - else - anger.Repeat(Seconds(1)); - }); - } - - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - DoMeleeAttackIfReady(); - } - - private: - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + invi.Repeat(Seconds(15), Seconds(25)); + }); } + + void JustEngagedWith(Unit* /*who*/) override + { + me->RemoveAurasDueToSpell(SPELL_GREATER_INVISIBILITY); + + _scheduler.CancelGroup(GROUP_OUT_OF_COMBAT); + _scheduler.Schedule(Seconds(1), [this](TaskContext anger) + { + Unit* target = me->GetVictim(); + if (target && me->IsWithinMeleeRange(target)) + DoCastSelf(SPELL_ANGER); + else + anger.Repeat(Seconds(1)); + }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler _scheduler; }; // 41986 - Anger -class spell_soul_fragment_anger : public SpellScriptLoader +class spell_soul_fragment_anger : public SpellScript { - public: - spell_soul_fragment_anger() : SpellScriptLoader("spell_soul_fragment_anger") { } + void HandleKill() + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->DespawnOrUnsummon(Milliseconds(200)); + } - class spell_soul_fragment_anger_SpellScript : public SpellScript - { - void HandleKill() - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->DespawnOrUnsummon(Milliseconds(200)); - } - - void Register() override - { - AfterCast.Register(&spell_soul_fragment_anger_SpellScript::HandleKill); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_soul_fragment_anger_SpellScript(); - } + void Register() override + { + AfterCast.Register(&spell_soul_fragment_anger::HandleKill); + } }; // 39645 - Shadow Inferno -class spell_illidari_nightlord_shadow_inferno : public SpellScriptLoader +class spell_illidari_nightlord_shadow_inferno : public AuraScript { - public: - spell_illidari_nightlord_shadow_inferno() : SpellScriptLoader("spell_illidari_nightlord_shadow_inferno") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHADOW_INFERNO_DAMAGE }); + } - class spell_illidari_nightlord_shadow_inferno_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHADOW_INFERNO_DAMAGE }); - } + void OnPeriodic(AuraEffect const* aurEffect) + { + PreventDefaultAction(); + int32 bp = aurEffect->GetTickNumber() * aurEffect->GetAmount(); + GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SHADOW_INFERNO_DAMAGE, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(bp)); + } - void OnPeriodic(AuraEffect const* aurEffect) - { - PreventDefaultAction(); - int32 bp = aurEffect->GetTickNumber() * aurEffect->GetAmount(); - GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_SHADOW_INFERNO_DAMAGE, CastSpellExtraArgs(true).AddSpellBP0(bp)); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidari_nightlord_shadow_inferno_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_nightlord_shadow_inferno_AuraScript(); - } + void Register() override + { + OnEffectPeriodic.Register(&spell_illidari_nightlord_shadow_inferno::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; void AddSC_black_temple() { - new npc_wrathbone_flayer(); - new npc_angered_soul_fragment(); - new spell_soul_fragment_anger(); - new spell_illidari_nightlord_shadow_inferno(); + RegisterBlackTempleCreatureAI(npc_wrathbone_flayer); + RegisterBlackTempleCreatureAI(npc_angered_soul_fragment); + RegisterSpellScript(spell_soul_fragment_anger); + RegisterSpellScript(spell_illidari_nightlord_shadow_inferno); } diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 10be8f5c63..1150096f74 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -55,7 +55,8 @@ enum BTDataTypes DATA_ESSENCE_OF_ANGER = 22, DATA_ILLIDAN_MUSIC_CONTROLLER = 23, DATA_TERON_GOREFIEND_INTRO = 24, - DATA_AKAMA_ILLIDAN_INTRO = 25 + DATA_AKAMA_ILLIDAN_INTRO = 25, + DATA_RELIQUARY_COMBAT_TRIGGER = 26 }; enum TriggerEmotes @@ -105,7 +106,11 @@ enum BTCreatureIds NPC_ILLIDARI_ELITE = 23226, NPC_GLAIVE_TARGET = 23448, NPC_GLAIVE_WORLD_TRIGGER = 22515, - NPC_DEMON_FIRE = 23069 + NPC_DEMON_FIRE = 23069, + NPC_PARASITIC_SHADOWFIEND = 23498, + NPC_BLAZE = 23259, + NPC_FLAME_CRASH = 23336, + NPC_RELIQUARY_COMBAT_TRIGGER = 23417 }; enum BTGameObjectIds @@ -130,7 +135,6 @@ enum BTGameObjectIds enum BlackTempleMisc { - AKAMA_FACTION_COMBAT = 1868, AKAMA_INTRO = 1, AKAMA_FIGHT = 2, ACTION_ACTIVE_AKAMA_INTRO = 3, @@ -143,4 +147,6 @@ inline AI* GetBlackTempleAI(T* obj) return GetInstanceAI(obj, BTScriptName); } +#define RegisterBlackTempleCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackTempleAI) + #endif // BLACK_TEMPLE_H_ diff --git a/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp index 39846d0c7e..a9af2c79a2 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp @@ -89,318 +89,275 @@ enum Events EVENT_CHARGE_PLAYER }; -class boss_gurtogg_bloodboil : public CreatureScript + +struct boss_gurtogg_bloodboil : public BossAI { -public: - boss_gurtogg_bloodboil() : CreatureScript("boss_gurtogg_bloodboil") { } - - struct boss_gurtogg_bloodboilAI : public BossAI + boss_gurtogg_bloodboil(Creature* creature) : BossAI(creature, DATA_GURTOGG_BLOODBOIL) { - boss_gurtogg_bloodboilAI(Creature* creature) : BossAI(creature, DATA_GURTOGG_BLOODBOIL) - { - Initialize(); - } + Initialize(); + } - void Reset() override - { - _Reset(); - Initialize(); - events.SetPhase(PHASE_1); - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); - } + void Reset() override + { + _Reset(); + Initialize(); + events.SetPhase(PHASE_1); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); + } - void Initialize() - { - _oldThreat = 0.0f; - _oldTargetGUID.Clear(); - _targetGUID.Clear(); - } + void Initialize() + { + _oldThreat = 0.0f; + _oldTargetGUID.Clear(); + _targetGUID.Clear(); + } - bool CanAIAttack(Unit const* who) const override - { - return BossAI::CanAIAttack(who) && !who->HasAura(SPELL_BEWILDERING_STRIKE); - } + bool CanAIAttack(Unit const* who) const override + { + return BossAI::CanAIAttack(who) && !who->HasAura(SPELL_BEWILDERING_STRIKE); + } - void AttackStart(Unit* who) override + void AttackStart(Unit* who) override + { + if (!CanAIAttack(who)) + return; + + BossAI::AttackStart(who); + } + + void JustEngagedWith(Unit* who) override + { + Talk(SAY_AGGRO); + BossAI::JustEngagedWith(who); + events.ScheduleEvent(EVENT_BERSERK, 10min); + events.ScheduleEvent(EVENT_CHANGE_PHASE, 1min); + ScheduleEvents(); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _DespawnAtEvade(); + } + + void ScheduleEvents() + { + if (events.IsInPhase(PHASE_1)) { - if (!CanAIAttack(who)) + events.ScheduleEvent(EVENT_BLOODBOIL, Seconds(10), GROUP_PHASE_1, PHASE_1); + events.ScheduleEvent(EVENT_ARCING_SMASH, Seconds(10), GROUP_PHASE_1, PHASE_1); + events.ScheduleEvent(EVENT_FEL_ACID_BREATH, Seconds(25), GROUP_PHASE_1, PHASE_1); + events.ScheduleEvent(EVENT_EJECT, Seconds(35), GROUP_PHASE_1, PHASE_1); + events.ScheduleEvent(EVENT_BEWILDERING_STRIKE, Seconds(47), GROUP_PHASE_1, PHASE_1); + } + else if (events.IsInPhase(PHASE_2)) + { + events.ScheduleEvent(EVENT_START_PHASE_2, Milliseconds(100), GROUP_PHASE_2, PHASE_2); + events.ScheduleEvent(EVENT_EJECT_2, Seconds(14), GROUP_PHASE_2, PHASE_2); + events.ScheduleEvent(EVENT_FEL_ACID_BREATH_2, Seconds(16), GROUP_PHASE_2, PHASE_2); + events.ScheduleEvent(EVENT_ARCING_SMASH_2, Seconds(8), GROUP_PHASE_2, PHASE_2); + } + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + DoPlaySoundToSet(me, SOUND_ID_DEATH); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BLOODBOIL: + DoCast(SPELL_BLOODBOIL); + events.Repeat(Seconds(10)); + break; + case EVENT_ARCING_SMASH: + DoCastVictim(SPELL_ARCING_SMASH); + events.Repeat(Seconds(10)); + break; + case EVENT_FEL_ACID_BREATH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, me->GetCombatReach())) + DoCast(target, SPELL_FEL_ACID_BREATH); + events.Repeat(Seconds(25), Seconds(30)); + break; + case EVENT_EJECT: + Talk(SAY_SPECIAL); + DoCastVictim(SPELL_EJECT); + break; + case EVENT_BEWILDERING_STRIKE: + DoCastVictim(SPELL_BEWILDERING_STRIKE); + break; + case EVENT_CHANGE_PHASE: + ChangePhase(); + break; + case EVENT_START_PHASE_2: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + { + if (Unit* oldTarget = me->GetVictim()) + { + _oldTargetGUID = oldTarget->GetGUID(); + _oldThreat = GetThreat(oldTarget); + } + _targetGUID = target->GetGUID(); + DoCastSelf(SPELL_FEL_RAGE_SELF, true); + DoCast(target, SPELL_FEL_RAGE_TARGET, true); + DoCast(target, SPELL_FEL_RAGE_2, true); + DoCast(target, SPELL_FEL_RAGE_3, true); + DoCast(target, SPELL_FEL_GEYSER, true); + DoCast(target, SPELL_FEL_RAGE_TARGET_2, true); + target->CastSpell(target, SPELL_FEL_RAGE_P, true); + target->CastSpell(target, SPELL_TAUNT_GURTOGG, true); + DoCastAOE(SPELL_INSIGNIFIGANCE, true); + + events.ScheduleEvent(EVENT_CHARGE_PLAYER, Seconds(2), GROUP_PHASE_2, PHASE_2); + + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); + } + else // If no other targets are found, reset phase 1 + { + events.SetPhase(PHASE_1); + events.CancelEventGroup(GROUP_PHASE_2); + ScheduleEvents(); + events.RescheduleEvent(EVENT_CHANGE_PHASE, Seconds(60)); + } + break; + case EVENT_CHARGE_PLAYER: + if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) + DoCast(target, SPELL_CHARGE); + break; + case EVENT_EJECT_2: + DoCastVictim(SPELL_EJECT_2); + break; + case EVENT_FEL_ACID_BREATH_2: + DoCastVictim(SPELL_FEL_ACID_BREATH_2); + break; + case EVENT_ARCING_SMASH_2: + DoCastVictim(SPELL_ARCING_SMASH_2); + events.Repeat(Seconds(13)); + break; + case EVENT_BERSERK: + DoCast(SPELL_BERSERK); + roll_chance_i(50) ? Talk(SAY_ENRAGE) : DoPlaySoundToSet(me, SOUND_ID_ENRAGE); + break; + default: + break; + } + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - BossAI::AttackStart(who); } - void JustEngagedWith(Unit* who) override + DoMeleeAttackIfReady(); + } + + void ChangePhase() + { + if (events.IsInPhase(PHASE_1)) { - BossAI::JustEngagedWith(who); - Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); - events.ScheduleEvent(EVENT_CHANGE_PHASE, Seconds(60)); + events.SetPhase(PHASE_2); + events.CancelEventGroup(GROUP_PHASE_1); + events.ScheduleEvent(EVENT_CHANGE_PHASE, 30s); ScheduleEvents(); } - - void EnterEvadeMode(EvadeReason /*why*/) override + else if (events.IsInPhase(PHASE_2)) { - _DespawnAtEvade(); - } + events.SetPhase(PHASE_1); + events.CancelEventGroup(GROUP_PHASE_2); + events.ScheduleEvent(EVENT_CHANGE_PHASE, 1min); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); + ScheduleEvents(); - void ScheduleEvents() - { - if (events.IsInPhase(PHASE_1)) - { - events.ScheduleEvent(EVENT_BLOODBOIL, Seconds(10), GROUP_PHASE_1, PHASE_1); - events.ScheduleEvent(EVENT_ARCING_SMASH, Seconds(10), GROUP_PHASE_1, PHASE_1); - events.ScheduleEvent(EVENT_FEL_ACID_BREATH, Seconds(25), GROUP_PHASE_1, PHASE_1); - events.ScheduleEvent(EVENT_EJECT, Seconds(35), GROUP_PHASE_1, PHASE_1); - events.ScheduleEvent(EVENT_BEWILDERING_STRIKE, Seconds(47), GROUP_PHASE_1, PHASE_1); - } - else if (events.IsInPhase(PHASE_2)) - { - events.ScheduleEvent(EVENT_START_PHASE_2, Milliseconds(100), GROUP_PHASE_2, PHASE_2); - events.ScheduleEvent(EVENT_EJECT_2, Seconds(14), GROUP_PHASE_2, PHASE_2); - events.ScheduleEvent(EVENT_FEL_ACID_BREATH_2, Seconds(16), GROUP_PHASE_2, PHASE_2); - events.ScheduleEvent(EVENT_ARCING_SMASH_2, Seconds(8), GROUP_PHASE_2, PHASE_2); - } - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - DoPlaySoundToSet(me, SOUND_ID_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) + // Attack the stored target + if (Unit* oldTarget = ObjectAccessor::GetUnit(*me, _oldTargetGUID)) + if (Unit* currentTarget = ObjectAccessor::GetUnit(*me, _targetGUID)) { - case EVENT_BLOODBOIL: - DoCast(SPELL_BLOODBOIL); - events.Repeat(Seconds(10)); - break; - case EVENT_ARCING_SMASH: - DoCastVictim(SPELL_ARCING_SMASH); - events.Repeat(Seconds(10)); - break; - case EVENT_FEL_ACID_BREATH: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, me->GetCombatReach())) - DoCast(target, SPELL_FEL_ACID_BREATH); - events.Repeat(Seconds(25), Seconds(30)); - break; - case EVENT_EJECT: - Talk(SAY_SPECIAL); - DoCastVictim(SPELL_EJECT); - break; - case EVENT_BEWILDERING_STRIKE: - DoCastVictim(SPELL_BEWILDERING_STRIKE); - break; - case EVENT_CHANGE_PHASE: - ChangePhase(); - break; - case EVENT_START_PHASE_2: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) - { - if (Unit* oldTarget = me->GetVictim()) - { - _oldTargetGUID = oldTarget->GetGUID(); - _oldThreat = GetThreat(oldTarget); - } - _targetGUID = target->GetGUID(); - DoCastSelf(SPELL_FEL_RAGE_SELF, true); - DoCast(target, SPELL_FEL_RAGE_TARGET, true); - DoCast(target, SPELL_FEL_RAGE_2, true); - DoCast(target, SPELL_FEL_RAGE_3, true); - DoCast(target, SPELL_FEL_GEYSER, true); - DoCast(target, SPELL_FEL_RAGE_TARGET_2, true); - target->CastSpell(target, SPELL_FEL_RAGE_P, true); - target->CastSpell(target, SPELL_TAUNT_GURTOGG, true); - DoCastAOE(SPELL_INSIGNIFIGANCE, true); - - events.ScheduleEvent(EVENT_CHARGE_PLAYER, Seconds(2), GROUP_PHASE_2, PHASE_2); - - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); - } - else // If no other targets are found, reset phase 1 - { - events.SetPhase(PHASE_1); - events.CancelEventGroup(GROUP_PHASE_2); - ScheduleEvents(); - events.RescheduleEvent(EVENT_CHANGE_PHASE, Seconds(60)); - } - break; - case EVENT_CHARGE_PLAYER: - if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) - DoCast(target, SPELL_CHARGE); - break; - case EVENT_EJECT_2: - DoCastVictim(SPELL_EJECT_2); - break; - case EVENT_FEL_ACID_BREATH_2: - DoCastVictim(SPELL_FEL_ACID_BREATH_2); - break; - case EVENT_ARCING_SMASH_2: - DoCastVictim(SPELL_ARCING_SMASH_2); - events.Repeat(Seconds(13)); - break; - case EVENT_BERSERK: - DoCast(SPELL_BERSERK); - roll_chance_i(50) ? Talk(SAY_ENRAGE) : DoPlaySoundToSet(me, SOUND_ID_ENRAGE); - break; - default: - break; + ModifyThreatByPercent(currentTarget, -100); + AttackStart(oldTarget); + AddThreat(oldTarget, _oldThreat); + Initialize(); } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - - void ChangePhase() - { - if (events.IsInPhase(PHASE_1)) - { - events.SetPhase(PHASE_2); - events.CancelEventGroup(GROUP_PHASE_1); - events.ScheduleEvent(EVENT_CHANGE_PHASE, Seconds(30)); - ScheduleEvents(); - } - else if (events.IsInPhase(PHASE_2)) - { - events.SetPhase(PHASE_1); - events.CancelEventGroup(GROUP_PHASE_2); - events.ScheduleEvent(EVENT_CHANGE_PHASE, Seconds(60)); - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); - ScheduleEvents(); - - // Attack the stored target - if (Unit* oldTarget = ObjectAccessor::GetUnit(*me, _oldTargetGUID)) - if (Unit* currentTarget = ObjectAccessor::GetUnit(*me, _targetGUID)) - { - ModifyThreatByPercent(currentTarget, -100); - AttackStart(oldTarget); - AddThreat(oldTarget, _oldThreat); - Initialize(); - } - } - } - - private: - ObjectGuid _targetGUID; - ObjectGuid _oldTargetGUID; - float _oldThreat; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); } + +private: + ObjectGuid _targetGUID; + ObjectGuid _oldTargetGUID; + float _oldThreat; }; -class npc_fel_geyser : public CreatureScript +struct npc_fel_geyser : public PassiveAI { -public: - npc_fel_geyser() : CreatureScript("npc_fel_geyser") { } + npc_fel_geyser(Creature* creature) : PassiveAI(creature) { } - struct npc_fel_geyserAI : public PassiveAI + void Reset() override { - npc_fel_geyserAI(Creature* creature) : PassiveAI(creature) { } - - void Reset() override - { - DoCastSelf(SPELL_FEL_GEYSER_2, true); - DoCastSelf(SPELL_BIRTH, true); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoCastSelf(SPELL_FEL_GEYSER_2, true); + DoCastSelf(SPELL_BIRTH, true); } }; // 42005 - Bloodboil -class spell_gurtogg_bloodboil_bloodboil : public SpellScriptLoader +class spell_gurtogg_bloodboil_bloodboil : public SpellScript { - public: - spell_gurtogg_bloodboil_bloodboil() : SpellScriptLoader("spell_gurtogg_bloodboil_bloodboil") { } + void FilterTargets(std::list& targets) + { + if (targets.size() <= 5) + return; - class spell_gurtogg_bloodboil_bloodboil_SpellScript : public SpellScript - { - void FilterTargets(std::list& targets) - { - if (targets.size() <= 5) - return; + // Sort the list of players + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); + // Resize so we only get top 5 + targets.resize(5); + } - // Sort the list of players - targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); - // Resize so we only get top 5 - targets.resize(5); - } - - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_gurtogg_bloodboil_bloodboil_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_gurtogg_bloodboil_bloodboil_SpellScript(); - } + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_gurtogg_bloodboil_bloodboil::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } }; // 40618 - Insignificance -class spell_gurtogg_bloodboil_insignificance : public SpellScriptLoader +class spell_gurtogg_bloodboil_insignificance : public SpellScript { -public: - spell_gurtogg_bloodboil_insignificance() : SpellScriptLoader("spell_gurtogg_bloodboil_insignificance") { } - - class spell_gurtogg_bloodboil_insignificance_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spell*/) override { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_FEL_RAGE_TARGET }); - } + return ValidateSpellInfo({ SPELL_FEL_RAGE_TARGET }); + } - void FilterTargets(std::list& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_FEL_RAGE_TARGET)); - } - - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_gurtogg_bloodboil_insignificance_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override + void FilterTargets(std::list& targets) { - return new spell_gurtogg_bloodboil_insignificance_SpellScript(); + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_FEL_RAGE_TARGET)); + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_gurtogg_bloodboil_insignificance::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } }; void AddSC_boss_gurtogg_bloodboil() { - new boss_gurtogg_bloodboil(); - new npc_fel_geyser(); - new spell_gurtogg_bloodboil_bloodboil(); - new spell_gurtogg_bloodboil_insignificance(); + RegisterBlackTempleCreatureAI(boss_gurtogg_bloodboil); + RegisterBlackTempleCreatureAI(npc_fel_geyser); + RegisterSpellScript(spell_gurtogg_bloodboil_bloodboil); + RegisterSpellScript(spell_gurtogg_bloodboil_insignificance); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index d7702f6e26..4efc75860a 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -17,7 +17,7 @@ #include "ScriptMgr.h" #include "black_temple.h" -#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" #include "InstanceScript.h" #include "Map.h" #include "MotionMaster.h" @@ -27,6 +27,7 @@ #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellAuraEffects.h" +#include "SpellInfo.h" #include "SpellScript.h" #include "TemporarySummon.h" @@ -158,6 +159,8 @@ enum IllidanSpells SPELL_DRAW_SOUL = 40904, SPELL_DRAW_SOUL_HEAL = 40903, SPELL_PARASITIC_SHADOWFIEND = 41917, + SPELL_PARASITIC_SHADOWFIEND_2 = 41914, + SPELL_REMOVE_PARASITIC_SHADOWFIEND = 41923, SPELL_AGONIZING_FLAMES = 40932, SPELL_AGONIZING_FLAMES_SELECTOR = 40834, SPELL_FRENZY = 40683, @@ -186,7 +189,16 @@ enum IllidanSpells SPELL_CAGED_TRAP_TELEPORT = 40693, SPELL_CAGE_TRAP = 40760, SPELL_CAGED_DEBUFF = 40695, - SPELL_EYE_BLAST = 39908 + SPELL_EYE_BLAST = 39908, + + // Blaze + SPELL_BLAZE = 40610, + + // Demon Fire + SPELL_DEMON_FIRE = 40029, + + // Flame Crash + SPELL_FLAME_CRASH_GROUND = 40836 }; enum IllidanMisc @@ -210,6 +222,7 @@ enum IllidanActions ACTION_FLAME_DEAD, ACTION_FINALIZE_AIR_PHASE, ACTION_START_PHASE_4, + ACTION_RESUME_COMBAT, ACTION_ILLIDAN_CAGED, ACTION_START_OUTRO, ACTION_MAIEV_DOWN_FADE @@ -222,7 +235,8 @@ enum IllidanPhases PHASE_MINIONS, PHASE_2, PHASE_3, - PHASE_4 + PHASE_4, + PHASE_OUTRO }; enum IllidanSplineMovement @@ -403,6 +417,12 @@ Position const IllidanDBTargetPoints[4] = { 660.3492f, 345.5749f, 353.2961f } }; +Position const BladesPositions[2] = +{ + { 676.226013f, 325.230988f }, + { 678.059998f, 285.220001f } +}; + uint32 const SummonCageTrapSpells[8] = { SPELL_SUMMON_CAGE_TRAP_1, @@ -433,2079 +453,1899 @@ private: class ChargeTargetSelector { - public: - ChargeTargetSelector(Unit const* unit) : _me(unit) { } +public: + ChargeTargetSelector() { } - bool operator()(Unit* unit) const - { - return unit->GetTypeId() == TYPEID_PLAYER && _me->GetDistance2d(unit) > 25.0f; - } - - private: - Unit const* _me; + bool operator()(Unit* unit) const + { + return unit->GetTypeId() == TYPEID_PLAYER + && unit->GetDistance2d(BladesPositions[0].GetPositionX(), BladesPositions[0].GetPositionY()) > 25.0f + && unit->GetDistance2d(BladesPositions[1].GetPositionX(), BladesPositions[1].GetPositionY()) > 25.0f; + } }; -class boss_illidan_stormrage : public CreatureScript +struct boss_illidan_stormrage : public BossAI { -public: - boss_illidan_stormrage() : CreatureScript("boss_illidan_stormrage") { } + boss_illidan_stormrage(Creature* creature) : BossAI(creature, DATA_ILLIDAN_STORMRAGE), + _minionsCount(0), _flameCount(0), _orientation(0.0f), _pillarIndex(0), _phase(0), _dead(false), _isDemon(false) { } - struct boss_illidan_stormrageAI : public BossAI + void Reset() override { - boss_illidan_stormrageAI(Creature* creature) : BossAI(creature, DATA_ILLIDAN_STORMRAGE), - _minionsCount(0), _flameCount(0), _orientation(0.0f), _pillarIndex(0), _phase(0), _dead(false), _isDemon(false) { } + _Reset(); + specialEvents.Reset(); + me->SummonCreatureGroup(SUMMON_GROUP); + me->LoadEquipment(1, true); + me->SetSheath(SHEATH_STATE_UNARMED); + me->SetControlled(false, UNIT_STATE_ROOT); + me->SetDisableGravity(false); + _dead = false; + _minionsCount = 0; + _flameCount = 0; + _phase = PHASE_1; + _isDemon = false; + if (instance->GetData(DATA_AKAMA_ILLIDAN_INTRO) && instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE) + if (Creature* akama = instance->GetCreature(DATA_AKAMA)) + akama->AI()->DoAction(ACTION_ACTIVE_AKAMA_INTRO); + } - void Reset() override - { - _Reset(); - specialEvents.Reset(); - me->SummonCreatureGroup(SUMMON_GROUP); - me->LoadEquipment(1, true); - me->SetSheath(SHEATH_STATE_UNARMED); - me->SetControlled(false, UNIT_STATE_ROOT); - me->SetDisableGravity(false); - _dead = false; - _minionsCount = 0; - _flameCount = 0; - _phase = PHASE_1; - _isDemon = false; - if (instance->GetData(DATA_AKAMA_ILLIDAN_INTRO) && instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE) - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_ACTIVE_AKAMA_INTRO); - } + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + me->SetCanDualWield(true); + if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) + musicController->PlayDirectMusic(EVENT_BT_SUMMIT_WALK_3_SOUND_ID); + specialEvents.ScheduleEvent(EVENT_EVADE_CHECK, 10s); + specialEvents.ScheduleEvent(EVENT_BERSERK, 25min); + ScheduleEvents(GROUP_PHASE_1, GROUP_PHASE_1); + events.ScheduleEvent(EVENT_TAUNT, Seconds(30), Seconds(60), GROUP_PHASE_ALL); + } - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - me->SetCanDualWield(true); - if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) - musicController->PlayDirectMusic(EVENT_BT_SUMMIT_WALK_3_SOUND_ID); - specialEvents.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10)); - specialEvents.ScheduleEvent(EVENT_BERSERK, Minutes(25)); - ScheduleEvents(GROUP_PHASE_1, GROUP_PHASE_1); - events.ScheduleEvent(EVENT_TAUNT, Seconds(30), Seconds(60), GROUP_PHASE_ALL); - } - - void ChangeOrientation(float orientation) - { - _orientation = orientation; - events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1), GROUP_PHASE_ALL); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_ILLIDAN_KILL); - } - - void ScheduleEvents(uint8 phase, uint8 group) - { - switch (phase) - { - case GROUP_PHASE_1: - events.ScheduleEvent(EVENT_FLAME_CRASH, Seconds(30), group); - events.ScheduleEvent(EVENT_DRAW_SOUL, Seconds(34), group); - events.ScheduleEvent(EVENT_SHEAR, Seconds(10), group); - events.ScheduleEvent(EVENT_PARASITIC_SHADOWFIEND, Seconds(26), group); - break; - case GROUP_PHASE_2: - events.ScheduleEvent(EVENT_FIREBALL, Seconds(1), Seconds(8), group); - events.ScheduleEvent(EVENT_EYE_BLAST, Seconds(1), Seconds(30), group); - if (roll_chance_i(50)) - events.ScheduleEvent(EVENT_DARK_BARRAGE, Seconds(1), Seconds(20), group); - break; - case GROUP_PHASE_3: - ScheduleEvents(GROUP_PHASE_1, group); - events.ScheduleEvent(EVENT_AGONIZING_FLAMES, Seconds(21), group); - events.ScheduleEvent(EVENT_DEMON, Seconds(60), group); - break; - case GROUP_PHASE_DEMON: - events.ScheduleEvent(EVENT_SHADOW_BLAST, Seconds(1), group); - events.ScheduleEvent(EVENT_FLAME_BURST, Seconds(6), group); - events.ScheduleEvent(EVENT_SHADOW_DEMON, Seconds(18), Seconds(30), group); - break; - case GROUP_PHASE_4: - ScheduleEvents(GROUP_PHASE_3, group); - events.ScheduleEvent(EVENT_FRENZY, Seconds(40), group); - break; - default: - break; - } - } - - void JustSummoned(Creature* summon) override - { + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_PARASITIC_SHADOWFIEND) + summons.Summon(summon); + else BossAI::JustSummoned(summon); - if (summon->GetEntry() == NPC_ILLIDARI_ELITE) + } + + void ChangeOrientation(float orientation) + { + _orientation = orientation; + events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1), GROUP_PHASE_ALL); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_ILLIDAN_KILL); + } + + void ScheduleEvents(uint8 phase, uint8 group) + { + switch (phase) + { + case GROUP_PHASE_1: + events.ScheduleEvent(EVENT_FLAME_CRASH, Seconds(30), group); + events.ScheduleEvent(EVENT_DRAW_SOUL, Seconds(34), group); + events.ScheduleEvent(EVENT_SHEAR, Seconds(10), group); + events.ScheduleEvent(EVENT_PARASITIC_SHADOWFIEND, Seconds(26), group); + break; + case GROUP_PHASE_2: + events.ScheduleEvent(EVENT_FIREBALL, Seconds(1), Seconds(8), group); + events.ScheduleEvent(EVENT_EYE_BLAST, Seconds(1), Seconds(30), group); + if (roll_chance_i(50)) + events.ScheduleEvent(EVENT_DARK_BARRAGE, Seconds(1), Seconds(20), group); + break; + case GROUP_PHASE_3: + ScheduleEvents(GROUP_PHASE_1, group); + events.ScheduleEvent(EVENT_AGONIZING_FLAMES, Seconds(21), group); + events.ScheduleEvent(EVENT_DEMON, Seconds(60), group); + break; + case GROUP_PHASE_DEMON: + events.ScheduleEvent(EVENT_SHADOW_BLAST, Seconds(1), group); + events.ScheduleEvent(EVENT_FLAME_BURST, Seconds(6), group); + events.ScheduleEvent(EVENT_SHADOW_DEMON, Seconds(18), Seconds(30), group); + break; + case GROUP_PHASE_4: + ScheduleEvents(GROUP_PHASE_3, group); + events.ScheduleEvent(EVENT_FRENZY, Seconds(40), group); + break; + default: + break; + } + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + if (summon->GetEntry() == NPC_ILLIDARI_ELITE) + _minionsCount--; + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + summons.DespawnAll(); + specialEvents.Reset(); + _DespawnAtEvade(); + } + + void DoAction(int32 actionId) override + { + switch (actionId) + { + case ACTION_START_ENCOUNTER: + events.SetPhase(PHASE_INTRO); + me->RemoveAurasDueToSpell(SPELL_KNEEL); + events.ScheduleEvent(EVENT_START_INTRO, Seconds(2), GROUP_PHASE_ALL); + events.ScheduleEvent(EVENT_UNCONVINCED, Seconds(24), GROUP_PHASE_ALL); if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - AddThreat(akama, 1000.0f, summon); - } - - void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override - { - if (summon->GetEntry() == NPC_ILLIDARI_ELITE) - _minionsCount--; - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - summons.DespawnAll(); - specialEvents.Reset(); - _DespawnAtEvade(); - } - - void DoAction(int32 actionId) override - { - switch (actionId) + akama->AI()->DoAction(ACTION_FREE); + break; + case ACTION_INTRO_DONE: + instance->SetData(DATA_AKAMA_ILLIDAN_INTRO, 0); + break; + case ACTION_START_MINIONS: + Talk(SAY_ILLIDAN_MINION); + if (Creature* akama = instance->GetCreature(DATA_AKAMA)) + akama->AI()->DoAction(ACTION_START_MINIONS); + break; + case ACTION_START_MINIONS_WEAVE: + events.ScheduleEvent(EVENT_MINIONS_WEAVE, Milliseconds(1), GROUP_PHASE_ALL); + break; + case ACTION_START_PHASE_2: { - case ACTION_START_ENCOUNTER: - events.SetPhase(PHASE_INTRO); - me->RemoveAurasDueToSpell(SPELL_KNEEL); - events.ScheduleEvent(EVENT_START_INTRO, Seconds(2), GROUP_PHASE_ALL); - events.ScheduleEvent(EVENT_UNCONVINCED, Seconds(24), GROUP_PHASE_ALL); - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_FREE); - break; - case ACTION_INTRO_DONE: - instance->SetData(DATA_AKAMA_ILLIDAN_INTRO, 0); - break; - case ACTION_START_MINIONS: - Talk(SAY_ILLIDAN_MINION); - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_START_MINIONS); - break; - case ACTION_START_MINIONS_WEAVE: - events.ScheduleEvent(EVENT_MINIONS_WEAVE, Milliseconds(1), GROUP_PHASE_ALL); - break; - case ACTION_START_PHASE_2: + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->SetDisableGravity(true); + DoPlaySoundToSet(me, ILLIDAN_TAKEOFF_SOUND_ID); + events.ScheduleEvent(EVENT_FLY, Seconds(1), GROUP_PHASE_ALL); + events.CancelEventGroup(GROUP_PHASE_1); + break; + } + case ACTION_FLAME_DEAD: + _flameCount++; + if (_flameCount == 2) { - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - me->SetDisableGravity(true); - DoPlaySoundToSet(me, ILLIDAN_TAKEOFF_SOUND_ID); - events.ScheduleEvent(EVENT_FLY, Seconds(1), GROUP_PHASE_ALL); - events.CancelEventGroup(GROUP_PHASE_1); - break; + _flameCount = 0; + DoAction(ACTION_FINALIZE_AIR_PHASE); } - case ACTION_FLAME_DEAD: - _flameCount++; - if (_flameCount == 2) - { - _flameCount = 0; - DoAction(ACTION_FINALIZE_AIR_PHASE); - } - break; - case ACTION_FINALIZE_AIR_PHASE: - me->InterruptNonMeleeSpells(false); - me->GetMotionMaster()->Clear(); - events.CancelEventGroup(GROUP_PHASE_2); - _phase = PHASE_3; - events.CancelEvent(EVENT_FLY_TO_RANDOM_PILLAR); - me->GetMotionMaster()->MovePoint(POINT_ILLIDAN_MIDDLE, IllidanMiddlePoint); - break; - case ACTION_START_PHASE_4: - events.CancelEventGroup(GROUP_PHASE_3); - DoCastSelf(SPELL_SHADOW_PRISON, true); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_SHADOW_PRISON_TEXT, Milliseconds(500), GROUP_PHASE_ALL); - break; - case ACTION_ILLIDAN_CAGED: - for (uint32 summonSpell : SummonCageTrapSpells) - DoCastSelf(summonSpell, true); - DoCastSelf(SPELL_CAGE_TRAP, true); - break; - case ACTION_START_OUTRO: - me->AttackStop(); - events.Reset(); - specialEvents.Reset(); - DoCastSelf(SPELL_DEATH, true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - events.ScheduleEvent(EVENT_DEFEATED_TEXT, Seconds(4)); - break; - default: - break; - } + break; + case ACTION_FINALIZE_AIR_PHASE: + me->InterruptNonMeleeSpells(false); + me->GetMotionMaster()->Clear(); + events.CancelEventGroup(GROUP_PHASE_2); + _phase = PHASE_3; + events.CancelEvent(EVENT_FLY_TO_RANDOM_PILLAR); + me->GetMotionMaster()->MovePoint(POINT_ILLIDAN_MIDDLE, IllidanMiddlePoint); + break; + case ACTION_START_PHASE_4: + events.CancelEventGroup(GROUP_PHASE_3); + DoCastSelf(SPELL_SHADOW_PRISON, true); + summons.DoAction(ACTION_START_PHASE_4, EntryCheckPredicate(NPC_PARASITIC_SHADOWFIEND)); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + events.ScheduleEvent(EVENT_SHADOW_PRISON_TEXT, Milliseconds(500), GROUP_PHASE_ALL); + break; + case ACTION_ILLIDAN_CAGED: + for (uint32 summonSpell : SummonCageTrapSpells) + DoCastSelf(summonSpell, true); + DoCastSelf(SPELL_CAGE_TRAP, true); + break; + case ACTION_START_OUTRO: + me->AttackStop(); + events.Reset(); + specialEvents.Reset(); + DoCastSelf(SPELL_DEATH, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + events.ScheduleEvent(EVENT_DEFEATED_TEXT, 4s); + break; + default: + break; } + } - void JustDied(Unit* /*killer*/) override + void JustDied(Unit* /*killer*/) override + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + instance->SetBossState(DATA_ILLIDAN_STORMRAGE, DONE); + events.Reset(); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (pointId) { - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - instance->SetBossState(DATA_ILLIDAN_STORMRAGE, DONE); - events.Reset(); + case POINT_THROW_GLAIVE: + DoPlaySoundToSet(me, ILLIDAN_WARGLAIVE_SOUND_ID); + events.ScheduleEvent(EVENT_THROW_WARGLAIVE, Seconds(2), GROUP_PHASE_ALL); + events.ScheduleEvent(EVENT_FACE_MIDDLE, Milliseconds(1), GROUP_PHASE_ALL); + break; + case POINT_RANDOM_PILLAR: + { + float orientation = IllidanPhase2Positions[_pillarIndex].GetOrientation(); + ChangeOrientation(orientation); + ScheduleEvents(GROUP_PHASE_2, GROUP_PHASE_2); + break; + } + case POINT_ILLIDAN_MIDDLE: + { + float orientation = IllidanMiddlePoint.GetOrientation(); + ChangeOrientation(orientation); + + std::list triggers; + GetCreatureListWithEntryInGrid(triggers, me, NPC_BLADE_OF_AZZINOTH, 150.0f); + for (Creature* trigger : triggers) + trigger->CastSpell(trigger, SPELL_GLAIVE_RETURNS, true); + + events.ScheduleEvent(EVENT_GLAIVE_EMOTE, Seconds(3), GROUP_PHASE_ALL); + break; + } + default: + break; } + } - void MovementInform(uint32 type, uint32 pointId) override + void EnterEvadeModeIfNeeded() + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->GetSource()) + if (player->IsAlive() && !player->IsGameMaster() && CheckBoundary(player)) + return; + + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); + } + + void SummonMinions() + { + uint8 needSummon = MAX_MINIONS_NUMBER - _minionsCount; + for (uint8 i = 0; i < needSummon; ++i) { - if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) - return; - - switch (pointId) - { - case POINT_THROW_GLAIVE: - DoPlaySoundToSet(me, ILLIDAN_WARGLAIVE_SOUND_ID); - events.ScheduleEvent(EVENT_THROW_WARGLAIVE, Seconds(2), GROUP_PHASE_ALL); - events.ScheduleEvent(EVENT_FACE_MIDDLE, Milliseconds(1), GROUP_PHASE_ALL); - break; - case POINT_RANDOM_PILLAR: - { - float orientation = IllidanPhase2Positions[_pillarIndex].GetOrientation(); - ChangeOrientation(orientation); - ScheduleEvents(GROUP_PHASE_2, GROUP_PHASE_2); - break; - } - case POINT_ILLIDAN_MIDDLE: - { - float orientation = IllidanMiddlePoint.GetOrientation(); - ChangeOrientation(orientation); - - std::list triggers; - GetCreatureListWithEntryInGrid(triggers, me, NPC_BLADE_OF_AZZINOTH, 150.0f); - for (Creature* trigger : triggers) - trigger->CastSpell(trigger, SPELL_GLAIVE_RETURNS, true); - - events.ScheduleEvent(EVENT_GLAIVE_EMOTE, Seconds(3), GROUP_PHASE_ALL); - break; - } - default: - break; - } + _minionsCount++; + me->SummonCreature(NPC_ILLIDARI_ELITE, MinionsSpawnPositions[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6s); } + } - void EnterEvadeModeIfNeeded() + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth() && (!who || who->GetGUID() != me->GetGUID())) { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) - if (player->IsAlive() && !player->IsGameMaster() && CheckBoundary(player)) - return; - - EnterEvadeMode(EVADE_REASON_NO_HOSTILES); - } - - void SummonMinions() - { - uint8 needSummon = MAX_MINIONS_NUMBER - _minionsCount; - for (uint8 i = 0; i < needSummon; ++i) + damage = me->GetHealth() - 1; + if (!_dead) { - _minionsCount++; - me->SummonCreature(NPC_ILLIDARI_ELITE, MinionsSpawnPositions[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 6000); - } - } - - void DamageTaken(Unit* who, uint32 &damage) override - { - - if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID()) - { - damage = me->GetHealth() - 1; - if (!_dead) - { - if (_isDemon) - { - events.Reset(); - specialEvents.Reset(); - DoCastSelf(SPELL_DEMON_TRANSFORM_1); - return; - } - _dead = true; - DoAction(ACTION_START_OUTRO); - if (Creature* maiev = instance->GetCreature(DATA_MAIEV)) - maiev->AI()->DoAction(ACTION_START_OUTRO); - } - } - else if (me->HealthBelowPct(90) && _phase < PHASE_MINIONS) - { - _phase = PHASE_MINIONS; - DoAction(ACTION_START_MINIONS); - } - else if (me->HealthBelowPct(65) && _phase < PHASE_2) - { - _phase = PHASE_2; - DoAction(ACTION_START_PHASE_2); - } - else if (me->HealthBelowPct(30) && _phase < PHASE_4) - { - _phase = PHASE_4; - if (_isDemon) { - _isDemon = false; + events.Reset(); + specialEvents.Reset(); + DoCastSelf(SPELL_DEMON_TRANSFORM_1); + return; + } + _dead = true; + summons.DespawnEntry(NPC_PARASITIC_SHADOWFIEND); + DoCastSelf(SPELL_REMOVE_PARASITIC_SHADOWFIEND, true); + DoAction(ACTION_START_OUTRO); + if (Creature* maiev = instance->GetCreature(DATA_MAIEV)) + maiev->AI()->DoAction(ACTION_START_OUTRO); + } + } + else if (me->HealthBelowPct(90) && _phase < PHASE_MINIONS) + { + _phase = PHASE_MINIONS; + DoAction(ACTION_START_MINIONS); + } + else if (me->HealthBelowPct(65) && _phase < PHASE_2) + { + _phase = PHASE_2; + DoAction(ACTION_START_PHASE_2); + } + else if (me->HealthBelowPct(30) && _phase < PHASE_4) + { + _phase = PHASE_4; + + if (_isDemon) + { + _isDemon = false; + me->SetControlled(false, UNIT_STATE_ROOT); + events.CancelEventGroup(GROUP_PHASE_DEMON); + me->InterruptNonMeleeSpells(false); + DoCastSelf(SPELL_DEMON_TRANSFORM_1, true); + events.ScheduleEvent(EVENT_PHASE_4_DELAYED, Seconds(12), GROUP_PHASE_ALL); + } + else + DoAction(ACTION_START_PHASE_4); + } + } + + void ExecuteSpecialEvents() + { + while (uint32 eventId = specialEvents.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BERSERK: + Talk(SAY_ILLIDAN_ENRAGE); + DoCastSelf(SPELL_BERSERK, true); + break; + case EVENT_CANCEL_DEMON_FORM: + me->InterruptNonMeleeSpells(false); me->SetControlled(false, UNIT_STATE_ROOT); events.CancelEventGroup(GROUP_PHASE_DEMON); - me->InterruptNonMeleeSpells(false); DoCastSelf(SPELL_DEMON_TRANSFORM_1, true); - events.ScheduleEvent(EVENT_PHASE_4_DELAYED, Seconds(12), GROUP_PHASE_ALL); - } - else - DoAction(ACTION_START_PHASE_4); + events.ScheduleEvent(EVENT_RESUME_COMBAT_DEMON, Seconds(12), GROUP_PHASE_ALL); + _isDemon = false; + break; + case EVENT_EVADE_CHECK: + EnterEvadeModeIfNeeded(); + specialEvents.Repeat(Seconds(10)); + break; + default: + break; } } + } - void ExecuteSpecialEvents() + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + return; + + specialEvents.Update(diff); + + ExecuteSpecialEvents(); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - while (uint32 eventId = specialEvents.ExecuteEvent()) + switch (eventId) { - switch (eventId) + case EVENT_START_INTRO: + Talk(SAY_ILLIDAN_DUPLICITY); + break; + case EVENT_UNCONVINCED: + Talk(SAY_ILLIDAN_UNCONVINCED); + events.ScheduleEvent(EVENT_PREPARED, Seconds(14), GROUP_PHASE_ALL); + break; + case EVENT_PREPARED: + Talk(SAY_ILLIDAN_PREPARED); + me->SetSheath(SHEATH_STATE_MELEE); + events.ScheduleEvent(EVENT_ENCOUNTER_START, Seconds(3), GROUP_PHASE_ALL); + break; + case EVENT_ENCOUNTER_START: + me->SetImmuneToAll(false); + DoZoneInCombat(); + if (Creature* akama = instance->GetCreature(DATA_AKAMA)) + akama->AI()->DoAction(ACTION_START_ENCOUNTER); + break; + case EVENT_FLAME_CRASH: + DoCastVictim(SPELL_FLAME_CRASH); + events.Repeat(Seconds(30)); + break; + case EVENT_DRAW_SOUL: + DoCastAOE(SPELL_DRAW_SOUL); + events.Repeat(Seconds(34)); + break; + case EVENT_SHEAR: + DoCastVictim(SPELL_SHEAR); + events.Repeat(Seconds(12)); + break; + case EVENT_PARASITIC_SHADOWFIEND: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_PARASITIC_SHADOWFIEND); + events.Repeat(Seconds(30)); + break; + case EVENT_MINIONS_WEAVE: + if (_dead) + return; + SummonMinions(); + events.Repeat(Seconds(30)); + break; + case EVENT_MOVE_TO_WARGLAIVE_POINT: { - case EVENT_BERSERK: - Talk(SAY_ILLIDAN_ENRAGE); - DoCastSelf(SPELL_BERSERK, true); - break; - case EVENT_CANCEL_DEMON_FORM: - me->InterruptNonMeleeSpells(false); - me->SetControlled(false, UNIT_STATE_ROOT); - events.CancelEventGroup(GROUP_PHASE_DEMON); - DoCastSelf(SPELL_DEMON_TRANSFORM_1, true); - events.ScheduleEvent(EVENT_RESUME_COMBAT_DEMON, Seconds(12), GROUP_PHASE_ALL); - _isDemon = false; - break; - case EVENT_EVADE_CHECK: - EnterEvadeModeIfNeeded(); - specialEvents.Repeat(Seconds(10)); - break; - default: + Position pos; + std::list triggers; + GetCreatureListWithEntryInGrid(triggers, me, NPC_GLAIVE_WORLD_TRIGGER, 150.0f); + triggers.remove_if([](WorldObject* unit) + { + return unit->GetPositionZ() < 355.0f || unit->GetPositionZ() > 365.0f; + }); + + if (triggers.empty()) break; + + triggers.sort(Trinity::ObjectDistanceOrderPred(me)); + pos.Relocate(triggers.front()); + pos.SetOrientation(0.0f); + me->GetMotionMaster()->MovePoint(POINT_THROW_GLAIVE, pos); + if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) + musicController->PlayDirectMusic(EVENT_BT_STORM_WALK_HERO_2_SOUND_ID); + break; } + case EVENT_THROW_WARGLAIVE: + DoCastAOE(SPELL_THROW_GLAIVE); + events.ScheduleEvent(EVENT_THROW_WARGLAIVE_2, Seconds(1), GROUP_PHASE_ALL); + break; + case EVENT_THROW_WARGLAIVE_2: + DoCastAOE(SPELL_THROW_GLAIVE2); + me->SetSheath(SHEATH_STATE_UNARMED); + events.ScheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, Seconds(2), GROUP_PHASE_ALL); + break; + case EVENT_CHANGE_ORIENTATION: + me->SetFacingTo(_orientation); + break; + case EVENT_FLY: + ChangeOrientation(3.137039f); + events.ScheduleEvent(EVENT_MOVE_TO_WARGLAIVE_POINT, Seconds(6), GROUP_PHASE_ALL); + break; + case EVENT_FLY_TO_RANDOM_PILLAR: + { + events.CancelEventGroup(GROUP_PHASE_2); + _pillarIndex = urand(0, 3); + me->GetMotionMaster()->MovePoint(POINT_RANDOM_PILLAR, IllidanPhase2Positions[_pillarIndex]); + events.Repeat(Seconds(30)); + break; + } + case EVENT_FACE_MIDDLE: + { + float angle = me->GetAngle(IllidanMiddlePoint); + me->SetFacingTo(angle); + break; + } + case EVENT_EYE_BLAST: + { + events.CancelEvent(EVENT_DARK_BARRAGE); + Position pos = IllidanDBTargetSpawnPositions[_pillarIndex]; + if (TempSummon* dbTarget = me->SummonCreature(NPC_ILLIDAN_DB_TARGET, pos, TEMPSUMMON_MANUAL_DESPAWN)) + { + Talk(SAY_ILLIDAN_EYE_BLAST); + DoCast(dbTarget, SPELL_EYE_BLAST); + dbTarget->GetMotionMaster()->MovePoint(POINT_DB_TARGET, IllidanDBTargetPoints[_pillarIndex]); + } + break; + } + case EVENT_DARK_BARRAGE: + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true)) + DoCast(target, SPELL_DARK_BARRAGE); + events.RescheduleEvent(EVENT_EYE_BLAST, Seconds(5), GROUP_PHASE_2); + Milliseconds currentTime = Milliseconds(events.GetTimeUntilEvent(EVENT_FLY_TO_RANDOM_PILLAR)); + events.RescheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, currentTime + 30s, GROUP_PHASE_2); + break; + } + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true)) + DoCast(target, SPELL_FIREBALL); + events.Repeat(Seconds(2), Seconds(4)); + break; + case EVENT_GLAIVE_EMOTE: + me->SetDisableGravity(false); + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->SetSheath(SHEATH_STATE_MELEE); + events.ScheduleEvent(EVENT_RESUME_COMBAT, Seconds(3), GROUP_PHASE_ALL); + break; + case EVENT_RESUME_COMBAT: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + ScheduleEvents(GROUP_PHASE_3, GROUP_PHASE_3); + if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) + musicController->PlayDirectMusic(EVENT_BT_STORM_WALK_UNI_3_SOUND_ID); + break; + case EVENT_AGONIZING_FLAMES: + DoCastSelf(SPELL_AGONIZING_FLAMES_SELECTOR); + events.Repeat(Seconds(53)); + break; + case EVENT_DEMON: + me->SetControlled(true, UNIT_STATE_ROOT); + _isDemon = true; + events.CancelEventGroup(_phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4); + me->LoadEquipment(0, true); + DoCastSelf(SPELL_DEMON_TRANSFORM_1, true); + events.ScheduleEvent(EVENT_DEMON_TEXT, Seconds(2), GROUP_PHASE_ALL); + specialEvents.ScheduleEvent(EVENT_CANCEL_DEMON_FORM, Minutes(1) + Seconds(12)); + events.ScheduleEvent(EVENT_SCHEDULE_DEMON_SPELLS, 15s); + break; + case EVENT_SCHEDULE_DEMON_SPELLS: + ResetThreatList(); + ScheduleEvents(GROUP_PHASE_DEMON, GROUP_PHASE_DEMON); + break; + case EVENT_DEMON_TEXT: + Talk(SAY_ILLIDAN_MORPH); + break; + case EVENT_RESUME_COMBAT_DEMON: + { + uint8 group = _phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4; + ResetThreatList(); + ScheduleEvents(group, group); + me->LoadEquipment(1, true); + break; + } + case EVENT_FLAME_BURST: + DoCastSelf(SPELL_FLAME_BURST); + events.Repeat(Seconds(22)); + break; + case EVENT_SHADOW_DEMON: + DoCastSelf(SPELL_SUMMON_SHADOWDEMON); + break; + case EVENT_SHADOW_BLAST: + DoCastVictim(SPELL_SHADOW_BLAST); + events.Repeat(Seconds(2)); + break; + case EVENT_PHASE_4_DELAYED: + DoAction(ACTION_START_PHASE_4); + break; + case EVENT_SHADOW_PRISON_TEXT: + Talk(SAY_ILLIDAN_SHADOW_PRISON); + events.ScheduleEvent(EVENT_SUMMON_MAIEV, Seconds(9), GROUP_PHASE_ALL); + break; + case EVENT_SUMMON_MAIEV: + DoCastSelf(SPELL_SUMMON_MAIEV); + if (Creature* maiev = instance->GetCreature(DATA_MAIEV)) + me->SetFacingToObject(maiev); + events.ScheduleEvent(EVENT_CONFRONT_MAIEV_TEXT, Seconds(9), GROUP_PHASE_ALL); + break; + case EVENT_CONFRONT_MAIEV_TEXT: + Talk(SAY_ILLIDAN_CONFRONT_MAIEV); + events.ScheduleEvent(EVENT_RESUME_COMBAT_PHASE_4, Seconds(13), GROUP_PHASE_ALL); + break; + case EVENT_RESUME_COMBAT_PHASE_4: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + ScheduleEvents(GROUP_PHASE_4, GROUP_PHASE_4); + summons.DoAction(ACTION_RESUME_COMBAT, EntryCheckPredicate(NPC_PARASITIC_SHADOWFIEND)); + break; + case EVENT_FRENZY: + DoCastSelf(SPELL_FRENZY); + Talk(SAY_ILLIDAN_FRENZY); + events.Repeat(Seconds(40)); + break; + case EVENT_TAUNT: + Talk(SAY_ILLIDAN_TAUNT); + events.Repeat(Seconds(30), Seconds(60)); + break; + case EVENT_DEFEATED_TEXT: + Talk(SAY_ILLIDAN_DEFEATED); + if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) + musicController->PlayDirectMusic(EVENT_BT_ARRIVAL_WALK_HERO_1_SOUND_ID); + events.ScheduleEvent(EVENT_QUIET_SUICIDE, 18s); + break; + case EVENT_QUIET_SUICIDE: + { + DoCastSelf(SPELL_QUIET_SUICIDE, true); + if (Creature* akama = instance->GetCreature(DATA_AKAMA)) + akama->AI()->DoAction(ACTION_START_OUTRO); + ObjectGuid _akamaGUID = instance->GetGuidData(DATA_AKAMA); + ObjectGuid _maievGUID = instance->GetGuidData(DATA_MAIEV); + summons.DespawnIf([_akamaGUID, _maievGUID](ObjectGuid unitGuid) + { + return unitGuid != _akamaGUID && unitGuid != _maievGUID; + }); + break; + } + default: + break; } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) - return; - - specialEvents.Update(diff); - - ExecuteSpecialEvents(); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_START_INTRO: - Talk(SAY_ILLIDAN_DUPLICITY); - break; - case EVENT_UNCONVINCED: - Talk(SAY_ILLIDAN_UNCONVINCED); - events.ScheduleEvent(EVENT_PREPARED, Seconds(14), GROUP_PHASE_ALL); - break; - case EVENT_PREPARED: - Talk(SAY_ILLIDAN_PREPARED); - me->SetSheath(SHEATH_STATE_MELEE); - events.ScheduleEvent(EVENT_ENCOUNTER_START, Seconds(3), GROUP_PHASE_ALL); - break; - case EVENT_ENCOUNTER_START: - me->SetImmuneToAll(false); - DoZoneInCombat(); - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_START_ENCOUNTER); - break; - case EVENT_FLAME_CRASH: - DoCastVictim(SPELL_FLAME_CRASH); - events.Repeat(Seconds(30)); - break; - case EVENT_DRAW_SOUL: - DoCastAOE(SPELL_DRAW_SOUL); - events.Repeat(Seconds(34)); - break; - case EVENT_SHEAR: - DoCastVictim(SPELL_SHEAR); - events.Repeat(Seconds(12)); - break; - case EVENT_PARASITIC_SHADOWFIEND: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - DoCast(target, SPELL_PARASITIC_SHADOWFIEND); - events.Repeat(Seconds(30)); - break; - case EVENT_MINIONS_WEAVE: - SummonMinions(); - events.Repeat(Seconds(30)); - break; - case EVENT_MOVE_TO_WARGLAIVE_POINT: - { - Position pos; - std::list triggers; - GetCreatureListWithEntryInGrid(triggers, me, NPC_GLAIVE_WORLD_TRIGGER, 150.0f); - triggers.remove_if([](WorldObject* unit) - { - return unit->GetPositionZ() < 355.0f || unit->GetPositionZ() > 365.0f; - }); - - if (triggers.empty()) - break; - - triggers.sort(Trinity::ObjectDistanceOrderPred(me)); - pos.Relocate(triggers.front()); - pos.SetOrientation(0.0f); - me->GetMotionMaster()->MovePoint(POINT_THROW_GLAIVE, pos); - if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) - musicController->PlayDirectMusic(EVENT_BT_STORM_WALK_HERO_2_SOUND_ID); - break; - } - case EVENT_THROW_WARGLAIVE: - DoCastAOE(SPELL_THROW_GLAIVE); - events.ScheduleEvent(EVENT_THROW_WARGLAIVE_2, Seconds(1), GROUP_PHASE_ALL); - break; - case EVENT_THROW_WARGLAIVE_2: - DoCastAOE(SPELL_THROW_GLAIVE2); - me->SetSheath(SHEATH_STATE_UNARMED); - events.ScheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, Seconds(2), GROUP_PHASE_ALL); - break; - case EVENT_CHANGE_ORIENTATION: - me->SetFacingTo(_orientation); - break; - case EVENT_FLY: - ChangeOrientation(3.137039f); - events.ScheduleEvent(EVENT_MOVE_TO_WARGLAIVE_POINT, Seconds(6), GROUP_PHASE_ALL); - break; - case EVENT_FLY_TO_RANDOM_PILLAR: - { - events.CancelEventGroup(GROUP_PHASE_2); - _pillarIndex = urand(0, 3); - me->GetMotionMaster()->MovePoint(POINT_RANDOM_PILLAR, IllidanPhase2Positions[_pillarIndex]); - events.Repeat(Seconds(30)); - break; - } - case EVENT_FACE_MIDDLE: - { - float angle = me->GetAngle(IllidanMiddlePoint); - me->SetFacingTo(angle); - break; - } - case EVENT_EYE_BLAST: - { - events.CancelEvent(EVENT_DARK_BARRAGE); - Position pos = IllidanDBTargetSpawnPositions[_pillarIndex]; - if (TempSummon* dbTarget = me->SummonCreature(NPC_ILLIDAN_DB_TARGET, pos, TEMPSUMMON_MANUAL_DESPAWN)) - { - Talk(SAY_ILLIDAN_EYE_BLAST); - DoCast(dbTarget, SPELL_EYE_BLAST); - dbTarget->GetMotionMaster()->MovePoint(POINT_DB_TARGET, IllidanDBTargetPoints[_pillarIndex]); - } - break; - } - case EVENT_DARK_BARRAGE: - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true)) - DoCast(target, SPELL_DARK_BARRAGE); - events.RescheduleEvent(EVENT_EYE_BLAST, Seconds(5), GROUP_PHASE_2); - uint32 currentTime = events.GetNextEventTime(EVENT_FLY_TO_RANDOM_PILLAR); - events.RescheduleEvent(EVENT_FLY_TO_RANDOM_PILLAR, Seconds(currentTime) + Seconds(30), GROUP_PHASE_2); - break; - } - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150.0f, true)) - DoCast(target, SPELL_FIREBALL); - events.Repeat(Seconds(2), Seconds(4)); - break; - case EVENT_GLAIVE_EMOTE: - me->SetDisableGravity(false); - me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - me->SetSheath(SHEATH_STATE_MELEE); - events.ScheduleEvent(EVENT_RESUME_COMBAT, Seconds(3), GROUP_PHASE_ALL); - break; - case EVENT_RESUME_COMBAT: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - ScheduleEvents(GROUP_PHASE_3, GROUP_PHASE_3); - if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) - musicController->PlayDirectMusic(EVENT_BT_STORM_WALK_UNI_3_SOUND_ID); - break; - case EVENT_AGONIZING_FLAMES: - DoCastSelf(SPELL_AGONIZING_FLAMES_SELECTOR); - events.Repeat(Seconds(53)); - break; - case EVENT_DEMON: - me->SetControlled(true, UNIT_STATE_ROOT); - _isDemon = true; - events.CancelEventGroup(_phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4); - me->LoadEquipment(0, true); - DoCastSelf(SPELL_DEMON_TRANSFORM_1, true); - events.ScheduleEvent(EVENT_DEMON_TEXT, Seconds(2), GROUP_PHASE_ALL); - specialEvents.ScheduleEvent(EVENT_CANCEL_DEMON_FORM, Minutes(1) + Seconds(12)); - events.ScheduleEvent(EVENT_SCHEDULE_DEMON_SPELLS, Seconds(15)); - break; - case EVENT_SCHEDULE_DEMON_SPELLS: - ResetThreatList(); - ScheduleEvents(GROUP_PHASE_DEMON, GROUP_PHASE_DEMON); - break; - case EVENT_DEMON_TEXT: - Talk(SAY_ILLIDAN_MORPH); - break; - case EVENT_RESUME_COMBAT_DEMON: - { - uint8 group = _phase == PHASE_3 ? GROUP_PHASE_3 : GROUP_PHASE_4; - ResetThreatList(); - ScheduleEvents(group, group); - me->LoadEquipment(1, true); - break; - } - case EVENT_FLAME_BURST: - DoCastSelf(SPELL_FLAME_BURST); - events.Repeat(Seconds(22)); - break; - case EVENT_SHADOW_DEMON: - DoCastSelf(SPELL_SUMMON_SHADOWDEMON); - break; - case EVENT_SHADOW_BLAST: - DoCastVictim(SPELL_SHADOW_BLAST); - events.Repeat(Seconds(2)); - break; - case EVENT_PHASE_4_DELAYED: - DoAction(ACTION_START_PHASE_4); - break; - case EVENT_SHADOW_PRISON_TEXT: - Talk(SAY_ILLIDAN_SHADOW_PRISON); - events.ScheduleEvent(EVENT_SUMMON_MAIEV, Seconds(9), GROUP_PHASE_ALL); - break; - case EVENT_SUMMON_MAIEV: - DoCastSelf(SPELL_SUMMON_MAIEV); - if (Creature* maiev = instance->GetCreature(DATA_MAIEV)) - me->SetFacingToObject(maiev); - events.ScheduleEvent(EVENT_CONFRONT_MAIEV_TEXT, Seconds(9), GROUP_PHASE_ALL); - break; - case EVENT_CONFRONT_MAIEV_TEXT: - Talk(SAY_ILLIDAN_CONFRONT_MAIEV); - events.ScheduleEvent(EVENT_RESUME_COMBAT_PHASE_4, Seconds(13), GROUP_PHASE_ALL); - break; - case EVENT_RESUME_COMBAT_PHASE_4: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - ScheduleEvents(GROUP_PHASE_4, GROUP_PHASE_4); - break; - case EVENT_FRENZY: - DoCastSelf(SPELL_FRENZY); - Talk(SAY_ILLIDAN_FRENZY); - events.Repeat(Seconds(40)); - break; - case EVENT_TAUNT: - Talk(SAY_ILLIDAN_TAUNT); - events.Repeat(Seconds(30), Seconds(60)); - break; - case EVENT_DEFEATED_TEXT: - Talk(SAY_ILLIDAN_DEFEATED); - if (GameObject* musicController = instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) - musicController->PlayDirectMusic(EVENT_BT_ARRIVAL_WALK_HERO_1_SOUND_ID); - events.ScheduleEvent(EVENT_QUIET_SUICIDE, Seconds(18)); - break; - case EVENT_QUIET_SUICIDE: - { - DoCastSelf(SPELL_QUIET_SUICIDE, true); - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_START_OUTRO); - ObjectGuid _akamaGUID = instance->GetGuidData(DATA_AKAMA); - ObjectGuid _maievGUID = instance->GetGuidData(DATA_MAIEV); - summons.DespawnIf([_akamaGUID, _maievGUID](ObjectGuid unitGuid) - { - return unitGuid != _akamaGUID && unitGuid != _maievGUID; - }); - break; - } - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - private: - uint8 _minionsCount; - uint8 _flameCount; - float _orientation; - uint8 _pillarIndex; - uint8 _phase; - bool _dead; - bool _isDemon; - EventMap specialEvents; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); } + +private: + uint8 _minionsCount; + uint8 _flameCount; + float _orientation; + uint8 _pillarIndex; + uint8 _phase; + bool _dead; + bool _isDemon; + EventMap specialEvents; }; -class npc_akama : public CreatureScript +struct npc_akama_illidan : public ScriptedAI { -public: - npc_akama() : CreatureScript("npc_akama_illidan") { } + npc_akama_illidan(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), + _orientation(0.0f), _isTeleportToMinions(false) { } - struct npc_akamaAI : public ScriptedAI + void Reset() override { - npc_akamaAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _orientation(0.0f), _isTeleportToMinions(false) { } + _events.Reset(); + _spiritOfUdaloGUID.Clear(); + _spiritOfOlumGUID.Clear(); + _isTeleportToMinions = false; + } - void Reset() override + bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + if (gossipListId == GOSSIP_START_INTRO) { - _events.Reset(); - _spiritOfUdaloGUID.Clear(); - _spiritOfOlumGUID.Clear(); - _isTeleportToMinions = false; + _instance->SetData(DATA_AKAMA, AKAMA_FIGHT); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_STAIRS, SPLINE_STAIRS, false); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->DoAction(ACTION_INTRO_DONE); + CloseGossipMenuFor(player); + } - - bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + else if (gossipListId == GOSSIP_START_FIGHT) { - if (gossipListId == GOSSIP_START_INTRO) - { - _instance->SetData(DATA_AKAMA, AKAMA_FIGHT); - me->GetMotionMaster()->MoveAlongSplineChain(POINT_STAIRS, SPLINE_STAIRS, false); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->DoAction(ACTION_INTRO_DONE); - CloseGossipMenuFor(player); - } - else if (gossipListId == GOSSIP_START_FIGHT) - { - _events.SetPhase(PHASE_INTRO); - me->GetMotionMaster()->MoveAlongSplineChain(POINT_FACE_ILLIDAN, SPLINE_FACE_ILLIDAN, false); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - CloseGossipMenuFor(player); - } + _events.SetPhase(PHASE_INTRO); + me->GetMotionMaster()->MoveAlongSplineChain(POINT_FACE_ILLIDAN, SPLINE_FACE_ILLIDAN, false); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + CloseGossipMenuFor(player); + } + return false; + } + + bool CanAIAttack(Unit const* who) const override + { + if (_events.IsInPhase(PHASE_MINIONS) && who->GetEntry() == NPC_ILLIDAN_STORMRAGE) return false; - } + return ScriptedAI::CanAIAttack(who); + } - bool CanAIAttack(Unit const* who) const override + uint32 GetData(uint32 /*data*/) const override + { + return _isTeleportToMinions ? 1 : 0; + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_SPIRIT_OF_UDALO) { - if (_events.IsInPhase(PHASE_MINIONS) && who->GetEntry() == NPC_ILLIDAN_STORMRAGE) - return false; - return ScriptedAI::CanAIAttack(who); + _spiritOfUdaloGUID = summon->GetGUID(); + summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - - uint32 GetData(uint32 /*data*/) const override + else if (summon->GetEntry() == NPC_SPIRIT_OF_OLUM) { - return _isTeleportToMinions ? 1 : 0; + _spiritOfOlumGUID = summon->GetGUID(); + summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } + } - void EnterEvadeMode(EvadeReason /*why*/) override { } - - void JustSummoned(Creature* summon) override + void DoAction(int32 actionId) override + { + switch (actionId) { - if (summon->GetEntry() == NPC_SPIRIT_OF_UDALO) + case ACTION_ACTIVE_AKAMA_INTRO: + _events.SetPhase(PHASE_INTRO); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + _events.SetPhase(PHASE_INTRO); + _events.ScheduleEvent(EVENT_TELEPORT, 1s); + _events.ScheduleEvent(EVENT_MOVE_TO_ILLIDARI_ROOM, Seconds(1) + Milliseconds(500)); + break; + case ACTION_OPEN_DOOR: + _instance->SetData(ACTION_OPEN_DOOR, 0); + _events.ScheduleEvent(EVENT_AKAMA_THANKS, 2s); + break; + case ACTION_FREE: + _events.ScheduleEvent(EVENT_FREE, 14s); + break; + case ACTION_START_ENCOUNTER: + DoZoneInCombat(); + _events.ScheduleEvent(EVENT_HEALING_POTION, 1s); + break; + case ACTION_START_MINIONS: + _events.ScheduleEvent(EVENT_AKAMA_MINIONS, 8s); + break; + case ACTION_START_OUTRO: + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + _events.Reset(); + _events.ScheduleEvent(EVENT_AKAMA_MOVE_BACK, 2s); + break; + default: + break; + } + } + + void ChangeOrientation(float orientation) + { + _orientation = orientation; + _events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1)); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_ILLIDARI_COUNCIL: + Talk(SAY_AKAMA_FINISH); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case POINT_STAIRS: + ChangeOrientation(6.265732f); + _events.ScheduleEvent(EVENT_AKAMA_SAY_DOOR, 5s); + break; + case POINT_ILLIDAN_ROOM: + ChangeOrientation(2.129302f); + Talk(SAY_AKAMA_BETRAYER); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case POINT_FACE_ILLIDAN: + ChangeOrientation(3.140537f); + _events.ScheduleEvent(EVENT_START_ILLIDAN, 2s); + break; + case POINT_TELEPORT: + DoCastSelf(SPELL_AKAMA_TELEPORT); + _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE_2, Milliseconds(500)); + break; + case POINT_MINIONS: + _events.SetPhase(PHASE_MINIONS); + me->SetImmuneToNPC(false); + me->SetReactState(REACT_AGGRESSIVE); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->DoAction(ACTION_START_MINIONS_WEAVE); + _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 2s); + break; + case POINT_MOVE_BACK: + _events.ScheduleEvent(EVENT_AKAMA_MOVE_TO_ILLIDAN, Milliseconds(1)); + break; + case POINT_ILLIDAN: + _events.ScheduleEvent(EVENT_AKAMA_LIGHT_TEXT, 1s); + break; + default: + break; + } + } + + void DamageTaken(Unit* /*who*/, uint32 &damage) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO)) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - _spiritOfUdaloGUID = summon->GetGUID(); - summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - else if (summon->GetEntry() == NPC_SPIRIT_OF_OLUM) - { - _spiritOfOlumGUID = summon->GetGUID(); - summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - } - - void DoAction(int32 actionId) override - { - switch (actionId) - { - case ACTION_ACTIVE_AKAMA_INTRO: - _events.SetPhase(PHASE_INTRO); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - _events.SetPhase(PHASE_INTRO); - _events.ScheduleEvent(EVENT_TELEPORT, Seconds(1)); - _events.ScheduleEvent(EVENT_MOVE_TO_ILLIDARI_ROOM, Seconds(1) + Milliseconds(500)); + case EVENT_TELEPORT: + DoCastSelf(SPELL_AKAMA_TELEPORT, true); break; - case ACTION_OPEN_DOOR: - _instance->SetData(ACTION_OPEN_DOOR, 0); - _events.ScheduleEvent(EVENT_AKAMA_THANKS, Seconds(2)); + case EVENT_MOVE_TO_ILLIDARI_ROOM: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDARI_COUNCIL, SPLINE_ILLIDARI_COUNCIL, false); break; - case ACTION_FREE: - _events.ScheduleEvent(EVENT_FREE, Seconds(14)); + case EVENT_AKAMA_SAY_DOOR: + Talk(SAY_AKAMA_DOOR); + _events.ScheduleEvent(EVENT_AKAMA_DOOR_FAIL, 4s); break; - case ACTION_START_ENCOUNTER: - DoZoneInCombat(); - _events.ScheduleEvent(EVENT_HEALING_POTION, Seconds(1)); + case EVENT_AKAMA_DOOR_FAIL: + DoCastSelf(SPELL_AKAMA_DOOR_FAIL); + _events.ScheduleEvent(EVENT_AKAMA_SAY_ALONE, 10s); break; - case ACTION_START_MINIONS: - _events.ScheduleEvent(EVENT_AKAMA_MINIONS, Seconds(8)); + case EVENT_AKAMA_SAY_ALONE: + Talk(SAY_AKAMA_ALONE); + _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 7s); break; - case ACTION_START_OUTRO: + case EVENT_SUMMON_SPIRITS: + me->SummonCreatureGroup(SUMMON_GROUP); + _events.ScheduleEvent(EVENT_SPIRIT_SAY_1, Seconds(1)); + break; + case EVENT_SPIRIT_SAY_1: + if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) + undalo->AI()->Talk(SAY_SPIRIT_ALONE); + _events.ScheduleEvent(EVENT_SPIRIT_SAY_2, Seconds(6)); + break; + case EVENT_SPIRIT_SAY_2: + if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) + olum->AI()->Talk(SAY_SPIRIT_ALONE); + _events.ScheduleEvent(EVENT_AKAMA_DOOR_SUCCESS, 6s); + break; + case EVENT_AKAMA_DOOR_SUCCESS: + DoCastSelf(SPELL_AKAMA_DOOR_CHANNEL); + if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) + undalo->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL); + if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) + olum->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL); + _events.ScheduleEvent(EVENT_AKAMA_START_SOUND, 5s); + break; + case EVENT_AKAMA_START_SOUND: + if (GameObject* musicController = _instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) + musicController->PlayDirectMusic(EVENT_BT_SUMMIT_WALK_SOUND_ID); + break; + case EVENT_AKAMA_THANKS: + Talk(SAY_AKAMA_SALUTE); + _events.ScheduleEvent(EVENT_SPIRIT_SALUTE, 3s); + _events.ScheduleEvent(EVENT_RUN_FROM_ILLIDAN_ROOM, 7s); + break; + case EVENT_SPIRIT_SALUTE: + if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) + { + undalo->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + undalo->DespawnOrUnsummon(Seconds(7)); + } + if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) + { + olum->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + olum->DespawnOrUnsummon(Seconds(7)); + } + break; + case EVENT_RUN_FROM_ILLIDAN_ROOM: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDAN_ROOM, SPLINE_ILLIDAN_ROOM, false); + break; + case EVENT_START_ILLIDAN: + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->DoAction(ACTION_START_ENCOUNTER); + break; + case EVENT_FREE: + Talk(SAY_AKAMA_FREE); + _events.ScheduleEvent(EVENT_TIME_HAS_COME, 18s); + break; + case EVENT_TIME_HAS_COME: + Talk(SAY_AKAMA_TIME_HAS_COME); + _events.ScheduleEvent(EVENT_ROAR, 2s); + break; + case EVENT_ROAR: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); + break; + case EVENT_CHANGE_ORIENTATION: + me->SetFacingTo(_orientation); + break; + case EVENT_HEALING_POTION: + if (me->HealthBelowPct(20)) + DoCastSelf(SPELL_HEALING_POTION); + _events.Repeat(Seconds(1)); + break; + case EVENT_AKAMA_MINIONS: + Talk(SAY_AKAMA_MINIONS); + _events.ScheduleEvent(EVENT_AKAMA_MINIONS_EMOTE, 2s); + break; + case EVENT_AKAMA_MINIONS_EMOTE: me->SetReactState(REACT_PASSIVE); me->AttackStop(); - _events.Reset(); - _events.ScheduleEvent(EVENT_AKAMA_MOVE_BACK, Seconds(2)); + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + me->SetImmuneToNPC(true); + _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE, 4s); break; - default: + case EVENT_AKAMA_MINIONS_MOVE: + _isTeleportToMinions = true; + me->GetMotionMaster()->MoveAlongSplineChain(POINT_TELEPORT, SPLINE_TELEPORT, false); break; - } - } - - void ChangeOrientation(float orientation) - { - _orientation = orientation; - _events.ScheduleEvent(EVENT_CHANGE_ORIENTATION, Milliseconds(1)); - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE) - return; - - switch (pointId) - { - case POINT_ILLIDARI_COUNCIL: - Talk(SAY_AKAMA_FINISH); - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + case EVENT_AKAMA_MINIONS_MOVE_2: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_MINIONS, SPLINE_MINIONS, false); break; - case POINT_STAIRS: - ChangeOrientation(6.265732f); - _events.ScheduleEvent(EVENT_AKAMA_SAY_DOOR, Seconds(5)); + case EVENT_CHAIN_LIGHTNING: + DoCastVictim(SPELL_CHAIN_LIGHTNING); + _events.Repeat(Seconds(8) + Milliseconds(500)); break; - case POINT_ILLIDAN_ROOM: - ChangeOrientation(2.129302f); - Talk(SAY_AKAMA_BETRAYER); - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + case EVENT_AKAMA_MOVE_BACK: + me->GetMotionMaster()->MoveAlongSplineChain(POINT_MOVE_BACK, SPLINE_MOVE_BACK, false); break; - case POINT_FACE_ILLIDAN: - ChangeOrientation(3.140537f); - _events.ScheduleEvent(EVENT_START_ILLIDAN, Seconds(2)); - break; - case POINT_TELEPORT: - DoCastSelf(SPELL_AKAMA_TELEPORT); - _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE_2, Milliseconds(500)); - break; - case POINT_MINIONS: - _events.SetPhase(PHASE_MINIONS); - me->SetImmuneToNPC(false); - me->SetReactState(REACT_AGGRESSIVE); + case EVENT_AKAMA_MOVE_TO_ILLIDAN: if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->DoAction(ACTION_START_MINIONS_WEAVE); - _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(2)); + me->GetMotionMaster()->MoveCloserAndStop(POINT_ILLIDAN, illidan, 5.0f); break; - case POINT_MOVE_BACK: - _events.ScheduleEvent(EVENT_AKAMA_MOVE_TO_ILLIDAN, Milliseconds(1)); + case EVENT_AKAMA_LIGHT_TEXT: + Talk(SAY_AKAMA_LIGHT); + _events.ScheduleEvent(EVENT_FINAL_SALUTE, 4s); break; - case POINT_ILLIDAN: - _events.ScheduleEvent(EVENT_AKAMA_LIGHT_TEXT, Seconds(1)); + case EVENT_FINAL_SALUTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + _events.ScheduleEvent(EVENT_AKAMA_DESPAWN, 5s); + break; + case EVENT_AKAMA_DESPAWN: + DoCastSelf(SPELL_AKAMA_DESPAWN, true); break; default: break; } - } - - void DamageTaken(Unit* /*who*/, uint32 &damage) override - { - if (damage >= me->GetHealth()) - damage = me->GetHealth() - 1; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO)) - return; - - _events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_TELEPORT: - DoCastSelf(SPELL_AKAMA_TELEPORT, true); - break; - case EVENT_MOVE_TO_ILLIDARI_ROOM: - me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDARI_COUNCIL, SPLINE_ILLIDARI_COUNCIL, false); - break; - case EVENT_AKAMA_SAY_DOOR: - Talk(SAY_AKAMA_DOOR); - _events.ScheduleEvent(EVENT_AKAMA_DOOR_FAIL, Seconds(4)); - break; - case EVENT_AKAMA_DOOR_FAIL: - DoCastSelf(SPELL_AKAMA_DOOR_FAIL); - _events.ScheduleEvent(EVENT_AKAMA_SAY_ALONE, Seconds(10)); - break; - case EVENT_AKAMA_SAY_ALONE: - Talk(SAY_AKAMA_ALONE); - _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, Seconds(7)); - break; - case EVENT_SUMMON_SPIRITS: - me->SummonCreatureGroup(SUMMON_GROUP); - _events.ScheduleEvent(EVENT_SPIRIT_SAY_1, Seconds(1)); - break; - case EVENT_SPIRIT_SAY_1: - if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) - undalo->AI()->Talk(SAY_SPIRIT_ALONE); - _events.ScheduleEvent(EVENT_SPIRIT_SAY_2, Seconds(6)); - break; - case EVENT_SPIRIT_SAY_2: - if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) - olum->AI()->Talk(SAY_SPIRIT_ALONE); - _events.ScheduleEvent(EVENT_AKAMA_DOOR_SUCCESS, Seconds(6)); - break; - case EVENT_AKAMA_DOOR_SUCCESS: - DoCastSelf(SPELL_AKAMA_DOOR_CHANNEL); - if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) - undalo->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL); - if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) - olum->CastSpell((Unit*) nullptr, SPELL_DEATHSWORN_DOOR_CHANNEL); - _events.ScheduleEvent(EVENT_AKAMA_START_SOUND, Seconds(5)); - break; - case EVENT_AKAMA_START_SOUND: - if (GameObject* musicController = _instance->GetGameObject(DATA_ILLIDAN_MUSIC_CONTROLLER)) - musicController->PlayDirectMusic(EVENT_BT_SUMMIT_WALK_SOUND_ID); - break; - case EVENT_AKAMA_THANKS: - Talk(SAY_AKAMA_SALUTE); - _events.ScheduleEvent(EVENT_SPIRIT_SALUTE, Seconds(3)); - _events.ScheduleEvent(EVENT_RUN_FROM_ILLIDAN_ROOM, Seconds(7)); - break; - case EVENT_SPIRIT_SALUTE: - if (Creature* undalo = ObjectAccessor::GetCreature(*me, _spiritOfUdaloGUID)) - { - undalo->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - undalo->DespawnOrUnsummon(Seconds(7)); - } - if (Creature* olum = ObjectAccessor::GetCreature(*me, _spiritOfOlumGUID)) - { - olum->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - olum->DespawnOrUnsummon(Seconds(7)); - } - break; - case EVENT_RUN_FROM_ILLIDAN_ROOM: - me->GetMotionMaster()->MoveAlongSplineChain(POINT_ILLIDAN_ROOM, SPLINE_ILLIDAN_ROOM, false); - break; - case EVENT_START_ILLIDAN: - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->DoAction(ACTION_START_ENCOUNTER); - break; - case EVENT_FREE: - Talk(SAY_AKAMA_FREE); - _events.ScheduleEvent(EVENT_TIME_HAS_COME, Seconds(18)); - break; - case EVENT_TIME_HAS_COME: - Talk(SAY_AKAMA_TIME_HAS_COME); - _events.ScheduleEvent(EVENT_ROAR, Seconds(2)); - break; - case EVENT_ROAR: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); - break; - case EVENT_CHANGE_ORIENTATION: - me->SetFacingTo(_orientation); - break; - case EVENT_HEALING_POTION: - if (me->HealthBelowPct(20)) - DoCastSelf(SPELL_HEALING_POTION); - _events.Repeat(Seconds(1)); - break; - case EVENT_AKAMA_MINIONS: - Talk(SAY_AKAMA_MINIONS); - _events.ScheduleEvent(EVENT_AKAMA_MINIONS_EMOTE, Seconds(2)); - break; - case EVENT_AKAMA_MINIONS_EMOTE: - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - me->SetImmuneToNPC(true); - _events.ScheduleEvent(EVENT_AKAMA_MINIONS_MOVE, Seconds(4)); - break; - case EVENT_AKAMA_MINIONS_MOVE: - _isTeleportToMinions = true; - me->GetMotionMaster()->MoveAlongSplineChain(POINT_TELEPORT, SPLINE_TELEPORT, false); - break; - case EVENT_AKAMA_MINIONS_MOVE_2: - me->GetMotionMaster()->MoveAlongSplineChain(POINT_MINIONS, SPLINE_MINIONS, false); - break; - case EVENT_CHAIN_LIGHTNING: - DoCastVictim(SPELL_CHAIN_LIGHTNING); - _events.Repeat(Seconds(8) + Milliseconds(500)); - break; - case EVENT_AKAMA_MOVE_BACK: - me->GetMotionMaster()->MoveAlongSplineChain(POINT_MOVE_BACK, SPLINE_MOVE_BACK, false); - break; - case EVENT_AKAMA_MOVE_TO_ILLIDAN: - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - me->GetMotionMaster()->MoveCloserAndStop(POINT_ILLIDAN, illidan, 5.0f); - break; - case EVENT_AKAMA_LIGHT_TEXT: - Talk(SAY_AKAMA_LIGHT); - _events.ScheduleEvent(EVENT_FINAL_SALUTE, Seconds(4)); - break; - case EVENT_FINAL_SALUTE: - me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); - _events.ScheduleEvent(EVENT_AKAMA_DESPAWN, Seconds(5)); - break; - case EVENT_AKAMA_DESPAWN: - DoCastSelf(SPELL_AKAMA_DESPAWN, true); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - private: - InstanceScript* _instance; - EventMap _events; - ObjectGuid _spiritOfUdaloGUID; - ObjectGuid _spiritOfOlumGUID; - float _orientation; - bool _isTeleportToMinions; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); } + +private: + InstanceScript* _instance; + EventMap _events; + ObjectGuid _spiritOfUdaloGUID; + ObjectGuid _spiritOfOlumGUID; + float _orientation; + bool _isTeleportToMinions; }; -class npc_parasitic_shadowfiend : public CreatureScript +struct npc_parasitic_shadowfiend : public ScriptedAI { -public: - npc_parasitic_shadowfiend() : CreatureScript("npc_parasitic_shadowfiend") { } + npc_parasitic_shadowfiend(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - struct npc_parasitic_shadowfiendAI : public ScriptedAI + void Reset() override { - npc_parasitic_shadowfiendAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - - void Reset() override + if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) { - if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) - { - me->DespawnOrUnsummon(); - return; - } + me->DespawnOrUnsummon(); + return; + } - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->JustSummoned(me); - me->SetReactState(REACT_DEFENSIVE); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->JustSummoned(me); + me->SetReactState(REACT_PASSIVE); + _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) + { + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + }); + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_PHASE_4) + { + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + } + else if (action == ACTION_RESUME_COMBAT) _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) { me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); + DoZoneInCombat(); }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; +}; + +struct npc_blade_of_azzinoth : public NullCreatureAI +{ + npc_blade_of_azzinoth(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) + { + me->DespawnOrUnsummon(); + return; } - void UpdateAI(uint32 diff) override + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->JustSummoned(me); + _flameGuid.Clear(); + me->PlayDirectSound(WARGLAIVE_SPAWN_SOUND_ID); + DoCastSelf(SPELL_BIRTH, true); + _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - _scheduler.Update(diff, [this] + DoCastSelf(SPELL_SUMMON_TEAR_OF_AZZINOTH); + _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*context*/) { - DoMeleeAttackIfReady(); + if (Creature* flame = ObjectAccessor::GetCreature(*me, _flameGuid)) + DoCast(flame, SPELL_AZZINOTH_CHANNEL); }); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + }); } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_FLAME_OF_AZZINOTH) + _flameGuid = summon->GetGUID(); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; + ObjectGuid _flameGuid; }; -class npc_blade_of_azzinoth : public CreatureScript +struct npc_flame_of_azzinoth : public ScriptedAI { -public: - npc_blade_of_azzinoth() : CreatureScript("npc_blade_of_azzinoth") { } - - struct npc_blade_of_azzinothAI : public NullCreatureAI + npc_flame_of_azzinoth(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { - npc_blade_of_azzinothAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { } - - void Reset() override - { - if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) - { - me->DespawnOrUnsummon(); - return; - } - - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->JustSummoned(me); - _flameGuid.Clear(); - me->PlayDirectSound(WARGLAIVE_SPAWN_SOUND_ID); - DoCastSelf(SPELL_BIRTH, true); - _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_SUMMON_TEAR_OF_AZZINOTH); - _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*context*/) - { - if (Creature* flame = ObjectAccessor::GetCreature(*me, _flameGuid)) - DoCast(flame, SPELL_AZZINOTH_CHANNEL); - }); - }); - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() == NPC_FLAME_OF_AZZINOTH) - _flameGuid = summon->GetGUID(); - } - - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - ObjectGuid _flameGuid; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + SetBoundary(_instance->GetBossBoundary(DATA_ILLIDAN_STORMRAGE)); } -}; -class npc_flame_of_azzinoth : public CreatureScript -{ -public: - npc_flame_of_azzinoth() : CreatureScript("npc_flame_of_azzinoth") { } - - struct npc_flame_of_azzinothAI : public ScriptedAI + void Reset() override { - npc_flame_of_azzinothAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) { - SetBoundary(_instance->GetBossBoundary(DATA_ILLIDAN_STORMRAGE)); + me->DespawnOrUnsummon(); + return; } - void Reset() override - { - if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) - { - me->DespawnOrUnsummon(); - return; - } - - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->JustSummoned(me); - DoCastSelf(SPELL_FLAME_TEAR_OF_AZZINOTH, true); // Idk what this spell should do - me->SetReactState(REACT_PASSIVE); - _events.ScheduleEvent(EVENT_ENGAGE, Seconds(3)); - _events.ScheduleEvent(EVENT_FLAME_BLAST, Seconds(11)); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ENGAGE: - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - _events.ScheduleEvent(EVENT_FLAME_CHARGE, Seconds(5)); - break; - case EVENT_FLAME_CHARGE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, ChargeTargetSelector(me))) - { - DoCast(target, SPELL_CHARGE); - _events.Repeat(Seconds(5)); - } - else - _events.Repeat(Seconds(1)); - break; - case EVENT_FLAME_BLAST: - DoCastAOE(SPELL_FLAME_BLAST); - _events.Repeat(Seconds(12)); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->AI()->DoAction(ACTION_FLAME_DEAD); - } - - private: - InstanceScript* _instance; - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->JustSummoned(me); + DoCastSelf(SPELL_FLAME_TEAR_OF_AZZINOTH, true); // Idk what this spell should do + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_ENGAGE, 3s); + _events.ScheduleEvent(EVENT_FLAME_BLAST, 11s); } -}; -class npc_illidan_db_target : public CreatureScript -{ -public: - npc_illidan_db_target() : CreatureScript("npc_illidan_db_target") { } - - struct npc_illidan_db_targetAI : public NullCreatureAI + void UpdateAI(uint32 diff) override { - npc_illidan_db_targetAI(Creature* creature) : NullCreatureAI(creature) { } + if (!UpdateVictim()) + return; - void Reset() override - { - DoCastSelf(SPELL_EYE_BLAST_TRIGGER); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() == NPC_DEMON_FIRE) - summon->SetReactState(REACT_PASSIVE); - } + _events.Update(diff); - void MovementInform(uint32 type, uint32 pointId) override + while (uint32 eventId = _events.ExecuteEvent()) { - if (type == POINT_MOTION_TYPE && pointId == POINT_DB_TARGET) + switch (eventId) { - me->RemoveAurasDueToSpell(SPELL_EYE_BLAST_TRIGGER); - me->RemoveAurasDueToSpell(SPELL_EYE_BLAST); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); - } -}; - -class npc_illidan_shadow_demon : public CreatureScript -{ -public: - npc_illidan_shadow_demon() : CreatureScript("npc_shadow_demon") { } - - struct npc_illidan_shadow_demonAI : public PassiveAI - { - npc_illidan_shadow_demonAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { } - - void Reset() override - { - if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) - { - me->DespawnOrUnsummon(); - return; - } - - DoCastSelf(SPELL_SHADOW_DEMON_PASSIVE); - DoCastSelf(SPELL_FIND_TARGET); - _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) - { - if (!target->IsAlive()) - DoCastSelf(SPELL_FIND_TARGET); - else if (me->IsWithinMeleeRange(target)) + case EVENT_ENGAGE: + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + _events.ScheduleEvent(EVENT_FLAME_CHARGE, 5s); + break; + case EVENT_FLAME_CHARGE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, ChargeTargetSelector())) { - me->InterruptNonMeleeSpells(false); - DoCast(target, SPELL_CONSUME_SOUL, true); + DoCast(target, SPELL_CHARGE); + _events.Repeat(Seconds(5)); } - } - checkTarget.Repeat(); - }); + else + _events.Repeat(Seconds(1)); + break; + case EVENT_FLAME_BLAST: + DoCastAOE(SPELL_FLAME_BLAST); + _events.Repeat(Seconds(12)); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override - { - _targetGUID = guid; - if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) - me->GetMotionMaster()->MoveChase(target); - } + DoMeleeAttackIfReady(); + } - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - ObjectGuid _targetGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustDied(Unit* /*killer*/) override { - return GetBlackTempleAI(creature); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->DoAction(ACTION_FLAME_DEAD); + } + +private: + InstanceScript* _instance; + EventMap _events; +}; + +struct npc_illidan_db_target : public NullCreatureAI +{ + npc_illidan_db_target(Creature* creature) : NullCreatureAI(creature) { } + + void Reset() override + { + DoCastSelf(SPELL_EYE_BLAST_TRIGGER); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_DEMON_FIRE) + summon->SetReactState(REACT_PASSIVE); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE && pointId == POINT_DB_TARGET) + { + me->RemoveAurasDueToSpell(SPELL_EYE_BLAST_TRIGGER); + me->RemoveAurasDueToSpell(SPELL_EYE_BLAST); + } } }; -class npc_maiev : public CreatureScript +struct npc_shadow_demon : public PassiveAI { -public: - npc_maiev() : CreatureScript("npc_maiev") { } + npc_shadow_demon(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) { } - struct npc_maievAI : public ScriptedAI + void Reset() override { - npc_maievAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _canDown(true) { } - - void Reset() override + if (_instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != IN_PROGRESS) { + me->DespawnOrUnsummon(); + return; + } + + DoCastSelf(SPELL_SHADOW_DEMON_PASSIVE); + DoCastSelf(SPELL_FIND_TARGET); + _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) + { + if (!target->IsAlive()) + DoCastSelf(SPELL_FIND_TARGET); + else if (me->IsWithinMeleeRange(target)) + { + me->InterruptNonMeleeSpells(false); + DoCast(target, SPELL_CONSUME_SOUL, true); + } + } + checkTarget.Repeat(); + }); + } + + void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + { + _targetGUID = guid; + if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID)) + me->GetMotionMaster()->MoveChase(target); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; + ObjectGuid _targetGUID; +}; + +struct npc_maiev : public ScriptedAI +{ + npc_maiev(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _canDown(true) { } + + void JustAppeared() override + { + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + me->SetFacingToObject(illidan); + me->SetReactState(REACT_PASSIVE); + _events.SetPhase(PHASE_OUTRO); + _events.ScheduleEvent(EVENT_MAIEV_APPEAR, 1s); + _events.ScheduleEvent(EVENT_MAIEV_EXCLAMATION, 2s); + _events.ScheduleEvent(EVENT_MAIEV_JUSTICE_TEXT, 14s); + _events.ScheduleEvent(EVENT_TAUNT, 20s, 1min); + _canDown = true; + } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.SetPhase(PHASE_1); + _events.ScheduleEvent(EVENT_CAGE_TRAP, 30s); + _events.ScheduleEvent(EVENT_SHADOW_STRIKE, 50s); + _events.ScheduleEvent(EVENT_THROW_DAGGER, 1s); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_START_OUTRO) + { + _events.Reset(); + _events.SetPhase(PHASE_OUTRO); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) me->SetFacingToObject(illidan); - me->SetReactState(REACT_PASSIVE); - _events.SetPhase(PHASE_INTRO); - _events.ScheduleEvent(EVENT_MAIEV_APPEAR, Seconds(1)); - _events.ScheduleEvent(EVENT_MAIEV_EXCLAMATION, Seconds(2)); - _events.ScheduleEvent(EVENT_MAIEV_JUSTICE_TEXT, Seconds(14)); - _events.ScheduleEvent(EVENT_TAUNT, Seconds(20), Seconds(60)); + Talk(SAY_MAIEV_SHADOWSONG_FINISHED); + _events.ScheduleEvent(EVENT_MAIEV_OUTRO_TEXT, 28s); + } + else if (actionId == ACTION_MAIEV_DOWN_FADE) _canDown = true; - } + } - void JustEngagedWith(Unit* /*who*/) override + void DamageTaken(Unit* /*who*/, uint32 &damage) override + { + if (damage >= me->GetHealth() && _canDown) { - _events.SetPhase(PHASE_1); - _events.ScheduleEvent(EVENT_CAGE_TRAP, Seconds(30)); - _events.ScheduleEvent(EVENT_SHADOW_STRIKE, Seconds(50)); - _events.ScheduleEvent(EVENT_THROW_DAGGER, Seconds(1)); + damage = me->GetHealth() - 1; + _canDown = false; + DoCastSelf(SPELL_MAIEV_DOWN, true); + Talk(SAY_MAIEV_SHADOWSONG_DOWN, me); } + } - void DoAction(int32 actionId) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO)) + return; + + if (!_events.IsInPhase(PHASE_OUTRO) && !UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) { - if (actionId == ACTION_START_OUTRO) + switch (eventId) { - _events.Reset(); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - me->SetFacingToObject(illidan); - Talk(SAY_MAIEV_SHADOWSONG_FINISHED); - _events.ScheduleEvent(EVENT_MAIEV_OUTRO_TEXT, Seconds(28)); + case EVENT_MAIEV_APPEAR: + Talk(SAY_MAIEV_SHADOWSONG_APPEAR); + break; + case EVENT_MAIEV_EXCLAMATION: + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + break; + case EVENT_MAIEV_JUSTICE_TEXT: + Talk(SAY_MAIEV_SHADOWSONG_JUSTICE); + _events.ScheduleEvent(EVENT_MAIEV_YES, 2s); + break; + case EVENT_MAIEV_YES: + me->HandleEmoteCommand(EMOTE_ONESHOT_YES); + _events.ScheduleEvent(EVENT_MAIEV_ROAR, 3s); + break; + case EVENT_MAIEV_ROAR: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + _events.ScheduleEvent(EVENT_MAIEV_COMBAT, 3s); + break; + case EVENT_MAIEV_COMBAT: + me->SetReactState(REACT_AGGRESSIVE); + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + AttackStart(illidan); + break; + case EVENT_CAGE_TRAP: + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->CastSpell(illidan, SPELL_CAGED_TRAP_TELEPORT, true); + DoCastSelf(SPELL_CAGE_TRAP_SUMMON); + Talk(SAY_MAIEV_SHADOWSONG_TRAP); + _events.Repeat(Seconds(30)); + break; + case EVENT_SHADOW_STRIKE: + DoCastVictim(SPELL_SHADOW_STRIKE); + _events.Repeat(Seconds(50)); + break; + case EVENT_THROW_DAGGER: + if (Unit* target = me->GetVictim()) + if (!me->IsWithinMeleeRange(target)) + { + DoCastVictim(SPELL_THROW_DAGGER); + _events.Repeat(Seconds(5)); + break; + } + _events.Repeat(Seconds(1)); + break; + case EVENT_TAUNT: + Talk(SAY_MAIEV_SHADOWSONG_TAUNT); + _events.Repeat(Seconds(30), Seconds(60)); + break; + case EVENT_MAIEV_OUTRO_TEXT: + Talk(SAY_MAIEV_SHADOWSONG_OUTRO); + _events.ScheduleEvent(EVENT_MAIEV_FAREWELL_TEXT, 11s); + break; + case EVENT_MAIEV_FAREWELL_TEXT: + Talk(SAY_MAIEV_SHADOWSONG_FAREWELL); + _events.ScheduleEvent(EVENT_MAIEV_TELEPORT_DESPAWN, 3s); + break; + case EVENT_MAIEV_TELEPORT_DESPAWN: + DoCastSelf(SPELL_TELEPORT_VISUAL); + me->DespawnOrUnsummon(Seconds(1)); + break; + default: + break; } - else if (actionId == ACTION_MAIEV_DOWN_FADE) - _canDown = true; - } - - void DamageTaken(Unit* /*who*/, uint32 &damage) override - { - if (damage >= me->GetHealth() && _canDown) - { - damage = me->GetHealth() - 1; - _canDown = false; - DoCastSelf(SPELL_MAIEV_DOWN, true); - Talk(SAY_MAIEV_SHADOWSONG_DOWN, me); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO)) - return; if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_MAIEV_APPEAR: - Talk(SAY_MAIEV_SHADOWSONG_APPEAR); - break; - case EVENT_MAIEV_EXCLAMATION: - me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - break; - case EVENT_MAIEV_JUSTICE_TEXT: - Talk(SAY_MAIEV_SHADOWSONG_JUSTICE); - _events.ScheduleEvent(EVENT_MAIEV_YES, Seconds(2)); - break; - case EVENT_MAIEV_YES: - me->HandleEmoteCommand(EMOTE_ONESHOT_YES); - _events.ScheduleEvent(EVENT_MAIEV_ROAR, Seconds(3)); - break; - case EVENT_MAIEV_ROAR: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - _events.ScheduleEvent(EVENT_MAIEV_COMBAT, Seconds(3)); - break; - case EVENT_MAIEV_COMBAT: - me->SetReactState(REACT_AGGRESSIVE); - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - AttackStart(illidan); - break; - case EVENT_CAGE_TRAP: - if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) - illidan->CastSpell(illidan, SPELL_CAGED_TRAP_TELEPORT, true); - DoCastSelf(SPELL_CAGE_TRAP_SUMMON); - Talk(SAY_MAIEV_SHADOWSONG_TRAP); - _events.Repeat(Seconds(30)); - break; - case EVENT_SHADOW_STRIKE: - DoCastVictim(SPELL_SHADOW_STRIKE); - _events.Repeat(Seconds(50)); - break; - case EVENT_THROW_DAGGER: - if (Unit* target = me->GetVictim()) - if (!me->IsWithinMeleeRange(target)) - { - DoCastVictim(SPELL_THROW_DAGGER); - _events.Repeat(Seconds(5)); - break; - } - _events.Repeat(Seconds(1)); - break; - case EVENT_TAUNT: - Talk(SAY_MAIEV_SHADOWSONG_TAUNT); - _events.Repeat(Seconds(30), Seconds(60)); - break; - case EVENT_MAIEV_OUTRO_TEXT: - Talk(SAY_MAIEV_SHADOWSONG_OUTRO); - _events.ScheduleEvent(EVENT_MAIEV_FAREWELL_TEXT, Seconds(11)); - break; - case EVENT_MAIEV_FAREWELL_TEXT: - Talk(SAY_MAIEV_SHADOWSONG_FAREWELL); - _events.ScheduleEvent(EVENT_MAIEV_TELEPORT_DESPAWN, Seconds(3)); - break; - case EVENT_MAIEV_TELEPORT_DESPAWN: - DoCastSelf(SPELL_TELEPORT_VISUAL); - me->DespawnOrUnsummon(Seconds(1)); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - private: - EventMap _events; - InstanceScript* _instance; - bool _canDown; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); } + +private: + EventMap _events; + InstanceScript* _instance; + bool _canDown; }; -class npc_cage_trap_trigger : public CreatureScript +struct npc_cage_trap_trigger : public PassiveAI { -public: - npc_cage_trap_trigger() : CreatureScript("npc_cage_trap_trigger") { } + npc_cage_trap_trigger(Creature* creature) : PassiveAI(creature) { } - struct npc_cage_trap_triggerAI : public PassiveAI + void Reset() override { - npc_cage_trap_triggerAI(Creature* creature) : PassiveAI(creature) { } - - void Reset() override + _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget) { - _scheduler.Schedule(Seconds(1), [this](TaskContext checkTarget) - { - DoCastSelf(SPELL_CAGE_TRAP_PERIODIC); - checkTarget.Repeat(); - }); - } - - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - } - - private: - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoCastSelf(SPELL_CAGE_TRAP_PERIODIC); + checkTarget.Repeat(); + }); } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +struct npc_illidari_elite : public ScriptedAI +{ + npc_illidari_elite(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + if (Creature* akama = _instance->GetCreature(DATA_AKAMA)) + { + AttackStart(akama); + AddThreat(akama, 1000.0f); + } + } + + bool CanAIAttack(Unit const* who) const override + { + if (who->GetEntry() == NPC_AKAMA) + return true; + return false; + } + +private: + InstanceScript* _instance; +}; + +struct npc_illidan_generic_fire : public ScriptedAI +{ + npc_illidan_generic_fire(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + } + + void Reset() override + { + if (Creature* illidan = _instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) + illidan->AI()->JustSummoned(me); + + me->SetReactState(REACT_PASSIVE); + switch (me->GetEntry()) + { + case NPC_DEMON_FIRE: + DoCastSelf(SPELL_DEMON_FIRE, true); + break; + case NPC_BLAZE: + DoCastSelf(SPELL_BLAZE, true); + DoCastSelf(SPELL_BIRTH, true); + break; + case NPC_FLAME_CRASH: + DoCastSelf(SPELL_FLAME_CRASH_GROUND, true); + break; + default: + break; + } + } + + void UpdateAI(uint32 /*diff*/) override { } + +private: + InstanceScript* _instance; }; // 41077 - Akama Teleport -class spell_illidan_akama_teleport : public SpellScriptLoader +class spell_illidan_akama_teleport : public SpellScript { - public: - spell_illidan_akama_teleport() : SpellScriptLoader("spell_illidan_akama_teleport") { } - - class spell_illidan_akama_teleport_SpellScript : public SpellScript + void SetDest(SpellDestination& dest) + { + if (Creature* caster = GetCaster()->ToCreature()) { - void SetDest(SpellDestination& dest) - { - if (Creature* caster = GetCaster()->ToCreature()) - { - uint32 destination = caster->AI()->GetData(DATA_AKAMA_TELEPORT_POSITION); - dest.Relocate(AkamaTeleportPositions[destination]); - } - } - - void Register() override - { - OnDestinationTargetSelect.Register(&spell_illidan_akama_teleport_SpellScript::SetDest, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_akama_teleport_SpellScript(); + uint32 destination = caster->AI()->GetData(DATA_AKAMA_TELEPORT_POSITION); + dest.Relocate(AkamaTeleportPositions[destination]); } + } + + void Register() override + { + OnDestinationTargetSelect.Register(&spell_illidan_akama_teleport::SetDest, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + } }; // 41268 - Quest - Black Temple - Akama - Door Open -class spell_illidan_akama_door_channel : public SpellScriptLoader +class spell_illidan_akama_door_channel : public AuraScript { - public: - spell_illidan_akama_door_channel() : SpellScriptLoader("spell_illidan_akama_door_channel") { } + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_ARCANE_EXPLOSION }); + } - class spell_illidan_akama_door_channel_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_ARCANE_EXPLOSION }); - } + void OnRemoveDummy(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_ARCANE_EXPLOSION, true); - void OnRemoveDummy(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - target->CastSpell(target, SPELL_ARCANE_EXPLOSION, true); + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* akama = instance->GetCreature(DATA_AKAMA)) + akama->AI()->DoAction(ACTION_OPEN_DOOR); + } - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* akama = instance->GetCreature(DATA_AKAMA)) - akama->AI()->DoAction(ACTION_OPEN_DOOR); - } - - void Register() override - { - AfterEffectRemove.Register(&spell_illidan_akama_door_channel_AuraScript::OnRemoveDummy, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_akama_door_channel_AuraScript(); - } + void Register() override + { + AfterEffectRemove.Register(&spell_illidan_akama_door_channel::OnRemoveDummy, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } }; // 40904 - Draw Soul -class spell_illidan_draw_soul : public SpellScriptLoader +class spell_illidan_draw_soul : public SpellScript { - public: - spell_illidan_draw_soul() : SpellScriptLoader("spell_illidan_draw_soul") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRAW_SOUL_HEAL }); + } - class spell_illidan_draw_soul_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRAW_SOUL_HEAL }); - } + void HandleScriptEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetCaster(), SPELL_DRAW_SOUL_HEAL, true); + } - void HandleScriptEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - GetHitUnit()->CastSpell(GetCaster(), SPELL_DRAW_SOUL_HEAL, true); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_draw_soul_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_draw_soul_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_draw_soul::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } }; /* 41917 - Parasitic Shadowfiend 41914 - Parasitic Shadowfiend */ -class spell_illidan_parasitic_shadowfiend : public SpellScriptLoader +class spell_illidan_parasitic_shadowfiend : public AuraScript { - public: - spell_illidan_parasitic_shadowfiend() : SpellScriptLoader("spell_illidan_parasitic_shadowfiend") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SUMMON_PARASITIC_SHADOWFIENDS }); + } - class spell_illidan_parasitic_shadowfiend_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SUMMON_PARASITIC_SHADOWFIENDS }); - } + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + auto removeMode = GetTargetApplication()->GetRemoveMode(); + if (!removeMode.HasFlag(AuraRemoveFlags::Expired | AuraRemoveFlags::ByDeath)) + return; - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - target->CastSpell(target, SPELL_SUMMON_PARASITIC_SHADOWFIENDS, true); - } + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_SUMMON_PARASITIC_SHADOWFIENDS, true); + } - void Register() override - { - AfterEffectRemove.Register(&spell_illidan_parasitic_shadowfiend_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); - } - }; + void Register() override + { + AfterEffectRemove.Register(&spell_illidan_parasitic_shadowfiend::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } +}; - AuraScript* GetAuraScript() const override - { - return new spell_illidan_parasitic_shadowfiend_AuraScript(); - } +// 41913 - Parasitic Shadowfiend Passive +class spell_illidan_parasitic_shadowfiend_proc : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PARASITIC_SHADOWFIEND, SPELL_PARASITIC_SHADOWFIEND_2 }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Unit* target = eventInfo.GetProcTarget(); + return target && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND) && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND_2); + } + + void Register() override + { + DoCheckProc.Register(&spell_illidan_parasitic_shadowfiend_proc::CheckProc); + } +}; + +// 41923 - Remove Parasitic Shadowfiends (SERVERSIDE) +class spell_illidan_remove_parasitic_shadowfiend : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PARASITIC_SHADOWFIEND, SPELL_PARASITIC_SHADOWFIEND_2 }); + } + + void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_PARASITIC_SHADOWFIEND); + GetTarget()->RemoveAurasDueToSpell(SPELL_PARASITIC_SHADOWFIEND_2); + } + + void Register() override + { + AfterEffectApply.Register(&spell_illidan_remove_parasitic_shadowfiend::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } }; /* 39635 - Throw Glaive 39849 - Throw Glaive */ -class spell_illidan_throw_warglaive : public SpellScriptLoader +class spell_illidan_throw_warglaive : public SpellScript { - public: - spell_illidan_throw_warglaive() : SpellScriptLoader("spell_illidan_throw_warglaive") { } - - class spell_illidan_throw_warglaive_SpellScript : public SpellScript - { - void HandleDummy(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - target->m_Events.AddEvent(new SummonWarglaiveEvent(target), target->m_Events.CalculateTime(1000)); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_throw_warglaive_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_throw_warglaive_SpellScript(); - } -}; - -// 39857 - Tear of Azzinoth Summon Channel -class spell_illidan_tear_of_azzinoth_channel : public SpellScriptLoader -{ - public: - spell_illidan_tear_of_azzinoth_channel() : SpellScriptLoader("spell_illidan_tear_of_azzinoth_channel") { } - - class spell_illidan_tear_of_azzinoth_channel_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_UNCAGED_WRATH }); - } - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - if (Unit* caster = GetCaster()) - { - Unit* target = GetTarget(); - if (caster->GetDistance2d(target) > 25.0f) - { - target->CastSpell(target, SPELL_UNCAGED_WRATH, true); - Remove(); - } - } - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidan_tear_of_azzinoth_channel_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_tear_of_azzinoth_channel_AuraScript(); - } -}; - -// 40631 - Flame Blast -class spell_illidan_flame_blast : public SpellScriptLoader -{ - public: - spell_illidan_flame_blast() : SpellScriptLoader("spell_illidan_flame_blast") { } - - class spell_illidan_flame_blast_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_BLAZE_SUMMON }); - } - - void HandleBlaze(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - if (target->GetTypeId() == TYPEID_PLAYER) - target->CastSpell(target, SPELL_BLAZE_SUMMON, true); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_flame_blast_SpellScript::HandleBlaze, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_flame_blast_SpellScript(); - } -}; - -// 39873 - Glaive Returns -class spell_illidan_return_glaives : public SpellScriptLoader -{ - public: spell_illidan_return_glaives() : SpellScriptLoader("spell_illidan_return_glaives") { } - - class spell_illidan_return_glaives_SpellScript : public SpellScript - { - void HandleScriptEffect(SpellEffIndex /*effIndex*/) - { - GetHitUnit()->SendPlaySpellVisualKit(SPELL_GLAIVE_VISUAL_KIT,0,0); - if (Creature* caster = GetCaster()->ToCreature()) - caster->DespawnOrUnsummon(); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_return_glaives_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_return_glaives_SpellScript(); - } -}; - -// 40834 - Agonizing Flames -class spell_illidan_agonizing_flames : public SpellScriptLoader -{ - public: - spell_illidan_agonizing_flames() : SpellScriptLoader("spell_illidan_agonizing_flames") { } - - class spell_illidan_agonizing_flames_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_AGONIZING_FLAMES }); - } - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - GetCaster()->CastSpell(GetHitUnit(), SPELL_AGONIZING_FLAMES, true); - } - - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_illidan_agonizing_flames_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget.Register(&spell_illidan_agonizing_flames_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_agonizing_flames_SpellScript(); - } -}; - -// 40511 - Demon Transform 1 -class spell_illidan_demon_transform1 : public SpellScriptLoader -{ - public: - spell_illidan_demon_transform1() : SpellScriptLoader("spell_illidan_demon_transform1") { } - - class spell_illidan_demon_transform1_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DEMON_TRANSFORM_2 }); - } - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_DEMON_TRANSFORM_2, true); - Remove(); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidan_demon_transform1_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_demon_transform1_AuraScript(); - } -}; - -// 40398 - Demon Transform 2 -class spell_illidan_demon_transform2 : public SpellScriptLoader -{ - public: - spell_illidan_demon_transform2() : SpellScriptLoader("spell_illidan_demon_transform2") { } - - class spell_illidan_demon_transform2_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DEMON_FORM, SPELL_DEMON_TRANSFORM_3 }); - } - - void OnPeriodic(AuraEffect const* aurEff) - { - PreventDefaultAction(); - Unit* target = GetTarget(); - - if (aurEff->GetTickNumber() == 1) - { - if (target->GetDisplayId() == target->GetNativeDisplayId()) - target->CastSpell(target, SPELL_DEMON_FORM, true); - else - target->RemoveAurasDueToSpell(SPELL_DEMON_FORM); - } - else if (aurEff->GetTickNumber() == 2) - { - target->CastSpell(target, SPELL_DEMON_TRANSFORM_3, true); - if (Aura* aura = GetUnitOwner()->GetAura(SPELL_DEMON_TRANSFORM_3)) - aura->SetDuration(4300); - Remove(); - } - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidan_demon_transform2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_demon_transform2_AuraScript(); - } -}; - -// 41126 - Flame Burst -class spell_illidan_flame_burst : public SpellScriptLoader -{ - public: - spell_illidan_flame_burst() : SpellScriptLoader("spell_illidan_flame_burst") { } - - class spell_illidan_flame_burst_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_FLAME_BURST_EFFECT }); - } - - void HandleScriptEffect(SpellEffIndex /*effIndex*/) - { - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FLAME_BURST_EFFECT, true); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_flame_burst_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_flame_burst_SpellScript(); - } -}; - -// 41081 - Find Target -class spell_illidan_find_target : public SpellScriptLoader -{ - public: - spell_illidan_find_target() : SpellScriptLoader("spell_illidan_find_target") { } - - class spell_illidan_find_target_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PARALYZE }); - } - - void FilterTargets(std::list& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_PARALYZE)); - - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - if (Creature* caster = GetCaster()->ToCreature()) - { - caster->CastSpell(target, SPELL_PARALYZE, true); - caster->AI()->SetGUID(target->GetGUID(), 0); - } - } - - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_illidan_find_target_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget.Register(&spell_illidan_find_target_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_find_target_SpellScript(); - } -}; - -// 39908 - Eye Blast -class spell_illidan_eye_blast : public SpellScriptLoader -{ - public: - spell_illidan_eye_blast() : SpellScriptLoader("spell_illidan_eye_blast") { } - - class spell_illidan_eye_blast_AuraScript : public AuraScript - { - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Creature* target = GetTarget()->ToCreature()) - target->DespawnOrUnsummon(); - } - - void Register() override - { - AfterEffectRemove.Register(&spell_illidan_eye_blast_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_eye_blast_AuraScript(); - } -}; - -// 40761 - Cage Trap -class spell_illidan_cage_trap : public SpellScriptLoader -{ - public: - spell_illidan_cage_trap() : SpellScriptLoader("spell_illidan_cage_trap") { } - - class spell_illidan_cage_trap_SpellScript : public SpellScript - { - void HandleScriptEffect(SpellEffIndex /*effIndex*/) - { - Creature* target = GetHitCreature(); - Creature* caster = GetCaster()->ToCreature(); - - if (!target || !caster) - return; - - if (caster->GetDistance2d(target) < 4.0f) - { - target->AI()->DoAction(ACTION_ILLIDAN_CAGED); - caster->DespawnOrUnsummon(); - if (GameObject* trap = target->FindNearestGameObject(GO_ILLIDAN_CAGE_TRAP, 10.0f)) - trap->UseDoorOrButton(); - } - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_cage_trap_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_cage_trap_SpellScript(); - } -}; - -// 40760 - Cage Trap -class spell_illidan_caged : public SpellScriptLoader -{ - public: - spell_illidan_caged() : SpellScriptLoader("spell_illidan_caged") { } - - class spell_illidan_caged_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_CAGED_DEBUFF }); - } - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - Unit* target = GetTarget(); - target->CastSpell(target, SPELL_CAGED_DEBUFF, true); - Remove(); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidan_caged_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidan_caged_AuraScript(); - } -}; - -// 40409 - Maiev Down -class spell_maiev_down : public SpellScriptLoader -{ -public: - spell_maiev_down() : SpellScriptLoader("spell_maiev_down") { } - - class spell_maiev_down_AuraScript : public AuraScript + void HandleDummy(SpellEffIndex /*effIndex*/) { - bool Load() override - { - return GetUnitOwner()->GetTypeId() == TYPEID_UNIT; - } + Unit* target = GetHitUnit(); + target->m_Events.AddEvent(new SummonWarglaiveEvent(target), target->m_Events.CalculateTime(1000)); + } - void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - GetTarget()->GetAI()->DoAction(ACTION_MAIEV_DOWN_FADE); - } - - void Register() override - { - OnEffectApply.Register(&spell_maiev_down_AuraScript::HandleEffectApply, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove.Register(&spell_maiev_down_AuraScript::HandleEffectRemove, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_maiev_down_AuraScript(); + OnEffectHitTarget.Register(&spell_illidan_throw_warglaive::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; -// 40693 - Cage Trap -class spell_illidan_cage_teleport : public SpellScriptLoader +// 39857 - Tear of Azzinoth Summon Channel +class spell_illidan_tear_of_azzinoth_channel : public AuraScript { - public: - spell_illidan_cage_teleport() : SpellScriptLoader("spell_illidan_cage_teleport") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_UNCAGED_WRATH }); + } - class spell_illidan_cage_teleport_SpellScript : public SpellScript + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) { - void SetDest(SpellDestination& dest) + Unit* target = GetTarget(); + if (caster->GetDistance2d(target) > 25.0f) { - Position offset = { 0.0f, 0.0f, GetCaster()->GetPositionZ(), 0.0f }; - dest.RelocateOffset(offset); + target->CastSpell(target, SPELL_UNCAGED_WRATH, true); + Remove(); } - - void Register() override - { - OnDestinationTargetSelect.Register(&spell_illidan_cage_teleport_SpellScript::SetDest, EFFECT_0, TARGET_DEST_CASTER_RADIUS); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_cage_teleport_SpellScript(); } + } + + void Register() override + { + OnEffectPeriodic.Register(&spell_illidan_tear_of_azzinoth_channel::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + +// 40631 - Flame Blast +class spell_illidan_flame_blast : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLAZE_SUMMON }); + } + + void HandleBlaze(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (target->GetTypeId() == TYPEID_PLAYER) + target->CastSpell(target, SPELL_BLAZE_SUMMON, true); + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_flame_blast::HandleBlaze, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } +}; + +// 39873 - Glaive Returns +class spell_illidan_return_glaives : public SpellScript +{ + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->SendPlaySpellVisualKit(SPELL_GLAIVE_VISUAL_KIT, 0, 0); + if (Creature* caster = GetCaster()->ToCreature()) + caster->DespawnOrUnsummon(); + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_return_glaives::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 40834 - Agonizing Flames +class spell_illidan_agonizing_flames : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_AGONIZING_FLAMES }); + } + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_AGONIZING_FLAMES, true); + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_illidan_agonizing_flames::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget.Register(&spell_illidan_agonizing_flames::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +// 40511 - Demon Transform 1 +class spell_illidan_demon_transform1 : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEMON_TRANSFORM_2 }); + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_DEMON_TRANSFORM_2, true); + Remove(); + } + + void Register() override + { + OnEffectPeriodic.Register(&spell_illidan_demon_transform1::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + + +// 40398 - Demon Transform 2 +class spell_illidan_demon_transform2 : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEMON_FORM, SPELL_DEMON_TRANSFORM_3 }); + } + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + Unit* target = GetTarget(); + + if (aurEff->GetTickNumber() == 1) + { + if (target->GetDisplayId() == target->GetNativeDisplayId()) + target->CastSpell(target, SPELL_DEMON_FORM, true); + else + target->RemoveAurasDueToSpell(SPELL_DEMON_FORM); + } + else if (aurEff->GetTickNumber() == 2) + { + target->CastSpell(target, SPELL_DEMON_TRANSFORM_3, true); + if (Aura* aura = GetUnitOwner()->GetAura(SPELL_DEMON_TRANSFORM_3)) + aura->SetDuration(4300); + Remove(); + } + } + + void Register() override + { + OnEffectPeriodic.Register(&spell_illidan_demon_transform2::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + +// 41126 - Flame Burst +class spell_illidan_flame_burst : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_FLAME_BURST_EFFECT }); + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FLAME_BURST_EFFECT, true); + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_flame_burst::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 41081 - Find Target +class spell_illidan_find_target : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PARALYZE }); + } + + void FilterTargets(std::list& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_PARALYZE)); + + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (Creature* caster = GetCaster()->ToCreature()) + { + caster->CastSpell(target, SPELL_PARALYZE, true); + caster->AI()->SetGUID(target->GetGUID(), 0); + } + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_illidan_find_target::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget.Register(&spell_illidan_find_target::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +// 39908 - Eye Blast +class spell_illidan_eye_blast : public AuraScript +{ + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->DespawnOrUnsummon(); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_illidan_eye_blast::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 40761 - Cage Trap +class spell_illidan_cage_trap : public SpellScript +{ + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + Creature* target = GetHitCreature(); + Creature* caster = GetCaster()->ToCreature(); + + if (!target || !caster) + return; + + if (caster->GetDistance2d(target) < 4.0f) + { + target->AI()->DoAction(ACTION_ILLIDAN_CAGED); + caster->DespawnOrUnsummon(); + if (GameObject* trap = target->FindNearestGameObject(GO_ILLIDAN_CAGE_TRAP, 10.0f)) + trap->UseDoorOrButton(); + } + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_cage_trap::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 40760 - Cage Trap +class spell_illidan_caged : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_CAGED_DEBUFF }); + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_CAGED_DEBUFF, true); + Remove(); + } + + void Register() override + { + OnEffectPeriodic.Register(&spell_illidan_caged::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + +// 40409 - Maiev Down +class spell_maiev_down : public AuraScript +{ + bool Load() override + { + return GetUnitOwner()->GetTypeId() == TYPEID_UNIT; + } + + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + GetTarget()->GetAI()->DoAction(ACTION_MAIEV_DOWN_FADE); + } + + void Register() override + { + OnEffectApply.Register(&spell_maiev_down::HandleEffectApply, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove.Register(&spell_maiev_down::HandleEffectRemove, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 40693 - Cage Trap +class spell_illidan_cage_teleport : public SpellScript +{ + void SetDest(SpellDestination& dest) + { + Position offset = { 0.0f, 0.0f, GetCaster()->GetPositionZ(), 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect.Register(&spell_illidan_cage_teleport::SetDest, EFFECT_0, TARGET_DEST_CASTER_RADIUS); + } }; // 41242 - Akama Despawn -class spell_illidan_despawn_akama : public SpellScriptLoader +class spell_illidan_despawn_akama : public SpellScript { - public: - spell_illidan_despawn_akama() : SpellScriptLoader("spell_illidan_despawn_akama") { } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Creature* target = GetHitCreature()) + target->DespawnOrUnsummon(Seconds(1)); + } - class spell_illidan_despawn_akama_SpellScript : public SpellScript - { - void HandleDummy(SpellEffIndex /*effIndex*/) - { - if (Creature* target = GetHitCreature()) - target->DespawnOrUnsummon(Seconds(1)); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidan_despawn_akama_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidan_despawn_akama_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_illidan_despawn_akama::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; void AddSC_boss_illidan() { - new boss_illidan_stormrage(); - new npc_akama(); - new npc_parasitic_shadowfiend(); - new npc_blade_of_azzinoth(); - new npc_flame_of_azzinoth(); - new npc_illidan_db_target(); - new npc_maiev(); - new npc_illidan_shadow_demon(); - new npc_cage_trap_trigger(); - new spell_illidan_akama_teleport(); - new spell_illidan_akama_door_channel(); - new spell_illidan_draw_soul(); - new spell_illidan_parasitic_shadowfiend(); - new spell_illidan_throw_warglaive(); - new spell_illidan_tear_of_azzinoth_channel(); - new spell_illidan_flame_blast(); - new spell_illidan_return_glaives(); - new spell_illidan_agonizing_flames(); - new spell_illidan_demon_transform1(); - new spell_illidan_demon_transform2(); - new spell_illidan_flame_burst(); - new spell_illidan_find_target(); - new spell_illidan_eye_blast(); - new spell_illidan_cage_trap(); - new spell_illidan_caged(); - new spell_maiev_down(); - new spell_illidan_cage_teleport(); - new spell_illidan_despawn_akama(); + RegisterBlackTempleCreatureAI(boss_illidan_stormrage); + RegisterBlackTempleCreatureAI(npc_akama_illidan); + RegisterBlackTempleCreatureAI(npc_parasitic_shadowfiend); + RegisterBlackTempleCreatureAI(npc_blade_of_azzinoth); + RegisterBlackTempleCreatureAI(npc_flame_of_azzinoth); + RegisterBlackTempleCreatureAI(npc_illidan_db_target); + RegisterBlackTempleCreatureAI(npc_maiev); + RegisterBlackTempleCreatureAI(npc_shadow_demon); + RegisterBlackTempleCreatureAI(npc_cage_trap_trigger); + RegisterBlackTempleCreatureAI(npc_illidari_elite); + RegisterBlackTempleCreatureAI(npc_illidan_generic_fire); + RegisterSpellScript(spell_illidan_akama_teleport); + RegisterSpellScript(spell_illidan_akama_door_channel); + RegisterSpellScript(spell_illidan_draw_soul); + RegisterSpellScript(spell_illidan_parasitic_shadowfiend); + RegisterSpellScript(spell_illidan_parasitic_shadowfiend_proc); + RegisterSpellScript(spell_illidan_remove_parasitic_shadowfiend); + RegisterSpellScript(spell_illidan_throw_warglaive); + RegisterSpellScript(spell_illidan_tear_of_azzinoth_channel); + RegisterSpellScript(spell_illidan_flame_blast); + RegisterSpellScript(spell_illidan_return_glaives); + RegisterSpellScript(spell_illidan_agonizing_flames); + RegisterSpellScript(spell_illidan_demon_transform1); + RegisterSpellScript(spell_illidan_demon_transform2); + RegisterSpellScript(spell_illidan_flame_burst); + RegisterSpellScript(spell_illidan_find_target); + RegisterSpellScript(spell_illidan_eye_blast); + RegisterSpellScript(spell_illidan_cage_trap); + RegisterSpellScript(spell_illidan_caged); + RegisterSpellScript(spell_maiev_down); + RegisterSpellScript(spell_illidan_cage_teleport); + RegisterSpellScript(spell_illidan_despawn_akama); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp index 473e813020..11c5241a41 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidari_council.cpp @@ -18,7 +18,7 @@ #include "ScriptMgr.h" #include "black_temple.h" #include "CellImpl.h" -#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" #include "InstanceScript.h" #include "PassiveAI.h" #include "ScriptedCreature.h" @@ -27,70 +27,71 @@ enum Says { - SAY_COUNCIL_AGRO = 0, - SAY_COUNCIL_ENRAGE = 1, - SAY_COUNCIL_SPECIAL = 2, - SAY_COUNCIL_SLAY = 3, - SAY_COUNCIL_COMNT = 4, - SAY_COUNCIL_DEATH = 5 + SAY_COUNCIL_AGRO = 0, + SAY_COUNCIL_ENRAGE = 1, + SAY_COUNCIL_SPECIAL = 2, + SAY_COUNCIL_SLAY = 3, + SAY_COUNCIL_COMNT = 4, + SAY_COUNCIL_DEATH = 5 }; enum Spells { // Illidari Council (Trigger) - SPELL_EMPYREAL_BALANCE = 41499, - SPELL_EMPYREAL_EQUIVALENCY = 41333, + SPELL_EMPYREAL_BALANCE = 41499, + SPELL_EMPYREAL_EQUIVALENCY = 41333, // Generic - SPELL_SHARED_RULE = 41342, - SPELL_BERSERK = 45078, - SPELL_BALANCE_OF_POWER = 41341, - SPELL_QUIET_SUICIDE = 3617, // Serverside spell + SPELL_SHARED_RULE = 41342, + SPELL_BERSERK = 45078, + SPELL_BALANCE_OF_POWER = 41341, + SPELL_QUIET_SUICIDE = 3617, // High Nethermancer Zerevor's - SPELL_FLAMESTRIKE = 41481, - SPELL_BLIZZARD = 41482, - SPELL_ARCANE_BOLT = 41483, - SPELL_ARCANE_EXPLOSION = 41524, - SPELL_DAMPEN_MAGIC = 41478, + SPELL_FLAMESTRIKE = 41481, + SPELL_BLIZZARD = 41482, + SPELL_ARCANE_BOLT = 41483, + SPELL_ARCANE_EXPLOSION = 41524, + SPELL_DAMPEN_MAGIC = 41478, // Lady Malande's - SPELL_EMPOWERED_SMITE = 41471, - SPELL_CIRCLE_OF_HEALING = 41455, - SPELL_REFLECTIVE_SHIELD = 41475, - SPELL_REFLECTIVE_SHIELD_DAMAGE = 33619, - SPELL_DIVINE_WRATH = 41472, + SPELL_EMPOWERED_SMITE = 41471, + SPELL_CIRCLE_OF_HEALING = 41455, + SPELL_REFLECTIVE_SHIELD = 41475, + SPELL_REFLECTIVE_SHIELD_DAMAGE = 33619, + SPELL_DIVINE_WRATH = 41472, // Gathios the Shatterer's - SPELL_BLESS_PROTECTION = 41450, - SPELL_BLESS_SPELL_WARDING = 41451, - SPELL_CONSECRATION = 41541, - SPELL_HAMMER_OF_JUSTICE = 41468, - SPELL_SEAL_OF_COMMAND = 41469, - SPELL_SEAL_OF_BLOOD = 41459, - SPELL_CHROMATIC_AURA = 41453, - SPELL_DEVOTION_AURA = 41452, - SPELL_JUDGEMENT_PRIMER = 41473, - SPELL_JUDGEMENT = 41467, - SPELL_JUDGEMENT_OF_COMMAND = 41470, - SPELL_JUDGEMENT_OF_BLOOD = 41461, + SPELL_BLESS_PROTECTION = 41450, + SPELL_BLESS_SPELL_WARDING = 41451, + SPELL_CONSECRATION = 41541, + SPELL_HAMMER_OF_JUSTICE = 41468, + SPELL_SEAL_OF_COMMAND = 41469, + SPELL_SEAL_OF_BLOOD = 41459, + SPELL_CHROMATIC_AURA = 41453, + SPELL_DEVOTION_AURA = 41452, + SPELL_JUDGEMENT_PRIMER = 41473, + SPELL_JUDGEMENT = 41467, + SPELL_JUDGEMENT_OF_COMMAND = 41470, + SPELL_JUDGEMENT_OF_BLOOD = 41461, // Veras Darkshadow's - SPELL_DEADLY_STRIKE = 41480, - SPELL_DEADLY_POISON = 41485, - SPELL_ENVENOM = 41487, - SPELL_VANISH = 41476, + SPELL_DEADLY_STRIKE = 41480, + SPELL_DEADLY_POISON = 41485, + SPELL_ENVENOM = 41487, + SPELL_ENVENOM_VISUAL = 41509, + SPELL_VANISH = 41476, + SPELL_VANISH_TELEPORT = 41479, // Veras Vanish Effect - SPELL_BIRTH = 40031, - SPELL_ENVENOM_DUMMY = 41510 + SPELL_BIRTH = 40031, + SPELL_ENVENOM_DUMMY = 41510 }; enum IllidariEvents { EVENT_EMPYREAL_EQUIVALENCY = 1, EVENT_VANISH, - EVENT_DEADLY_STRIKE, EVENT_FLAMESTRIKE, EVENT_BLIZZARD, EVENT_ARCANE_EXPLOSION, @@ -128,126 +129,116 @@ static uint32 GetRandomBossExcept(uint32 exception) if (data != exception) bossData.emplace_back(data); - return bossData[urand(0, 3)]; + return Trinity::Containers::SelectRandomContainerElement(bossData); } -class boss_illidari_council : public CreatureScript +struct boss_illidari_council : public BossAI { -public: - boss_illidari_council() : CreatureScript("boss_illidari_council") { } + boss_illidari_council(Creature* creature) : BossAI(creature, DATA_ILLIDARI_COUNCIL), _inCombat(false) { } - struct boss_illidari_councilAI : public BossAI + void Reset() override { - boss_illidari_councilAI(Creature* creature) : BossAI(creature, DATA_ILLIDARI_COUNCIL), _inCombat(false) { } + _Reset(); + _inCombat = false; + me->SummonCreatureGroup(SUMMON_COUNCIL_GROUP); + } - void Reset() override + void JustEngagedWith(Unit* who) override + { + if (!_inCombat) { - _Reset(); - _inCombat = false; - me->SummonCreatureGroup(SUMMON_COUNCIL_GROUP); + _inCombat = true; + BossAI::JustEngagedWith(who); DoCastSelf(SPELL_EMPYREAL_BALANCE, true); - } - - void JustEngagedWith(Unit* who) override - { - if (!_inCombat) - { - _inCombat = true; - _JustEngagedWith(who); - for (uint32 bossData : CouncilData) - { - if (Creature* council = instance->GetCreature(bossData)) - { - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, council); - DoZoneInCombat(council); - } - } - events.ScheduleEvent(EVENT_EMPYREAL_EQUIVALENCY, Seconds(2)); - events.ScheduleEvent(EVENT_BERSERK, Minutes(15)); - if (Creature* council = instance->GetCreature(CouncilData[urand(0, 3)])) - council->AI()->Talk(SAY_COUNCIL_AGRO); - } - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (!me->IsInEvadeMode()) - { - _inCombat = false; - for (uint32 bossData : CouncilData) - if (Creature* council = instance->GetCreature(bossData)) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); - - summons.DespawnAll(); - _DespawnAtEvade(); - } - } - - void JustDied(Unit* /*killer*/) override - { - _inCombat = false; - events.Reset(); - instance->SetBossState(DATA_ILLIDARI_COUNCIL, DONE); - for (uint32 bossData : CouncilData) { if (Creature* council = instance->GetCreature(bossData)) { - // Allow loot - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); - council->LowerPlayerDamageReq(council->GetMaxHealth()); - council->CastSpell(council, SPELL_QUIET_SUICIDE, true); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, council); + DoZoneInCombat(council); } } + events.ScheduleEvent(EVENT_EMPYREAL_EQUIVALENCY, 2s); + events.ScheduleEvent(EVENT_BERSERK, 15min); + if (Creature* council = instance->GetCreature(CouncilData[urand(0, 3)])) + council->AI()->Talk(SAY_COUNCIL_AGRO); } + } - void UpdateAI(uint32 diff) override + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (!me->IsInEvadeMode()) { - if (!UpdateVictim()) - return; + _inCombat = false; + for (uint32 bossData : CouncilData) + if (Creature* council = instance->GetCreature(bossData)) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); - events.Update(diff); + summons.DespawnAll(); + _DespawnAtEvade(); + } + } + + void JustDied(Unit* /*killer*/) override + { + _inCombat = false; + events.Reset(); + instance->SetBossState(DATA_ILLIDARI_COUNCIL, DONE); + + for (uint32 bossData : CouncilData) + { + if (Creature* council = instance->GetCreature(bossData)) + { + // Allow loot + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, council); + council->LowerPlayerDamageReq(council->GetMaxHealth()); + council->CastSpell(council, SPELL_QUIET_SUICIDE, true); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_EMPYREAL_EQUIVALENCY: + DoCastSelf(SPELL_EMPYREAL_EQUIVALENCY, true); + events.Repeat(Seconds(2)); + break; + case EVENT_BERSERK: + for (uint32 bossData : CouncilData) + { + if (Creature* council = instance->GetCreature(bossData)) + { + council->CastSpell(council, SPELL_BERSERK, true); + council->AI()->Talk(SAY_COUNCIL_ENRAGE); + } + } + break; + default: + break; + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_EMPYREAL_EQUIVALENCY: - DoCastSelf(SPELL_EMPYREAL_EQUIVALENCY, true); - events.Repeat(Seconds(2)); - break; - case EVENT_BERSERK: - for (uint32 bossData : CouncilData) - { - if (Creature* council = instance->GetCreature(bossData)) - { - council->CastSpell(council, SPELL_BERSERK, true); - council->AI()->Talk(SAY_COUNCIL_ENRAGE); - } - } - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } } - - private: - bool _inCombat; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); } + +private: + bool _inCombat; }; + struct IllidariCouncilBossAI : public BossAI { IllidariCouncilBossAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _bossId(bossId) @@ -259,6 +250,7 @@ struct IllidariCouncilBossAI : public BossAI { me->SetCombatPulseDelay(0); events.Reset(); + DoCastSelf(SPELL_BALANCE_OF_POWER, true); } void JustEngagedWith(Unit* /*who*/) override @@ -285,7 +277,7 @@ struct IllidariCouncilBossAI : public BossAI void DamageTaken(Unit* who, uint32 &damage) override { - if (damage >= me->GetHealth() && who->GetGUID() != me->GetGUID()) + if (damage >= me->GetHealth() && (!who || who->GetGUID() != me->GetGUID())) damage = me->GetHealth() - 1; } @@ -305,632 +297,507 @@ private: class HammerTargetSelector { - public: - HammerTargetSelector(Unit const* unit) : _me(unit) { } +public: + HammerTargetSelector(Unit const* unit) : _me(unit) { } - bool operator()(Unit* unit) const - { - return _me->IsInRange(unit, 10.0f, 40.0f); - } + bool operator()(Unit* unit) const + { + return _me->IsInRange(unit, 10.0f, 40.0f); + } - private: - Unit const* _me; +private: + Unit const* _me; }; -class boss_gathios_the_shatterer : public CreatureScript +struct boss_gathios_the_shatterer : public IllidariCouncilBossAI { -public: - boss_gathios_the_shatterer() : CreatureScript("boss_gathios_the_shatterer") { } + boss_gathios_the_shatterer(Creature* creature) : IllidariCouncilBossAI(creature, DATA_GATHIOS_THE_SHATTERER) { } - struct boss_gathios_the_shattererAI : public IllidariCouncilBossAI + void ScheduleEvents() override { - boss_gathios_the_shattererAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_GATHIOS_THE_SHATTERER) { } + DoCastSelf(SPELL_SEAL_OF_BLOOD); + events.ScheduleEvent(EVENT_BLESS, 20s); + events.ScheduleEvent(EVENT_CONSECRATION, 10s); + events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, 10s); + events.ScheduleEvent(EVENT_JUDGEMENT, 15s); + events.ScheduleEvent(EVENT_AURA, 6s); + } - void ScheduleEvents() override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - DoCastSelf(SPELL_SEAL_OF_BLOOD); - events.ScheduleEvent(EVENT_BLESS, Seconds(20)); - events.ScheduleEvent(EVENT_CONSECRATION, Seconds(10)); - events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, Seconds(10)); - events.ScheduleEvent(EVENT_JUDGEMENT, Seconds(15)); - events.ScheduleEvent(EVENT_AURA, Seconds(6)); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_BLESS: { - case EVENT_BLESS: + std::list TargetList; + Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 100.0f); + Trinity::UnitListSearcher searcher(me, TargetList, checker); + Cell::VisitAllObjects(me, searcher, 100.0f); + + if (!TargetList.empty()) { - std::list TargetList; - Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 100.0f); - Trinity::UnitListSearcher searcher(me, TargetList, checker); - Cell::VisitAllObjects(me, searcher, 100.0f); - - if (!TargetList.empty()) - { - Unit* target = Trinity::Containers::SelectRandomContainerElement(TargetList); - DoCast(target, RAND(SPELL_BLESS_PROTECTION, SPELL_BLESS_SPELL_WARDING)); - } - events.Repeat(Seconds(30), Seconds(45)); - break; + Unit* target = Trinity::Containers::SelectRandomContainerElement(TargetList); + DoCast(target, RAND(SPELL_BLESS_PROTECTION, SPELL_BLESS_SPELL_WARDING)); } - case EVENT_AURA: - DoCastSelf(RAND(SPELL_CHROMATIC_AURA, SPELL_DEVOTION_AURA)); - events.Repeat(Seconds(30)); - break; - case EVENT_HAMMER_OF_JUSTICE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, HammerTargetSelector(me))) - DoCast(target, SPELL_HAMMER_OF_JUSTICE); - events.Repeat(Seconds(20)); - break; - case EVENT_JUDGEMENT: - DoCastVictim(SPELL_JUDGEMENT); - events.Repeat(Seconds(15)); - break; - case EVENT_CONSECRATION: - DoCastSelf(SPELL_CONSECRATION); - events.Repeat(Seconds(30), Seconds(35)); - break; - default: - break; + events.Repeat(Seconds(30), Seconds(45)); + break; } + case EVENT_AURA: + DoCastSelf(RAND(SPELL_CHROMATIC_AURA, SPELL_DEVOTION_AURA)); + events.Repeat(Seconds(30)); + break; + case EVENT_HAMMER_OF_JUSTICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, HammerTargetSelector(me))) + DoCast(target, SPELL_HAMMER_OF_JUSTICE); + events.Repeat(Seconds(20)); + break; + case EVENT_JUDGEMENT: + DoCastVictim(SPELL_JUDGEMENT); + events.Repeat(Seconds(15)); + break; + case EVENT_CONSECRATION: + DoCastSelf(SPELL_CONSECRATION); + events.Repeat(Seconds(30), Seconds(35)); + break; + default: + break; } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); } }; -class boss_high_nethermancer_zerevor : public CreatureScript +struct boss_high_nethermancer_zerevor : public IllidariCouncilBossAI { -public: - boss_high_nethermancer_zerevor() : CreatureScript("boss_high_nethermancer_zerevor") { } + boss_high_nethermancer_zerevor(Creature* creature) : IllidariCouncilBossAI(creature, DATA_HIGH_NETHERMANCER_ZEREVOR), _canUseArcaneExplosion(true) { } - struct boss_high_nethermancer_zerevorAI : public IllidariCouncilBossAI + void Reset() override { - boss_high_nethermancer_zerevorAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_HIGH_NETHERMANCER_ZEREVOR), _canUseArcaneExplosion(true) { } + IllidariCouncilBossAI::Reset(); + _canUseArcaneExplosion = true; + DoCastSelf(SPELL_DAMPEN_MAGIC); + } - void Reset() override + void ScheduleEvents() override + { + events.ScheduleEvent(EVENT_FLAMESTRIKE, 8s); + events.ScheduleEvent(EVENT_BLIZZARD, 25s); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 5s); + DoCastSelf(SPELL_DAMPEN_MAGIC); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_REFRESH_DAMPEN) + events.ScheduleEvent(EVENT_DAMPEN_MAGIC, 50s); + } + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - IllidariCouncilBossAI::Reset(); - _canUseArcaneExplosion = true; - DoCastSelf(SPELL_DAMPEN_MAGIC); + case EVENT_FLAMESTRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_FLAMESTRIKE); + Talk(SAY_COUNCIL_SPECIAL); + events.Repeat(Seconds(40)); + break; + case EVENT_BLIZZARD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_BLIZZARD); + events.Repeat(Seconds(15), Seconds(40)); + break; + case EVENT_ARCANE_EXPLOSION_CHECK: + _canUseArcaneExplosion = true; + break; + case EVENT_ARCANE_EXPLOSION: + if (_canUseArcaneExplosion && SelectTarget(SELECT_TARGET_RANDOM, 0, 10.0f)) + { + DoCastSelf(SPELL_ARCANE_EXPLOSION); + _canUseArcaneExplosion = false; + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION_CHECK, 5s); + } + events.Repeat(Seconds(1)); + break; + case EVENT_DAMPEN_MAGIC: + DoCastSelf(SPELL_DAMPEN_MAGIC); + break; + default: + break; } + } - void ScheduleEvents() override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - events.ScheduleEvent(EVENT_FLAMESTRIKE, Seconds(8)); - events.ScheduleEvent(EVENT_BLIZZARD, Seconds(25)); - events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, Seconds(5)); - DoCastSelf(SPELL_DAMPEN_MAGIC); - } - - void DoAction(int32 actionId) override - { - if (actionId == ACTION_REFRESH_DAMPEN) - events.ScheduleEvent(EVENT_DAMPEN_MAGIC, Seconds(50)); - } - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_FLAMESTRIKE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_FLAMESTRIKE); - Talk(SAY_COUNCIL_SPECIAL); - events.Repeat(Seconds(40)); - break; - case EVENT_BLIZZARD: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_BLIZZARD); - events.Repeat(Seconds(15), Seconds(40)); - break; - case EVENT_ARCANE_EXPLOSION_CHECK: - _canUseArcaneExplosion = true; - break; - case EVENT_ARCANE_EXPLOSION: - if (_canUseArcaneExplosion && SelectTarget(SELECT_TARGET_RANDOM, 0, 10.0f)) - { - DoCastSelf(SPELL_ARCANE_EXPLOSION); - _canUseArcaneExplosion = false; - events.ScheduleEvent(EVENT_ARCANE_EXPLOSION_CHECK, Seconds(5)); - } - events.Repeat(Seconds(1)); - break; - case EVENT_DAMPEN_MAGIC: - DoCastSelf(SPELL_DAMPEN_MAGIC); - break; - default: - break; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - + ExecuteEvent(eventId); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - ExecuteEvent(eventId); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoSpellAttackIfReady(SPELL_ARCANE_BOLT); } - private: - bool _canUseArcaneExplosion; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoSpellAttackIfReady(SPELL_ARCANE_BOLT); } +private: + bool _canUseArcaneExplosion; }; -class boss_lady_malande : public CreatureScript +struct boss_lady_malande : public IllidariCouncilBossAI { -public: - boss_lady_malande() : CreatureScript("boss_lady_malande") { } + boss_lady_malande(Creature* creature) : IllidariCouncilBossAI(creature, DATA_LADY_MALANDE) { } - struct boss_lady_malandeAI : public IllidariCouncilBossAI + void ScheduleEvents() override { - boss_lady_malandeAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_LADY_MALANDE) { } + events.ScheduleEvent(EVENT_CIRCLE_OF_HEALING, 20s); + events.ScheduleEvent(EVENT_REFLECTIVE_SHIELD, 25s); + events.ScheduleEvent(EVENT_DIVINE_WRATH, 32s); + } - void ScheduleEvents() override + void HealReceived(Unit* /*who*/, uint32& addhealth) override + { + // Need be negative to heal trigger + me->CastSpell(nullptr, SPELL_SHARED_RULE, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(-int32(addhealth))); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - events.ScheduleEvent(EVENT_CIRCLE_OF_HEALING, Seconds(20)); - events.ScheduleEvent(EVENT_REFLECTIVE_SHIELD, Seconds(25)); - events.ScheduleEvent(EVENT_DIVINE_WRATH, Seconds(32)); + case EVENT_CIRCLE_OF_HEALING: + DoCastSelf(SPELL_CIRCLE_OF_HEALING); + events.Repeat(Seconds(20), Seconds(35)); + break; + case EVENT_REFLECTIVE_SHIELD: + DoCastSelf(SPELL_REFLECTIVE_SHIELD); + Talk(SAY_COUNCIL_SPECIAL); + events.Repeat(Seconds(40)); + break; + case EVENT_DIVINE_WRATH: + DoCastVictim(SPELL_DIVINE_WRATH); + events.Repeat(Seconds(20)); + break; + default: + break; } + } - void HealReceived(Unit* /*who*/, uint32& addhealth) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - // Need be negative to heal trigger - int32 bp = addhealth * (-1); - DoCast(nullptr, SPELL_SHARED_RULE, CastSpellExtraArgs(true).AddSpellBP0(bp)); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_CIRCLE_OF_HEALING: - DoCastSelf(SPELL_CIRCLE_OF_HEALING); - events.Repeat(Seconds(20), Seconds(35)); - break; - case EVENT_REFLECTIVE_SHIELD: - DoCastSelf(SPELL_REFLECTIVE_SHIELD); - Talk(SAY_COUNCIL_SPECIAL); - events.Repeat(Seconds(40)); - break; - case EVENT_DIVINE_WRATH: - DoCastVictim(SPELL_DIVINE_WRATH); - events.Repeat(Seconds(20)); - break; - default: - break; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - + ExecuteEvent(eventId); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - ExecuteEvent(eventId); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoSpellAttackIfReady(SPELL_EMPOWERED_SMITE); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); - } - -}; - -class boss_veras_darkshadow : public CreatureScript -{ -public: - boss_veras_darkshadow() : CreatureScript("boss_veras_darkshadow") { } - - struct boss_veras_darkshadowAI : public IllidariCouncilBossAI - { - boss_veras_darkshadowAI(Creature* creature) : IllidariCouncilBossAI(creature, DATA_VERAS_DARKSHADOW) - { - me->SetMaxHealth(1327900); - me->SetFullHealth(); } - void ScheduleEvents() override - { - events.ScheduleEvent(EVENT_DEADLY_STRIKE, Seconds(18)); - events.ScheduleEvent(EVENT_VANISH, Seconds(18)); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_DEADLY_STRIKE: - DoCastSelf(SPELL_DEADLY_STRIKE); - events.Repeat(Seconds(60)); - break; - case EVENT_VANISH: - DoCastSelf(SPELL_VANISH); - Talk(SAY_COUNCIL_SPECIAL); - events.Repeat(Seconds(60)); - break; - default: - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoSpellAttackIfReady(SPELL_EMPOWERED_SMITE); } }; -class npc_veras_vanish_effect : public CreatureScript +struct boss_veras_darkshadow : public IllidariCouncilBossAI { -public: - npc_veras_vanish_effect() : CreatureScript("npc_veras_vanish_effect") { } + boss_veras_darkshadow(Creature* creature) : IllidariCouncilBossAI(creature, DATA_VERAS_DARKSHADOW) { } - struct npc_veras_vanish_effectAI : public PassiveAI + void ScheduleEvents() override { - npc_veras_vanish_effectAI(Creature* creature) : PassiveAI(creature) { } + events.ScheduleEvent(EVENT_VANISH, 18s); + } - void Reset() override + bool CanSeeAlways(WorldObject const* who) override + { + return me->HasAura(SPELL_VANISH) ? true : ScriptedAI::CanSeeAlways(who); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_VANISH: + Talk(SAY_COUNCIL_SPECIAL); + DoCastSelf(SPELL_VANISH); + DoCastSelf(SPELL_DEADLY_STRIKE); + events.Repeat(Seconds(60)); + break; + default: + break; + } + } +}; + +struct npc_veras_vanish_effect : public PassiveAI +{ + npc_veras_vanish_effect(Creature* creature) : PassiveAI(creature) { } + + void Reset() override + { + DoCastSelf(SPELL_BIRTH, true); + _scheduler.Schedule(Seconds(1), [this](TaskContext /*context*/) { - DoCastSelf(SPELL_BIRTH, true); DoCastSelf(SPELL_ENVENOM_DUMMY, true); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + }); } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; }; // 41499 - Empyreal Balance -class spell_illidari_council_empyreal_balance : public SpellScriptLoader +class spell_illidari_council_empyreal_balance : public SpellScript { - public: - spell_illidari_council_empyreal_balance() : SpellScriptLoader("spell_illidari_council_empyreal_balance") { } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + uint32 health = GetCaster()->CountPctFromCurHealth(25); + target->SetMaxHealth(health); + target->SetHealth(health); + } - class spell_illidari_council_empyreal_balance_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_BALANCE_OF_POWER }); - } - - void HandleDummy(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - target->CastSpell(target, SPELL_BALANCE_OF_POWER, true); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidari_council_empyreal_balance_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidari_council_empyreal_balance_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_illidari_council_empyreal_balance::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; // 41333 - Empyreal Equivalency -class spell_illidari_council_empyreal_equivalency : public SpellScriptLoader +class spell_illidari_council_empyreal_equivalency : public SpellScript { - public: - spell_illidari_council_empyreal_equivalency() : SpellScriptLoader("spell_illidari_council_empyreal_equivalency") { } + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->SetHealth(GetCaster()->CountPctFromCurHealth(25)); + } - class spell_illidari_council_empyreal_equivalency_SpellScript : public SpellScript - { - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* target = GetHitUnit(); - int32 casterHpPct = (int32) GetCaster()->GetHealthPct(); - uint32 newHp = target->CountPctFromMaxHealth(casterHpPct); - if (newHp <= 0) - newHp = target->GetMaxHealth() - 1; - target->SetHealth(newHp); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_illidari_council_empyreal_equivalency_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidari_council_empyreal_equivalency_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_illidari_council_empyreal_equivalency::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; // 41341 - Balance of Power -class spell_illidari_council_balance_of_power : public SpellScriptLoader +class spell_illidari_council_balance_of_power : public AuraScript { - public: - spell_illidari_council_balance_of_power() : SpellScriptLoader("spell_illidari_council_balance_of_power") { } + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_SHARED_RULE }); + } - class spell_illidari_council_balance_of_power_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_SHARED_RULE }); - } + void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& /*absorbAmount*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(nullptr, SPELL_SHARED_RULE, CastSpellExtraArgs(aurEff).AddSpellBP0(dmgInfo.GetDamage())); + } - void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& /*absorbAmount*/) - { - PreventDefaultAction(); - int32 bp = dmgInfo.GetDamage(); - GetTarget()->CastSpell(nullptr, SPELL_SHARED_RULE, CastSpellExtraArgs(aurEff).AddSpellBP0(bp)); - } - - void Register() override - { - OnEffectAbsorb.Register(&spell_illidari_council_balance_of_power_AuraScript::Absorb, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_council_balance_of_power_AuraScript(); - } + void Register() override + { + OnEffectAbsorb.Register(&spell_illidari_council_balance_of_power::Absorb, EFFECT_0); + } }; // 41480 - Deadly Strike -class spell_illidari_council_deadly_strike : public SpellScriptLoader +class spell_illidari_council_deadly_strike : public AuraScript { - public: - spell_illidari_council_deadly_strike() : SpellScriptLoader("spell_illidari_council_deadly_strike") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEADLY_POISON }); + } - class spell_illidari_council_deadly_strike_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DEADLY_POISON }); - } + void OnTrigger(AuraEffect const* aurEff) + { + PreventDefaultAction(); - void OnTrigger(AuraEffect const* aurEff) - { - PreventDefaultAction(); + if (Unit* victim = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, true)) + GetTarget()->CastSpell(victim, SPELL_DEADLY_POISON, aurEff); + } - if (Unit* victim = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) - GetTarget()->CastSpell(victim, SPELL_DEADLY_POISON, CastSpellExtraArgs(aurEff)); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_illidari_council_deadly_strike_AuraScript::OnTrigger, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_council_deadly_strike_AuraScript(); - } + void Register() override + { + OnEffectPeriodic.Register(&spell_illidari_council_deadly_strike::OnTrigger, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; // 41485 - Deadly Poison -class spell_illidari_council_deadly_poison : public SpellScriptLoader +class spell_illidari_council_deadly_poison : public AuraScript { - public: - spell_illidari_council_deadly_poison() : SpellScriptLoader("spell_illidari_council_deadly_poison") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ENVENOM, SPELL_ENVENOM_VISUAL }); + } - class spell_illidari_council_deadly_poison_AuraScript : public AuraScript + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_ENVENOM }); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - caster->CastSpell(GetTarget(), SPELL_ENVENOM, true); - } - - void Register() override - { - OnEffectRemove.Register(&spell_illidari_council_deadly_poison_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_council_deadly_poison_AuraScript(); + Unit* target = GetTarget(); + caster->CastSpell(target, SPELL_ENVENOM, true); + target->CastSpell(nullptr, SPELL_ENVENOM_VISUAL, true); } + } + + void Register() override + { + OnEffectRemove.Register(&spell_illidari_council_deadly_poison::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 41476 - Vanish +class spell_illidari_council_vanish : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_VANISH_TELEPORT }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->CastSpell(GetTarget(), SPELL_VANISH_TELEPORT, true); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_illidari_council_vanish::OnRemove, EFFECT_0, SPELL_AURA_MOD_ROOT, AURA_EFFECT_HANDLE_REAL); + } }; // 41475 - Reflective Shield -class spell_illidari_council_reflective_shield : public SpellScriptLoader +class spell_illidari_council_reflective_shield : public AuraScript { - public: - spell_illidari_council_reflective_shield() : SpellScriptLoader("spell_illidari_council_reflective_shield") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_REFLECTIVE_SHIELD_DAMAGE }); + } - class spell_illidari_council_reflective_shield_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_REFLECTIVE_SHIELD_DAMAGE }); - } + void OnAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) + { + Unit* target = GetTarget(); + if (dmgInfo.GetAttacker() == target) + return; - void OnAbsorb(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) - { - Unit* target = GetTarget(); - if (dmgInfo.GetAttacker() == target) - return; + target->CastSpell(dmgInfo.GetAttacker(), SPELL_REFLECTIVE_SHIELD_DAMAGE, CastSpellExtraArgs(aurEff).AddSpellBP0(absorbAmount/2)); + } - int32 bp = absorbAmount / 2; - target->CastSpell(dmgInfo.GetAttacker(), SPELL_REFLECTIVE_SHIELD_DAMAGE, CastSpellExtraArgs(aurEff).AddSpellBP0(bp)); - } - - void Register() override - { - AfterEffectAbsorb.Register(&spell_illidari_council_reflective_shield_AuraScript::OnAbsorb, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_council_reflective_shield_AuraScript(); - } + void Register() override + { + AfterEffectAbsorb.Register(&spell_illidari_council_reflective_shield::OnAbsorb, EFFECT_0); + } }; // 41467 - Judgement -class spell_illidari_council_judgement : public SpellScriptLoader +class spell_illidari_council_judgement : public SpellScript { - public: - spell_illidari_council_judgement() : SpellScriptLoader("spell_illidari_council_judgement") { } - - class spell_illidari_council_judgement_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_JUDGEMENT_OF_BLOOD, SPELL_JUDGEMENT_OF_COMMAND, SPELL_JUDGEMENT_PRIMER }); - } + SPELL_JUDGEMENT_OF_BLOOD, + SPELL_JUDGEMENT_OF_COMMAND, + SPELL_JUDGEMENT_PRIMER + }); + } - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - Unit* target = GetHitUnit(); - uint32 judgementId = caster->HasAura(SPELL_SEAL_OF_BLOOD) ? SPELL_JUDGEMENT_OF_BLOOD : SPELL_JUDGEMENT_OF_COMMAND; - caster->CastSpell(target, SPELL_JUDGEMENT_PRIMER, true); - caster->CastSpell(target, judgementId, true); - } + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + uint32 judgementId = caster->HasAura(SPELL_SEAL_OF_BLOOD) ? SPELL_JUDGEMENT_OF_BLOOD : SPELL_JUDGEMENT_OF_COMMAND; + caster->CastSpell(target, SPELL_JUDGEMENT_PRIMER, true); + caster->CastSpell(target, judgementId, true); + } - void OnFinishCast() - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->Talk(SAY_COUNCIL_SPECIAL); - } + void OnFinishCast() + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->Talk(SAY_COUNCIL_SPECIAL); + } - void Register() override - { - OnEffectHitTarget.Register(&spell_illidari_council_judgement_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - AfterCast.Register(&spell_illidari_council_judgement_SpellScript::OnFinishCast); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_illidari_council_judgement_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_illidari_council_judgement::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + AfterCast.Register(&spell_illidari_council_judgement::OnFinishCast); + } }; /* 41469 - Seal of Command 41459 - Seal of Blood */ -class spell_illidari_council_seal : public SpellScriptLoader +class spell_illidari_council_seal : public AuraScript { - public: - spell_illidari_council_seal() : SpellScriptLoader("spell_illidari_council_seal") { } - - class spell_illidari_council_seal_AuraScript : public AuraScript + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SEAL_OF_COMMAND, SPELL_SEAL_OF_BLOOD }); - } + SPELL_SEAL_OF_COMMAND, + SPELL_SEAL_OF_BLOOD + }); + } - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (target->IsInWorld() && target->IsAlive()) - { - uint32 spellId = aurEff->GetId() == SPELL_SEAL_OF_COMMAND ? SPELL_SEAL_OF_BLOOD : SPELL_SEAL_OF_COMMAND; - target->CastSpell(target, spellId, true); - } - } - - void Register() override - { - OnEffectRemove.Register(&spell_illidari_council_seal_AuraScript::OnRemove, EFFECT_2, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->IsInWorld() && target->IsAlive()) { - return new spell_illidari_council_seal_AuraScript(); + uint32 spellId = aurEff->GetId() == SPELL_SEAL_OF_COMMAND ? SPELL_SEAL_OF_BLOOD : SPELL_SEAL_OF_COMMAND; + target->CastSpell(target, spellId, true); } + } + + void Register() override + { + OnEffectRemove.Register(&spell_illidari_council_seal::OnRemove, EFFECT_2, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } }; // 41478 - Dampen Magic -class spell_illidari_dampen_magic : public SpellScriptLoader +class spell_illidari_dampen_magic : public AuraScript { - public: - spell_illidari_dampen_magic() : SpellScriptLoader("spell_illidari_dampen_magic") { } - - class spell_illidari_dampen_magic_AuraScript : public AuraScript + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) { - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Creature* target = GetTarget()->ToCreature()) - { - if (GetTargetApplication()->GetRemoveMode().HasFlag(AuraRemoveFlags::ByEnemySpell | AuraRemoveFlags::Expired)) - target->AI()->DoAction(ACTION_REFRESH_DAMPEN); - } - } - - void Register() override - { - OnEffectRemove.Register(&spell_illidari_dampen_magic_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_illidari_dampen_magic_AuraScript(); + auto mode = GetTargetApplication()->GetRemoveMode(); + if (mode.HasFlag(AuraRemoveFlags::ByEnemySpell | AuraRemoveFlags::Expired)) + target->AI()->DoAction(ACTION_REFRESH_DAMPEN); } + } + + void Register() override + { + OnEffectRemove.Register(&spell_illidari_dampen_magic::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + } }; void AddSC_boss_illidari_council() { - new boss_illidari_council(); - new boss_gathios_the_shatterer(); - new boss_lady_malande(); - new boss_veras_darkshadow(); - new boss_high_nethermancer_zerevor(); - new npc_veras_vanish_effect(); - new spell_illidari_council_empyreal_balance(); - new spell_illidari_council_empyreal_equivalency(); - new spell_illidari_council_balance_of_power(); - new spell_illidari_council_deadly_strike(); - new spell_illidari_council_deadly_poison(); - new spell_illidari_council_reflective_shield(); - new spell_illidari_council_judgement(); - new spell_illidari_council_seal(); - new spell_illidari_dampen_magic(); + RegisterBlackTempleCreatureAI(boss_illidari_council); + RegisterBlackTempleCreatureAI(boss_gathios_the_shatterer); + RegisterBlackTempleCreatureAI(boss_lady_malande); + RegisterBlackTempleCreatureAI(boss_veras_darkshadow); + RegisterBlackTempleCreatureAI(boss_high_nethermancer_zerevor); + RegisterBlackTempleCreatureAI(npc_veras_vanish_effect); + RegisterSpellScript(spell_illidari_council_empyreal_balance); + RegisterSpellScript(spell_illidari_council_empyreal_equivalency); + RegisterSpellScript(spell_illidari_council_balance_of_power); + RegisterSpellScript(spell_illidari_council_deadly_strike); + RegisterSpellScript(spell_illidari_council_deadly_poison); + RegisterSpellScript(spell_illidari_council_vanish); + RegisterSpellScript(spell_illidari_council_reflective_shield); + RegisterSpellScript(spell_illidari_council_judgement); + RegisterSpellScript(spell_illidari_council_seal); + RegisterSpellScript(spell_illidari_dampen_magic); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp index 44e6a78dc0..5513be3702 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp @@ -17,11 +17,11 @@ #include "ScriptMgr.h" -#include "black_temple.h" -#include "GridNotifiers.h" #include "ScriptedCreature.h" -#include "SpellAuraEffects.h" +#include "black_temple.h" #include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "GridNotifiers.h" enum Texts { @@ -40,7 +40,7 @@ enum Spells SPELL_FATAL_ATTRACTION_DAMAGE = 40871, SPELL_SILENCING_SHRIEK = 40823, SPELL_SABER_LASH_IMMUNITY = 43690, - SPELL_FATAL_ATTACTION_TELEPORT = 40869, + SPELL_FATAL_ATTRACTION_TELEPORT = 40869, SPELL_BERSERK = 45078, SPELL_FATAL_ATTRACTION = 41001, SPELL_SINISTER_PERIODIC = 40863, @@ -96,296 +96,223 @@ uint32 const PrismaticAuras[6]= SPELL_PRISMATIC_AURA_HOLY }; -Position const TeleportPoint[7]= +struct boss_mother_shahraz : public BossAI { - { 959.996f, 212.576f, 193.843f }, - { 932.537f, 231.813f, 193.838f }, - { 958.675f, 254.767f, 193.822f }, - { 946.955f, 201.316f, 192.535f }, - { 944.294f, 149.676f, 197.551f }, - { 930.548f, 284.888f, 193.367f }, - { 965.997f, 278.398f, 195.777f } -}; + boss_mother_shahraz(Creature* creature) : BossAI(creature, DATA_MOTHER_SHAHRAZ), _enraged(false) { } -class boss_mother_shahraz : public CreatureScript -{ -public: - boss_mother_shahraz() : CreatureScript("boss_mother_shahraz") { } - - struct boss_shahrazAI : public BossAI + void Reset() override { - boss_shahrazAI(Creature* creature) : BossAI(creature, DATA_MOTHER_SHAHRAZ), _enraged(false) { } - - void Reset() override - { - _Reset(); - _enraged = false; - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_SILENCING_SHRIEK, Seconds(22)); - events.ScheduleEvent(EVENT_PRISMATIC_SHIELD, Seconds(15)); - events.ScheduleEvent(EVENT_FATAL_ATTRACTION, Seconds(35)); - events.ScheduleEvent(EVENT_RANDOM_BEAM, Seconds(6)); - events.ScheduleEvent(EVENT_BERSERK, Minutes(10)); - events.ScheduleEvent(EVENT_TAUNT, Seconds(35)); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - Talk(SAY_DEATH); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - _DespawnAtEvade(); - } - - void DamageTaken(Unit* /*attacker*/, uint32 &damage) override - { - if (!_enraged && me->HealthBelowPctDamaged(10, damage)) - { - _enraged = true; - DoCastSelf(SPELL_RANDOM_PERIODIC, true); - Talk(EMOTE_ENRAGE, me); - Talk(SAY_ENRAGE); - } - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_RANDOM_BEAM: - DoCastSelf(BeamTriggers[urand(0, 3)]); - events.Repeat(Seconds(30)); - break; - case EVENT_PRISMATIC_SHIELD: - DoCastSelf(PrismaticAuras[urand(0, 5)]); - events.Repeat(Seconds(15)); - break; - case EVENT_FATAL_ATTRACTION: - Talk(SAY_SPELL); - DoCastSelf(SPELL_FATAL_ATTACTION_TELEPORT, { SPELLVALUE_MAX_TARGETS, 3 }); - events.Repeat(Seconds(30)); - break; - case EVENT_SILENCING_SHRIEK: - DoCastVictim(SPELL_SILENCING_SHRIEK); - events.Repeat(Seconds(18), Seconds(30)); - break; - case EVENT_TAUNT: - Talk(SAY_TAUNT); - events.Repeat(Seconds(30), Seconds(40)); - break; - case EVENT_BERSERK: - Talk(EMOTE_BERSERK, me); - DoCastSelf(SPELL_BERSERK); - break; - default: - break; - } - } - - private: - bool _enraged; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _Reset(); + _enraged = false; } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_SILENCING_SHRIEK, 22s); + events.ScheduleEvent(EVENT_PRISMATIC_SHIELD, 15s); + events.ScheduleEvent(EVENT_FATAL_ATTRACTION, 35s); + events.ScheduleEvent(EVENT_RANDOM_BEAM, 6s); + events.ScheduleEvent(EVENT_BERSERK, 10min); + events.ScheduleEvent(EVENT_TAUNT, 35s); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _DespawnAtEvade(); + } + + void DamageTaken(Unit* /*attacker*/, uint32 &damage) override + { + if (!_enraged && me->HealthBelowPctDamaged(10, damage)) + { + _enraged = true; + DoCastSelf(SPELL_RANDOM_PERIODIC, true); + Talk(EMOTE_ENRAGE, me); + Talk(SAY_ENRAGE); + } + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_RANDOM_BEAM: + DoCastSelf(BeamTriggers[urand(0, 3)]); + events.Repeat(Seconds(30)); + break; + case EVENT_PRISMATIC_SHIELD: + DoCastSelf(PrismaticAuras[urand(0, 5)]); + events.Repeat(Seconds(15)); + break; + case EVENT_FATAL_ATTRACTION: + Talk(SAY_SPELL); + DoCastSelf(SPELL_FATAL_ATTRACTION_TELEPORT, { SPELLVALUE_MAX_TARGETS, 3 }); + events.Repeat(Seconds(30)); + break; + case EVENT_SILENCING_SHRIEK: + DoCastVictim(SPELL_SILENCING_SHRIEK); + events.Repeat(Seconds(18), Seconds(30)); + break; + case EVENT_TAUNT: + Talk(SAY_TAUNT); + events.Repeat(Seconds(30), Seconds(40)); + break; + case EVENT_BERSERK: + Talk(EMOTE_BERSERK, me); + DoCastSelf(SPELL_BERSERK); + break; + default: + break; + } + } + +private: + bool _enraged; }; // 40869 - Fatal Attraction -class spell_mother_shahraz_fatal_attraction : public SpellScriptLoader +class spell_mother_shahraz_fatal_attraction : public SpellScript { - public: - spell_mother_shahraz_fatal_attraction() : SpellScriptLoader("spell_mother_shahraz_fatal_attraction") { } - - class spell_mother_shahraz_fatal_attraction_SpellScript : public SpellScript + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_SABER_LASH_IMMUNITY, SPELL_FATAL_ATTRACTION }); - } + SPELL_SABER_LASH_IMMUNITY, + SPELL_FATAL_ATTRACTION + }); + } - void FilterTargets(std::list& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_SABER_LASH_IMMUNITY)); - } + void FilterTargets(std::list& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_SABER_LASH_IMMUNITY)); + } - void SetDest(SpellDestination& dest) - { - dest.Relocate(TeleportPoint[urand(0, 6)]); - } + void SetDest(SpellDestination& dest) + { + dest.Relocate(GetCaster()->GetRandomNearPosition(50.0f)); + } - void HandleTeleport(SpellEffIndex /*effIndex*/) - { - GetCaster()->CastSpell(GetHitUnit(), SPELL_FATAL_ATTRACTION, true); - } + void HandleTeleport(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_FATAL_ATTRACTION, true); + } - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_mother_shahraz_fatal_attraction_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - OnDestinationTargetSelect.Register(&spell_mother_shahraz_fatal_attraction_SpellScript::SetDest, EFFECT_1, TARGET_DEST_CASTER_RANDOM); - OnEffectHitTarget.Register(&spell_mother_shahraz_fatal_attraction_SpellScript::HandleTeleport, EFFECT_1, SPELL_EFFECT_TELEPORT_UNITS); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mother_shahraz_fatal_attraction_SpellScript(); - } + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_mother_shahraz_fatal_attraction::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + OnDestinationTargetSelect.Register(&spell_mother_shahraz_fatal_attraction::SetDest, EFFECT_1, TARGET_DEST_CASTER_RANDOM); + OnEffectHitTarget.Register(&spell_mother_shahraz_fatal_attraction::HandleTeleport, EFFECT_1, SPELL_EFFECT_TELEPORT_UNITS); + } }; // 40870 - Fatal Attraction Dummy Visual -class spell_mother_shahraz_fatal_attraction_link : public SpellScriptLoader +class spell_mother_shahraz_fatal_attraction_link : public SpellScript { - public: - spell_mother_shahraz_fatal_attraction_link() : SpellScriptLoader("spell_mother_shahraz_fatal_attraction_link") { } + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo({ SPELL_FATAL_ATTRACTION_DAMAGE }); + } - class spell_mother_shahraz_fatal_attraction_link_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_FATAL_ATTRACTION_DAMAGE }); - } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetCaster(), SPELL_FATAL_ATTRACTION_DAMAGE, true); + } - void HandleDummy(SpellEffIndex /*effIndex*/) - { - GetCaster()->CastSpell(GetCaster(), SPELL_FATAL_ATTRACTION_DAMAGE, true); - } - - void Register() override - { - OnEffectHitTarget.Register(&spell_mother_shahraz_fatal_attraction_link_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mother_shahraz_fatal_attraction_link_SpellScript(); - } + void Register() override + { + OnEffectHitTarget.Register(&spell_mother_shahraz_fatal_attraction_link::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; // 40816 - Saber Lash -class spell_mother_shahraz_saber_lash : public SpellScriptLoader +class spell_mother_shahraz_saber_lash : public AuraScript { - public: - spell_mother_shahraz_saber_lash() : SpellScriptLoader("spell_mother_shahraz_saber_lash") { } + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->Effects[EFFECT_1].TriggerSpell }); + } - class spell_mother_shahraz_saber_lash_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* spellInfo) override - { - return ValidateSpellInfo({ spellInfo->Effects[EFFECT_1].TriggerSpell }); - } + void OnTrigger(AuraEffect const* aurEff) + { + PreventDefaultAction(); - void OnTrigger(AuraEffect const* aurEff) - { - PreventDefaultAction(); + uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) + GetUnitOwner()->CastSpell(target, triggerSpell, true); + } - uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) - GetUnitOwner()->CastSpell(target, triggerSpell, true); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_mother_shahraz_saber_lash_AuraScript::OnTrigger, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mother_shahraz_saber_lash_AuraScript(); - } + void Register() override + { + OnEffectPeriodic.Register(&spell_mother_shahraz_saber_lash::OnTrigger, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; /* 40863 - Sinister Periodic 40865 - Vile Periodic 40866 - Wicked Periodic 40862 - Sinful Periodic */ -class spell_mother_shahraz_generic_periodic : public SpellScriptLoader +class spell_mother_shahraz_generic_periodic : public AuraScript { - public: - spell_mother_shahraz_generic_periodic() : SpellScriptLoader("spell_mother_shahraz_generic_periodic") { } + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->Effects[EFFECT_0].TriggerSpell }); + } - class spell_mother_shahraz_generic_periodic_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* spellInfo) override - { - return ValidateSpellInfo({ spellInfo->Effects[EFFECT_0].TriggerSpell }); - } + void OnTrigger(AuraEffect const* aurEff) + { + PreventDefaultAction(); - void OnTrigger(AuraEffect const* aurEff) - { - PreventDefaultAction(); + uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) + GetUnitOwner()->CastSpell(target, triggerSpell, true); + } - uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0)) - GetUnitOwner()->CastSpell(target, triggerSpell, true); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_mother_shahraz_generic_periodic_AuraScript::OnTrigger, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mother_shahraz_generic_periodic_AuraScript(); - } + void Register() override + { + OnEffectPeriodic.Register(&spell_mother_shahraz_generic_periodic::OnTrigger, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; // 40867 - Random Periodic -class spell_mother_shahraz_random_periodic : public SpellScriptLoader +class spell_mother_shahraz_random_periodic : public AuraScript { - public: - spell_mother_shahraz_random_periodic() : SpellScriptLoader("spell_mother_shahraz_random_periodic") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo(RandomBeam); + } - class spell_mother_shahraz_random_periodic_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo(RandomBeam); - } + void OnPeriodic(AuraEffect const* /*aurEffect*/) + { + PreventDefaultAction(); + GetUnitOwner()->CastSpell(GetUnitOwner(), RandomBeam[urand(0, 3)], true); + } - void OnPeriodic(AuraEffect const* /*aurEffect*/) - { - PreventDefaultAction(); - GetUnitOwner()->CastSpell(GetUnitOwner(), RandomBeam[urand(0, 3)], true); - } - - void Register() override - { - OnEffectPeriodic.Register(&spell_mother_shahraz_random_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mother_shahraz_random_periodic_AuraScript(); - } + void Register() override + { + OnEffectPeriodic.Register(&spell_mother_shahraz_random_periodic::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; void AddSC_boss_mother_shahraz() { - new boss_mother_shahraz(); - new spell_mother_shahraz_fatal_attraction(); - new spell_mother_shahraz_fatal_attraction_link(); - new spell_mother_shahraz_saber_lash(); - new spell_mother_shahraz_generic_periodic(); - new spell_mother_shahraz_random_periodic(); + RegisterBlackTempleCreatureAI(boss_mother_shahraz); + RegisterSpellScript(spell_mother_shahraz_fatal_attraction); + RegisterSpellScript(spell_mother_shahraz_fatal_attraction_link); + RegisterSpellScript(spell_mother_shahraz_saber_lash); + RegisterSpellScript(spell_mother_shahraz_generic_periodic); + RegisterSpellScript(spell_mother_shahraz_random_periodic); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp index 5712c06971..91a2f02902 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp @@ -21,6 +21,7 @@ #include "MotionMaster.h" #include "Player.h" #include "ScriptedCreature.h" +#include "Spell.h" #include "SpellAuraEffects.h" #include "SpellScript.h" @@ -92,6 +93,7 @@ enum Misc ACTION_ESSENCE_OF_SUFFERING_DEAD, ACTION_ESSENCE_OF_DESIRE_DEAD, ACTION_KILL_SELF, + ACTION_START_COMBAT, ANGER_SOUND_ID_DEATH = 11401 }; @@ -135,729 +137,678 @@ class EnslavedSoulEvent : public BasicEvent Creature* _owner; }; -class boss_reliquary_of_souls : public CreatureScript +struct boss_reliquary_of_souls : public BossAI { -public: - boss_reliquary_of_souls() : CreatureScript("boss_reliquary_of_souls") { } + boss_reliquary_of_souls(Creature* creature) : BossAI(creature, DATA_RELIQUARY_OF_SOULS), _inCombat(false) { } - struct boss_reliquary_of_soulsAI : public BossAI + void Reset() override { - boss_reliquary_of_soulsAI(Creature* creature) : BossAI(creature, DATA_RELIQUARY_OF_SOULS), _inCombat(false) - { - creature->m_SightDistance = 70.0f; - } - - void Reset() override - { - _Reset(); - me->SetReactState(REACT_PASSIVE); - _inCombat = false; - events.SetPhase(PHASE_ESSENCE_OF_SUFFERING); - } - - void MoveInLineOfSight(Unit* who) override - { - if (!_inCombat && who->GetTypeId() == TYPEID_PLAYER && !who->ToPlayer()->IsGameMaster() && CanAIAttack(who)) - { - _inCombat = true; - DoZoneInCombat(); - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); - events.ScheduleEvent(EVENT_SUBMERGE, Seconds(10)); - } - } - - uint32 GetSummonSpell() - { - if (events.IsInPhase(PHASE_ESSENCE_OF_SUFFERING)) - return SPELL_SUMMON_ESSENCE_OF_SUFFERING; - else if (events.IsInPhase(PHASE_ESSENCE_OF_DESIRE)) - return SPELL_SUMMON_ESSENCE_OF_DESIRE; - else if (events.IsInPhase(PHASE_ESSENCE_OF_ANGER)) - return SPELL_SUMMON_ESSENCE_OF_ANGER; - else //Should never happen - return 0; - } - - void DoAction(int32 actionId) override - { - switch (actionId) - { - case ACTION_ESSENCE_OF_SUFFERING_DEAD: - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); - events.SetPhase(PHASE_ESSENCE_OF_DESIRE); - HandleSpirits(); - events.ScheduleEvent(EVENT_SUBMERGE, Seconds(40)); - break; - case ACTION_ESSENCE_OF_DESIRE_DEAD: - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); - events.SetPhase(PHASE_ESSENCE_OF_ANGER); - HandleSpirits(); - events.ScheduleEvent(EVENT_SUBMERGE, Seconds(40)); - break; - case ACTION_KILL_SELF: - me->KillSelf(); - break; - } - } - - void HandleSpirits() - { - std::vector _worldTriggerList; - me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); - - if (_worldTriggerList.empty()) - return; - - //Get random creatures - Trinity::Containers::RandomShuffle(_worldTriggerList); - _worldTriggerList.resize(21); - - for (uint8 i = 0; i < 21; i++) - { - Creature* wTrigger = _worldTriggerList[i]; - if (i < 3) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(4000)); - else if (i < 6) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(8000)); - else if (i < 9) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(12000)); - else if (i < 12) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(16000)); - else if (i < 15) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(20000)); - else if (i < 18) - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(24000)); - else - wTrigger->m_Events.AddEvent(new EnslavedSoulEvent(wTrigger), wTrigger->m_Events.CalculateTime(28000)); - } - } - - void KillAssyncEvents() - { - std::vector _worldTriggerList; - me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); - - if (_worldTriggerList.empty()) - return; - - for (Creature* trigger : _worldTriggerList) - trigger->m_Events.KillAllEvents(true); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - events.Reset(); - summons.DespawnAll(); - KillAssyncEvents(); - _DespawnAtEvade(); - } - - void JustDied(Unit* /*killer*/) override - { - events.Reset(); - instance->SetBossState(DATA_RELIQUARY_OF_SOULS, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SUBMERGE: - DoCastSelf(SPELL_SUBMERGE_VISUAL, true); - events.ScheduleEvent(EVENT_SUMMON_ESSENCE, Seconds(3)); - break; - case EVENT_SUMMON_ESSENCE: - { - EntryCheckPredicate pred(NPC_ENSLAVED_SOUL); - summons.DoAction(ACTION_KILL_SELF, pred); - DoCastSelf(GetSummonSpell()); - break; - } - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - } - - private: - bool _inCombat; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _Reset(); + me->SetReactState(REACT_PASSIVE); + _inCombat = false; + events.SetPhase(PHASE_ESSENCE_OF_SUFFERING); } -}; -class boss_essence_of_suffering : public CreatureScript -{ -public: - boss_essence_of_suffering() : CreatureScript("boss_essence_of_suffering") { } - - struct boss_essence_of_sufferingAI : public BossAI + void JustSummoned(Creature* summon) override { - boss_essence_of_sufferingAI(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_SUFFERING), _dead(false) - { - SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); - } - - void Reset() override - { - DoCastAOE(SPELL_AURA_OF_SUFFERING, true); - events.Reset(); - _dead = false; - } - - void MovementInform(uint32 motionType, uint32 pointId) override - { - if (motionType != POINT_MOTION_TYPE) - return; - - if (pointId == RELIQUARY_DESPAWN_WAYPOINT) - { - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->DoAction(ACTION_ESSENCE_OF_SUFFERING_DEAD); - - DoCastSelf(SPELL_SUBMERGE_VISUAL, true); - me->DespawnOrUnsummon(Seconds(2)); - } - } - - void DamageTaken(Unit* /*done_by*/, uint32 &damage) override - { - if (damage >= me->GetHealth()) - { - damage = 0; - if (!_dead) - { - _dead = true; - Talk(SUFF_SAY_RECAP); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - events.Reset(); - me->InterruptNonMeleeSpells(false); - me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); - } - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SetCombatPulseDelay(5); - me->setActive(true); - DoZoneInCombat(); - - events.ScheduleEvent(EVENT_SOUL_DRAIN, Seconds(20)); - events.ScheduleEvent(EVENT_FRENZY, Seconds(45)); - Talk(SUFF_SAY_AGRO); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SUFF_SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SOUL_DRAIN: - DoCastSelf(SPELL_SOUL_DRAIN, { SPELLVALUE_MAX_TARGETS, 5 }); - events.Repeat(Seconds(30), Seconds(35)); - break; - case EVENT_FRENZY: - Talk(SUFF_SAY_ENRAGE); - DoCastSelf(SPELL_FRENZY); - events.Repeat(Seconds(45), Seconds(50)); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); - } - private: - bool _dead; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + summons.Summon(summon); + summon->AI()->DoZoneInCombat(); } -}; -class boss_essence_of_desire : public CreatureScript -{ -public: - boss_essence_of_desire() : CreatureScript("boss_essence_of_desire") { } - - struct boss_essence_of_desireAI : public BossAI + uint32 GetSummonSpell() { - boss_essence_of_desireAI(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_DESIRE), _dead(false) - { - SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); - } - - void Reset() override - { - DoCastSelf(SPELL_AURA_OF_DESIRE, true); - events.Reset(); - _dead = false; - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_SPIRIT_SHOCK, Seconds(11)); - events.ScheduleEvent(EVENT_RUNE_SHIELD, Seconds(16)); - events.ScheduleEvent(EVENT_DEADEN, Seconds(31)); - - me->SetCombatPulseDelay(5); - me->setActive(true); - DoZoneInCombat(); - Talk(DESI_SAY_FREED); - } - - void MovementInform(uint32 motionType, uint32 pointId) override - { - if (motionType != POINT_MOTION_TYPE) - return; - - if (pointId == RELIQUARY_DESPAWN_WAYPOINT) - { - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->DoAction(ACTION_ESSENCE_OF_DESIRE_DEAD); - - DoCastSelf(SPELL_SUBMERGE_VISUAL, true); - me->DespawnOrUnsummon(Seconds(2)); - } - } - - void DamageTaken(Unit* /*done_by*/, uint32 &damage) override - { - if (damage >= me->GetHealth()) - { - damage = 0; - if (!_dead) - { - _dead = true; - Talk(DESI_SAY_RECAP); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - events.Reset(); - me->InterruptNonMeleeSpells(false); - me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); - } - } - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(DESI_SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SPIRIT_SHOCK: - DoCastVictim(SPELL_SPIRIT_SHOCK); - events.Repeat(Seconds(10), Seconds(15)); - break; - case EVENT_RUNE_SHIELD: - DoCastSelf(SPELL_RUNE_SHIELD); - events.Repeat(Seconds(16)); - break; - case EVENT_DEADEN: - Talk(DESI_SAY_SPEC); - DoCastVictim(SPELL_DEADEN); - events.Repeat(Seconds(31)); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); - } - private: - bool _dead; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + if (events.IsInPhase(PHASE_ESSENCE_OF_SUFFERING)) + return SPELL_SUMMON_ESSENCE_OF_SUFFERING; + else if (events.IsInPhase(PHASE_ESSENCE_OF_DESIRE)) + return SPELL_SUMMON_ESSENCE_OF_DESIRE; + else if (events.IsInPhase(PHASE_ESSENCE_OF_ANGER)) + return SPELL_SUMMON_ESSENCE_OF_ANGER; + else //Should never happen + return 0; } -}; -class boss_essence_of_anger : public CreatureScript -{ -public: - boss_essence_of_anger() : CreatureScript("boss_essence_of_anger") { } - - struct boss_essence_of_angerAI : public BossAI + void DoAction(int32 actionId) override { - boss_essence_of_angerAI(Creature* creature) :BossAI(creature, DATA_ESSENCE_OF_ANGER) + switch (actionId) { - SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); - } - - void Reset() override - { - events.Reset(); - _targetGUID.Clear(); - DoCastSelf(SPELL_AURA_OF_ANGER); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(ANGER_SAY_FREED); - - events.ScheduleEvent(EVENT_START_CHECK_TANKER, Seconds(5)); - events.ScheduleEvent(EVENT_SOUL_SCREAM, Seconds(11)); - events.ScheduleEvent(EVENT_SPITE, Seconds(20)); - events.ScheduleEvent(EVENT_FREED_2, Seconds(1), Minutes(3)); - - me->SetCombatPulseDelay(5); - me->setActive(true); - DoZoneInCombat(); - } - - void JustDied(Unit* /*killer*/) override - { - DoPlaySoundToSet(me, ANGER_SOUND_ID_DEATH); - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->DoAction(ACTION_KILL_SELF); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_CHECK_TANKER: - { - Unit* target = me->GetVictim(); - if (!_targetGUID || !target) - return; - - if (target->GetGUID() != _targetGUID) - { - Talk(ANGER_SAY_SEETHE); - Talk(ANGER_EMOTE_SEETHE, me); - _targetGUID = target->GetGUID(); - DoCastSelf(SPELL_SEETHE, true); - } - break; - } - case EVENT_SOUL_SCREAM: - DoCastSelf(SPELL_SOUL_SCREAM); - events.Repeat(Seconds(11)); - break; - case EVENT_SPITE: - Talk(ANGER_SAY_SPITE); - DoCastSelf(SPELL_SPITE, { SPELLVALUE_MAX_TARGETS, 3 }); - events.Repeat(Seconds(20)); - break; - case EVENT_START_CHECK_TANKER: - if (Unit* target = me->GetVictim()) - { - _targetGUID = target->GetGUID(); - events.ScheduleEvent(EVENT_CHECK_TANKER, Seconds(1)); - } - else - events.Repeat(Seconds(1)); - break; - case EVENT_FREED_2: - Talk(ANGER_SAY_FREED_2); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->EnterEvadeMode(EVADE_REASON_OTHER); - } - - private: - ObjectGuid _targetGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); - } -}; - -class npc_enslaved_soul : public CreatureScript -{ -public: - npc_enslaved_soul() : CreatureScript("npc_enslaved_soul") { } - - struct npc_enslaved_soulAI : public ScriptedAI - { - npc_enslaved_soulAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - - void Reset() override - { - me->SetReactState(REACT_PASSIVE); - if (Creature* reliquary = _instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) - reliquary->AI()->JustSummoned(me); - - DoCastSelf(SPELL_ENSLAVED_SOUL_PASSIVE, true); - - _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) - { - me->SetReactState(REACT_AGGRESSIVE); - me->SetInCombatWithZone(); - }); - } - - void DoAction(int32 actionId) override - { - if (actionId == ACTION_KILL_SELF) + case ACTION_ESSENCE_OF_SUFFERING_DEAD: + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); + events.SetPhase(PHASE_ESSENCE_OF_DESIRE); + HandleSpirits(); + events.ScheduleEvent(EVENT_SUBMERGE, 40s); + break; + case ACTION_ESSENCE_OF_DESIRE_DEAD: + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); + events.SetPhase(PHASE_ESSENCE_OF_ANGER); + HandleSpirits(); + events.ScheduleEvent(EVENT_SUBMERGE, 40s); + break; + case ACTION_KILL_SELF: me->KillSelf(); + if (Creature* combatTrigger = instance->GetCreature(DATA_RELIQUARY_COMBAT_TRIGGER)) + combatTrigger->AI()->DoAction(ACTION_KILL_SELF); + break; + case ACTION_START_COMBAT: + _inCombat = true; + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); + events.ScheduleEvent(EVENT_SUBMERGE, 10s); + break; + default: + break; } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _scheduler.Update(diff); - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - DoCastSelf(SPELL_SOUL_RELEASE, true); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); } + + void HandleSpirits() + { + std::vector _worldTriggerList; + me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); + + if (_worldTriggerList.empty()) + return; + + //Get random creatures + Trinity::Containers::RandomShuffle(_worldTriggerList); + _worldTriggerList.resize(21); + + for (uint8 i = 0; i < 21; i++) + { + Creature* wTrigger = _worldTriggerList[i]; + if (i < 3) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 4s); + else if (i < 6) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 8s); + else if (i < 9) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 12s); + else if (i < 12) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 16s); + else if (i < 15) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 20s); + else if (i < 18) + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 24s); + else + wTrigger->m_Events.AddEventAtOffset(new EnslavedSoulEvent(wTrigger), 28s); + } + } + + void KillAssyncEvents() + { + std::vector _worldTriggerList; + me->GetCreatureListWithEntryInGrid(_worldTriggerList, NPC_RELIQUARY_WORLD_TRIGGER, 70.0f); + + if (_worldTriggerList.empty()) + return; + + for (Creature* trigger : _worldTriggerList) + trigger->m_Events.KillAllEvents(true); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + events.Reset(); + summons.DespawnAll(); + KillAssyncEvents(); + _DespawnAtEvade(); + } + + void JustDied(Unit* /*killer*/) override + { + events.Reset(); + instance->SetBossState(DATA_RELIQUARY_OF_SOULS, DONE); + } + + void UpdateAI(uint32 diff) override + { + if (!_inCombat) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + if (eventId == EVENT_SUBMERGE) + { + DoCastSelf(SPELL_SUBMERGE_VISUAL, true); + EntryCheckPredicate pred(NPC_ENSLAVED_SOUL); + summons.DoAction(ACTION_KILL_SELF, pred); + DoCastSelf(GetSummonSpell()); + } + } + } + +private: + bool _inCombat; +}; + +struct boss_essence_of_suffering : public BossAI +{ + boss_essence_of_suffering(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_SUFFERING), _dead(false) + { + SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); + } + + void Reset() override + { + DoCastAOE(SPELL_AURA_OF_SUFFERING, true); + events.Reset(); + _dead = false; + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (pointId == RELIQUARY_DESPAWN_WAYPOINT) + { + if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + reliquary->AI()->DoAction(ACTION_ESSENCE_OF_SUFFERING_DEAD); + + DoCastSelf(SPELL_SUBMERGE_VISUAL, true); + me->DespawnOrUnsummon(Seconds(2)); + } + } + + void DamageTaken(Unit* /*done_by*/, uint32 &damage) override + { + if (damage >= me->GetHealth()) + { + damage = 0; + if (!_dead) + { + _dead = true; + Talk(SUFF_SAY_RECAP); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + events.Reset(); + me->InterruptNonMeleeSpells(false); + me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); + } + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->SetCombatPulseDelay(5); + me->setActive(true); + + events.ScheduleEvent(EVENT_SOUL_DRAIN, 20s); + events.ScheduleEvent(EVENT_FRENZY, 45s); + Talk(SUFF_SAY_AGRO); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SUFF_SAY_SLAY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SOUL_DRAIN: + DoCastSelf(SPELL_SOUL_DRAIN, { SPELLVALUE_MAX_TARGETS, 5 }); + events.Repeat(Seconds(30), Seconds(35)); + break; + case EVENT_FRENZY: + Talk(SUFF_SAY_ENRAGE); + DoCastSelf(SPELL_FRENZY); + events.Repeat(Seconds(45), Seconds(50)); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } +private: + bool _dead; +}; + +struct boss_essence_of_desire : public BossAI +{ + boss_essence_of_desire(Creature* creature) : BossAI(creature, DATA_ESSENCE_OF_DESIRE), _dead(false) + { + SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); + } + + void Reset() override + { + DoCastSelf(SPELL_AURA_OF_DESIRE, true); + events.Reset(); + _dead = false; + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_SPIRIT_SHOCK, 11s); + events.ScheduleEvent(EVENT_RUNE_SHIELD, 16s); + events.ScheduleEvent(EVENT_DEADEN, 31s); + + me->SetCombatPulseDelay(5); + me->setActive(true); + Talk(DESI_SAY_FREED); + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (pointId == RELIQUARY_DESPAWN_WAYPOINT) + { + if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + reliquary->AI()->DoAction(ACTION_ESSENCE_OF_DESIRE_DEAD); + + DoCastSelf(SPELL_SUBMERGE_VISUAL, true); + me->DespawnOrUnsummon(Seconds(2)); + } + } + + void DamageTaken(Unit* /*done_by*/, uint32 &damage) override + { + if (damage >= me->GetHealth()) + { + damage = 0; + if (!_dead) + { + _dead = true; + Talk(DESI_SAY_RECAP); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + events.Reset(); + me->InterruptNonMeleeSpells(false); + me->GetMotionMaster()->MovePoint(RELIQUARY_DESPAWN_WAYPOINT, DespawnPoint); + } + } + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(DESI_SAY_SLAY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SPIRIT_SHOCK: + DoCastVictim(SPELL_SPIRIT_SHOCK); + events.Repeat(Seconds(10), Seconds(15)); + break; + case EVENT_RUNE_SHIELD: + DoCastSelf(SPELL_RUNE_SHIELD); + events.Repeat(Seconds(16)); + break; + case EVENT_DEADEN: + Talk(DESI_SAY_SPEC); + DoCastVictim(SPELL_DEADEN); + events.Repeat(Seconds(31)); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } +private: + bool _dead; +}; + +struct boss_essence_of_anger : public BossAI +{ + boss_essence_of_anger(Creature* creature) :BossAI(creature, DATA_ESSENCE_OF_ANGER) + { + SetBoundary(instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); + } + + void Reset() override + { + events.Reset(); + _targetGUID.Clear(); + DoCastSelf(SPELL_AURA_OF_ANGER); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(ANGER_SAY_FREED); + + events.ScheduleEvent(EVENT_START_CHECK_TANKER, 5s); + events.ScheduleEvent(EVENT_SOUL_SCREAM, 11s); + events.ScheduleEvent(EVENT_SPITE, 20s); + events.ScheduleEvent(EVENT_FREED_2, Seconds(1), Minutes(3)); + + me->SetCombatPulseDelay(5); + me->setActive(true); + } + + void JustDied(Unit* /*killer*/) override + { + DoPlaySoundToSet(me, ANGER_SOUND_ID_DEATH); + if (Creature* reliquary = instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + reliquary->AI()->DoAction(ACTION_KILL_SELF); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHECK_TANKER: + { + Unit* target = me->GetVictim(); + if (!_targetGUID || !target) + return; + + if (target->GetGUID() != _targetGUID) + { + Talk(ANGER_SAY_SEETHE); + Talk(ANGER_EMOTE_SEETHE, me); + _targetGUID = target->GetGUID(); + DoCastSelf(SPELL_SEETHE, true); + } + break; + } + case EVENT_SOUL_SCREAM: + DoCastSelf(SPELL_SOUL_SCREAM); + events.Repeat(Seconds(11)); + break; + case EVENT_SPITE: + Talk(ANGER_SAY_SPITE); + DoCastSelf(SPELL_SPITE, { SPELLVALUE_MAX_TARGETS, 3 }); + events.Repeat(Seconds(20)); + break; + case EVENT_START_CHECK_TANKER: + if (Unit* target = me->GetVictim()) + { + _targetGUID = target->GetGUID(); + events.ScheduleEvent(EVENT_CHECK_TANKER, 1s); + } + else + events.Repeat(Seconds(1)); + break; + case EVENT_FREED_2: + Talk(ANGER_SAY_FREED_2); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + } + +private: + ObjectGuid _targetGUID; +}; + +struct npc_enslaved_soul : public ScriptedAI +{ + npc_enslaved_soul(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _dead(false) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + if (Creature* reliquary = _instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + reliquary->AI()->JustSummoned(me); + + DoCastSelf(SPELL_ENSLAVED_SOUL_PASSIVE, true); + + _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) + { + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + }); + _dead = false; + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_KILL_SELF) + HandleSoulRelease(); + } + + void HandleSoulRelease() + { + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->GetMotionMaster()->Clear(); + DoCastSelf(SPELL_SOUL_RELEASE); + me->m_Events.AddEventAtOffset([this]() { me->KillSelf(); }, 500ms); + } + + void DamageTaken(Unit* /*done_by*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + { + damage = 0; + if (!_dead) + { + _dead = true; + HandleSoulRelease(); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; + bool _dead; +}; + +struct npc_reliquary_combat_trigger : public ScriptedAI +{ + npc_reliquary_combat_trigger(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + creature->m_SightDistance = 70.0f; + SetBoundary(_instance->GetBossBoundary(DATA_RELIQUARY_OF_SOULS)); + } + + bool CanAIAttack(Unit const* who) const override + { + return ScriptedAI::CanAIAttack(who) && CheckBoundary(who); + } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + if (_instance->GetBossState(DATA_RELIQUARY_OF_SOULS) == DONE) + me->DespawnOrUnsummon(); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!me->IsEngaged() && who->GetTypeId() == TYPEID_PLAYER && !who->ToPlayer()->IsGameMaster() && CheckBoundary(who)) + { + if (Creature* reliquary = _instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + { + DoZoneInCombat(); + reliquary->AI()->DoAction(ACTION_START_COMBAT); + } + } + } + + void DamageTaken(Unit* /*done_by*/, uint32& damage) override + { + damage = 0; + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (Creature* reliquary = _instance->GetCreature(DATA_RELIQUARY_OF_SOULS)) + reliquary->AI()->EnterEvadeMode(why); + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_KILL_SELF) + me->KillSelf(); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; + } + +private: + InstanceScript* _instance; }; // 41350 - Aura of Desire -class spell_reliquary_of_souls_aura_of_desire : public SpellScriptLoader +class spell_reliquary_of_souls_aura_of_desire : public AuraScript { - public: - spell_reliquary_of_souls_aura_of_desire() : SpellScriptLoader("spell_reliquary_of_souls_aura_of_desire") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_AURA_OF_DESIRE_DAMAGE }); + } - class spell_reliquary_of_souls_aura_of_desire_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_AURA_OF_DESIRE_DAMAGE }); - } + void OnProcSpell(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; - void OnProcSpell(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, SPELL_AURA_OF_DESIRE_DAMAGE, CastSpellExtraArgs(aurEff).AddSpellBP0(damageInfo->GetDamage() / 2)); + } - Unit* caster = eventInfo.GetActor(); - int32 bp = damageInfo->GetDamage() / 2; - caster->CastSpell(caster, SPELL_AURA_OF_DESIRE_DAMAGE, CastSpellExtraArgs(aurEff).AddSpellBP0(bp)); - } + void UpdateAmount(AuraEffect* /*aurEff*/) + { + if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) + effect->ChangeAmount(effect->GetAmount() - 5); + } - void UpdateAmount(AuraEffect* /*aurEff*/) - { - if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) - effect->ChangeAmount(effect->GetAmount() - 5); - } - - void Register() override - { - OnEffectProc.Register(&spell_reliquary_of_souls_aura_of_desire_AuraScript::OnProcSpell, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); - OnEffectUpdatePeriodic.Register(&spell_reliquary_of_souls_aura_of_desire_AuraScript::UpdateAmount, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_reliquary_of_souls_aura_of_desire_AuraScript(); - } + void Register() override + { + OnEffectProc.Register(&spell_reliquary_of_souls_aura_of_desire::OnProcSpell, EFFECT_0, SPELL_AURA_MOD_HEALING_PCT); + OnEffectUpdatePeriodic.Register(&spell_reliquary_of_souls_aura_of_desire::UpdateAmount, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } }; // 28819 - Submerge Visual -class spell_reliquary_of_souls_submerge : public SpellScriptLoader +class spell_reliquary_of_souls_submerge : public AuraScript { - public: - spell_reliquary_of_souls_submerge() : SpellScriptLoader("spell_reliquary_of_souls_submerge") { } + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); + } - class spell_reliquary_of_souls_submerge_AuraScript : public AuraScript - { - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); - } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); + } - void Register() override - { - AfterEffectApply.Register(&spell_reliquary_of_souls_submerge_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove.Register(&spell_reliquary_of_souls_submerge_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_reliquary_of_souls_submerge_AuraScript(); - } + void Register() override + { + AfterEffectApply.Register(&spell_reliquary_of_souls_submerge::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove.Register(&spell_reliquary_of_souls_submerge::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } }; // 41376 - Spite -class spell_reliquary_of_souls_spite : public SpellScriptLoader +class spell_reliquary_of_souls_spite : public AuraScript { - public: - spell_reliquary_of_souls_spite() : SpellScriptLoader("spell_reliquary_of_souls_spite") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SPITE_DAMAGE }); + } - class spell_reliquary_of_souls_spite_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SPITE_DAMAGE }); - } + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetTarget(), SPELL_SPITE_DAMAGE, true); + } - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - caster->CastSpell(GetTarget(), SPELL_SPITE_DAMAGE, true); - } - - void Register() override - { - AfterEffectRemove.Register(&spell_reliquary_of_souls_spite_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DAMAGE_IMMUNITY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_reliquary_of_souls_spite_AuraScript(); - } + void Register() override + { + AfterEffectRemove.Register(&spell_reliquary_of_souls_spite::OnRemove, EFFECT_0, SPELL_AURA_DAMAGE_IMMUNITY, AURA_EFFECT_HANDLE_REAL); + } }; // 41305 - Frenzy -class spell_reliquary_of_souls_frenzy : public SpellScriptLoader +class spell_reliquary_of_souls_frenzy : public SpellScript { - public: - spell_reliquary_of_souls_frenzy() : SpellScriptLoader("spell_reliquary_of_souls_frenzy") { } + void HandleAfterCast() + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->Talk(SUFF_EMOTE_ENRAGE, caster); + } - class spell_reliquary_of_souls_frenzy_SpellScript : public SpellScript - { - void HandleAfterCast() - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->Talk(SUFF_EMOTE_ENRAGE, caster); - } - - void Register() override - { - AfterCast.Register(&spell_reliquary_of_souls_frenzy_SpellScript::HandleAfterCast); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_reliquary_of_souls_frenzy_SpellScript(); - } + void Register() override + { + AfterCast.Register(&spell_reliquary_of_souls_frenzy::HandleAfterCast); + } }; void AddSC_boss_reliquary_of_souls() { - new boss_reliquary_of_souls(); - new boss_essence_of_suffering(); - new boss_essence_of_desire(); - new boss_essence_of_anger(); - new npc_enslaved_soul(); - new spell_reliquary_of_souls_aura_of_desire(); - new spell_reliquary_of_souls_submerge(); - new spell_reliquary_of_souls_spite(); - new spell_reliquary_of_souls_frenzy(); + RegisterBlackTempleCreatureAI(boss_reliquary_of_souls); + RegisterBlackTempleCreatureAI(boss_essence_of_suffering); + RegisterBlackTempleCreatureAI(boss_essence_of_desire); + RegisterBlackTempleCreatureAI(boss_essence_of_anger); + RegisterBlackTempleCreatureAI(npc_enslaved_soul); + RegisterBlackTempleCreatureAI(npc_reliquary_combat_trigger); + RegisterSpellScript(spell_reliquary_of_souls_aura_of_desire); + RegisterSpellScript(spell_reliquary_of_souls_submerge); + RegisterSpellScript(spell_reliquary_of_souls_spite); + RegisterSpellScript(spell_reliquary_of_souls_frenzy); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index e2331c1656..3ae58f2583 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -17,12 +17,12 @@ #include "ScriptMgr.h" #include "black_temple.h" +#include "GridNotifiers.h" #include "InstanceScript.h" #include "Map.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "PassiveAI.h" -#include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellAuraEffects.h" @@ -32,14 +32,14 @@ enum Says { // Akama - SAY_BROKEN_FREE_0 = 0, - SAY_BROKEN_FREE_1 = 1, - SAY_BROKEN_FREE_2 = 2, - SAY_LOW_HEALTH = 3, - SAY_DEAD = 4, + SAY_BROKEN_FREE_0 = 0, + SAY_BROKEN_FREE_1 = 1, + SAY_BROKEN_FREE_2 = 2, + SAY_LOW_HEALTH = 3, + SAY_DEAD = 4, // Ashtongue Broken - SAY_BROKEN_SPECIAL = 0, - SAY_BROKEN_HAIL = 1 + SAY_BROKEN_SPECIAL = 0, + SAY_BROKEN_HAIL = 1 }; enum Spells @@ -81,20 +81,20 @@ enum Spells enum Creatures { - NPC_ASHTONGUE_CHANNELER = 23421, - NPC_ASHTONGUE_BROKEN = 23319, - NPC_CREATURE_SPAWNER_AKAMA = 23210 + NPC_ASHTONGUE_CHANNELER = 23421, + NPC_ASHTONGUE_BROKEN = 23319, + NPC_CREATURE_SPAWNER_AKAMA = 23210 }; enum Actions { - ACTION_START_SPAWNING = 0, - ACTION_STOP_SPAWNING = 1, - ACTION_DESPAWN_ALL_SPAWNS = 2, - ACTION_SHADE_OF_AKAMA_DEAD = 3, - ACTION_BROKEN_SPECIAL = 4, - ACTION_BROKEN_EMOTE = 5, - ACTION_BROKEN_HAIL = 6 + ACTION_START_SPAWNING = 0, + ACTION_STOP_SPAWNING = 1, + ACTION_DESPAWN_ALL_SPAWNS = 2, + ACTION_SHADE_OF_AKAMA_DEAD = 3, + ACTION_BROKEN_SPECIAL = 4, + ACTION_BROKEN_EMOTE = 5, + ACTION_BROKEN_HAIL = 6 }; enum Events @@ -139,10 +139,9 @@ enum Events enum Misc { - AKAMA_CHANNEL_WAYPOINT = 0, - AKAMA_INTRO_WAYPOINT = 1, - - SUMMON_GROUP_RESET = 1 + AKAMA_CHANNEL_WAYPOINT = 0, + AKAMA_INTRO_WAYPOINT = 1, + SUMMON_GROUP_RESET = 1 }; Position const AkamaWP[2] = @@ -199,1069 +198,937 @@ static float const MIDDLE_OF_ROOM = 400.0f; static float const FACE_THE_DOOR = 0.08726646f; static float const FACE_THE_PLATFORM = 3.118662f; -class boss_shade_of_akama : public CreatureScript + +struct boss_shade_of_akama : public BossAI { -public: - boss_shade_of_akama() : CreatureScript("boss_shade_of_akama") { } - - struct boss_shade_of_akamaAI : public BossAI + boss_shade_of_akama(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA) { - boss_shade_of_akamaAI(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA) - { - Initialize(); - } - - void Initialize() - { - _spawners.clear(); - _isInPhaseOne = true; - } - - void Reset() override - { - _Reset(); - Initialize(); - me->SetImmuneToPC(true); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN); - me->SetWalk(true); - events.ScheduleEvent(EVENT_INITIALIZE_SPAWNERS, Seconds(1)); - me->SummonCreatureGroup(SUMMON_GROUP_RESET); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - events.Reset(); - summons.DespawnAll(); - - for (ObjectGuid spawnerGuid : _spawners) - if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) - spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS); - - _DespawnAtEvade(); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_AKAMA_SOUL_CHANNEL) - { - events.ScheduleEvent(EVENT_START_CHANNELERS_AND_SPAWNERS, Seconds(1)); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - events.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10)); - if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } - - if (spell->Id == SPELL_AKAMA_SOUL_RETRIEVE) - DoCastSelf(SPELL_AKAMA_SOUL_EXPEL_CHANNEL); - } - - void MovementInform(uint32 motionType, uint32 /*pointId*/) override - { - if (_isInPhaseOne && motionType == CHASE_MOTION_TYPE) - { - _isInPhaseOne = false; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(false); - me->SetWalk(false); - events.ScheduleEvent(EVENT_ADD_THREAT, Milliseconds(100)); - - for (ObjectGuid spawnerGuid : _spawners) - if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) - spawner->AI()->DoAction(ACTION_STOP_SPAWNING); - } - } - - void JustDied(Unit* /*killer*/) override - { - DoCastSelf(SPELL_SHADE_OF_AKAMA_TRIGGER); - - if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) - akama->AI()->DoAction(ACTION_SHADE_OF_AKAMA_DEAD); - - for (ObjectGuid spawnerGuid : _spawners) - if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) - spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS); - - events.Reset(); - summons.DespawnEntry(NPC_ASHTONGUE_CHANNELER); - instance->SetBossState(DATA_SHADE_OF_AKAMA, DONE); - } - - void EnterEvadeModeIfNeeded() - { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) - if (player->IsAlive() && !player->IsGameMaster() && CheckBoundary(player)) - return; - - EnterEvadeMode(EVADE_REASON_NO_HOSTILES); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if (!UpdateVictim()) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_INITIALIZE_SPAWNERS: - { - std::list SpawnerList; - me->GetCreatureListWithEntryInGrid(SpawnerList, NPC_CREATURE_SPAWNER_AKAMA); - for (Creature* spawner : SpawnerList) - _spawners.push_back(spawner->GetGUID()); - - break; - } - case EVENT_START_CHANNELERS_AND_SPAWNERS: - { - for (ObjectGuid summonGuid : summons) - if (Creature* channeler = ObjectAccessor::GetCreature(*me, summonGuid)) - channeler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - for (ObjectGuid spawnerGuid : _spawners) - if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) - spawner->AI()->DoAction(ACTION_START_SPAWNING); - - break; - } - case EVENT_ADD_THREAT: - DoCast(SPELL_THREAT); - events.Repeat(Seconds(3) + Milliseconds(500)); - break; - case EVENT_EVADE_CHECK: - EnterEvadeModeIfNeeded(); - events.Repeat(Seconds(10)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - GuidVector _spawners; - bool _isInPhaseOne; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + Initialize(); } -}; -class npc_akama_shade : public CreatureScript -{ -public: - npc_akama_shade() : CreatureScript("npc_akama_shade") { } - - struct npc_akamaAI : public ScriptedAI + void Initialize() { - npc_akamaAI(Creature* creature) : ScriptedAI(creature), _summons(me) + _spawners.clear(); + _isInPhaseOne = true; + } + + void Reset() override + { + _Reset(); + Initialize(); + me->SetImmuneToPC(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN); + me->SetWalk(true); + events.ScheduleEvent(EVENT_INITIALIZE_SPAWNERS, 1s); + me->SummonCreatureGroup(SUMMON_GROUP_RESET); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + events.Reset(); + summons.DespawnAll(); + + for (ObjectGuid const spawnerGuid : _spawners) + if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) + spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS); + + _DespawnAtEvade(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_AKAMA_SOUL_CHANNEL) { - Initialize(); - _instance = creature->GetInstanceScript(); + events.ScheduleEvent(EVENT_START_CHANNELERS_AND_SPAWNERS, 1s); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + events.ScheduleEvent(EVENT_EVADE_CHECK, 10s); + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); } - void Initialize() + if (spellInfo->Id == SPELL_AKAMA_SOUL_RETRIEVE) + DoCastSelf(SPELL_AKAMA_SOUL_EXPEL_CHANNEL); + } + + void MovementInform(uint32 motionType, uint32 /*pointId*/) override + { + if (_isInPhaseOne && motionType == CHASE_MOTION_TYPE) { - _isInCombat = false; - _hasYelledOnce = false; - _chosen.Clear(); - _summons.DespawnAll(); - _events.Reset(); + _isInPhaseOne = false; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(false); + me->SetWalk(false); + events.ScheduleEvent(EVENT_ADD_THREAT, Milliseconds(100)); + + for (ObjectGuid const spawnerGuid : _spawners) + if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) + spawner->AI()->DoAction(ACTION_STOP_SPAWNING); } + } - void Reset() override - { - Initialize(); - me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); - DoCastSelf(SPELL_STEALTH); + void JustDied(Unit* /*killer*/) override + { + DoCastSelf(SPELL_SHADE_OF_AKAMA_TRIGGER); - if (_instance->GetBossState(DATA_SHADE_OF_AKAMA) != DONE) - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + akama->AI()->DoAction(ACTION_SHADE_OF_AKAMA_DEAD); - void JustSummoned(Creature* summon) override - { - _summons.Summon(summon); - } + for (ObjectGuid const spawnerGuid : _spawners) + if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) + spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS); - void EnterEvadeMode(EvadeReason /*why*/) override { } + events.Reset(); + summons.DespawnEntry(NPC_ASHTONGUE_CHANNELER); + instance->SetBossState(DATA_SHADE_OF_AKAMA, DONE); + } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_THREAT && !_isInCombat) - { - _isInCombat = true; - me->SetWalk(false); - me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); - if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) - { - shade->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); - AttackStart(shade); - _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(2)); - _events.ScheduleEvent(EVENT_DESTRUCTIVE_POISON, Seconds(5)); - } - } - } - - void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override - { - if (me->HealthBelowPct(20) && !_hasYelledOnce) - { - _hasYelledOnce = true; - Talk(SAY_LOW_HEALTH); - } - } - - void DoAction(int32 actionId) override - { - if (actionId == ACTION_SHADE_OF_AKAMA_DEAD) - { - _isInCombat = false; - me->CombatStop(true); - me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); - me->SetWalk(true); - _events.Reset(); - me->GetMotionMaster()->MovePoint(AKAMA_INTRO_WAYPOINT, AkamaWP[1]); - } - } - - void MovementInform(uint32 motionType, uint32 pointId) override - { - if (motionType != POINT_MOTION_TYPE) - return; - - if (pointId == AKAMA_CHANNEL_WAYPOINT) - _events.ScheduleEvent(EVENT_SHADE_CHANNEL, Seconds(1)); - - else if (pointId == AKAMA_INTRO_WAYPOINT) - { - me->SetWalk(false); - _events.ScheduleEvent(EVENT_START_SOUL_RETRIEVE, Seconds(1)); - } - } - - void SummonBrokens() - { - for (uint8 i = 0; i < 18; i++) - { - if (TempSummon* summoned = me->SummonCreature(NPC_ASHTONGUE_BROKEN, BrokenPos[i])) - { - summoned->SetWalk(true); - summoned->GetMotionMaster()->MovePoint(0, BrokenWP[i]); - if (i == 9) //On Sniffs, npc that Yell "Special" is the tenth to be created - _chosen = summoned->GetGUID(); - } - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADE_START: - _instance->SetBossState(DATA_SHADE_OF_AKAMA, IN_PROGRESS); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - me->RemoveAurasDueToSpell(SPELL_STEALTH); - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(AKAMA_CHANNEL_WAYPOINT, AkamaWP[0], false); - break; - case EVENT_SHADE_CHANNEL: - me->SetFacingTo(FACE_THE_PLATFORM); - DoCastSelf(SPELL_AKAMA_SOUL_CHANNEL); - me->SetFaction(FACTION_MONSTER_SPAR_BUDDY); - _events.ScheduleEvent(EVENT_FIXATE, Seconds(5)); - break; - case EVENT_FIXATE: - DoCast(SPELL_FIXATE); - break; - case EVENT_CHAIN_LIGHTNING: - DoCastVictim(SPELL_CHAIN_LIGHTNING); - _events.Repeat(Seconds(8), Seconds(15)); - break; - case EVENT_DESTRUCTIVE_POISON: - DoCastSelf(SPELL_DESTRUCTIVE_POISON); - _events.Repeat(Seconds(3), Seconds(7)); - break; - case EVENT_START_SOUL_RETRIEVE: - me->SetFacingTo(FACE_THE_DOOR); - DoCast(SPELL_AKAMA_SOUL_RETRIEVE); - _events.ScheduleEvent(EVENT_START_BROKEN_FREE, Seconds(15)); - break; - case EVENT_START_BROKEN_FREE: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - Talk(SAY_BROKEN_FREE_0); - SummonBrokens(); - _events.ScheduleEvent(EVENT_BROKEN_FREE_1, Seconds(10)); - break; - case EVENT_BROKEN_FREE_1: - Talk(SAY_BROKEN_FREE_1); - _events.ScheduleEvent(EVENT_BROKEN_FREE_2, Seconds(12)); - break; - case EVENT_BROKEN_FREE_2: - Talk(SAY_BROKEN_FREE_2); - _events.ScheduleEvent(EVENT_BROKEN_FREE_3, Seconds(15)); - break; - case EVENT_BROKEN_FREE_3: - if (Creature* special = ObjectAccessor::GetCreature(*me, _chosen)) - special->AI()->Talk(SAY_BROKEN_SPECIAL); - - _summons.DoAction(ACTION_BROKEN_EMOTE, _pred); - _events.ScheduleEvent(EVENT_BROKEN_FREE_4, Seconds(5)); - break; - case EVENT_BROKEN_FREE_4: - _summons.DoAction(ACTION_BROKEN_HAIL, _pred); - break; - default: - break; - } - } - - if (me->GetFaction() == FACTION_MONSTER_SPAR_BUDDY) - { - if (!UpdateVictim()) + void EnterEvadeModeIfNeeded() + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->GetSource()) + if (player->IsAlive() && !player->IsGameMaster() && CheckBoundary(player)) return; - DoMeleeAttackIfReady(); - } - } - - void JustDied(Unit* /*killer*/) override - { - _summons.DespawnAll(); - Talk(SAY_DEAD); - if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) - if (shade->IsAlive()) - shade->AI()->EnterEvadeMode(EVADE_REASON_OTHER); - } - - bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override - { - if (gossipListId == 0) - { - CloseGossipMenuFor(player); - _events.ScheduleEvent(EVENT_SHADE_START, Milliseconds(500)); - } - return false; - } - - private: - InstanceScript* _instance; - EventMap _events; - SummonList _summons; - DummyEntryCheckPredicate _pred; - ObjectGuid _chosen; //Creature that should yell the speech special. - bool _isInCombat; - bool _hasYelledOnce; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); } -}; -class npc_ashtongue_channeler : public CreatureScript -{ -public: - npc_ashtongue_channeler() : CreatureScript("npc_ashtongue_channeler") { } - - struct npc_ashtongue_channelerAI : public PassiveAI + void UpdateAI(uint32 diff) override { - npc_ashtongue_channelerAI(Creature* creature) : PassiveAI(creature) - { - _instance = creature->GetInstanceScript(); - } + events.Update(diff); - void Reset() override + if (!UpdateVictim()) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _scheduler.Schedule(Seconds(2), [this](TaskContext channel) + switch (eventId) { - if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) + case EVENT_INITIALIZE_SPAWNERS: { - if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) - DoCastSelf(SPELL_SHADE_SOUL_CHANNEL); + std::list SpawnerList; + me->GetCreatureListWithEntryInGrid(SpawnerList, NPC_CREATURE_SPAWNER_AKAMA); + for (Creature* spawner : SpawnerList) + _spawners.push_back(spawner->GetGUID()); - else - me->DespawnOrUnsummon(Seconds(3)); + break; } + case EVENT_START_CHANNELERS_AND_SPAWNERS: + { + for (ObjectGuid const summonGuid : summons) + if (Creature* channeler = ObjectAccessor::GetCreature(*me, summonGuid)) + channeler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - channel.Repeat(Seconds(2)); - }); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } + for (ObjectGuid const spawnerGuid : _spawners) + if (Creature* spawner = ObjectAccessor::GetCreature(*me, spawnerGuid)) + spawner->AI()->DoAction(ACTION_START_SPAWNING); - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); - } -}; - -class npc_creature_generator_akama : public CreatureScript -{ -public: - npc_creature_generator_akama() : CreatureScript("npc_creature_generator_akama") { } - - struct npc_creature_generator_akamaAI : public ScriptedAI - { - npc_creature_generator_akamaAI(Creature* creature) : ScriptedAI(creature), _summons(me) - { - Initialize(); - } - - void Initialize() - { - _leftSide = false; - _events.Reset(); - _summons.DespawnAll(); - } - - void Reset() override - { - Initialize(); - - if (me->GetPositionY() < MIDDLE_OF_ROOM) - _leftSide = true; - } - - void JustSummoned(Creature* summon) override - { - _summons.Summon(summon); - } - - void DoAction(int32 actionId) override - { - switch (actionId) - { - case ACTION_START_SPAWNING: - if (_leftSide) - { - _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Milliseconds(100)); - _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, Seconds(2), Seconds(5)); - } - else - { - _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Seconds(10)); - _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, Seconds(2), Seconds(5)); - } break; - case ACTION_STOP_SPAWNING: - _events.Reset(); + } + case EVENT_ADD_THREAT: + DoCast(SPELL_THREAT); + events.Repeat(Seconds(3) + Milliseconds(500)); break; - case ACTION_DESPAWN_ALL_SPAWNS: - _events.Reset(); - _summons.DespawnAll(); + case EVENT_EVADE_CHECK: + EnterEvadeModeIfNeeded(); + events.Repeat(Seconds(10)); break; default: break; } } - void UpdateAI(uint32 diff) override - { - _events.Update(diff); + DoMeleeAttackIfReady(); + } - while (uint32 eventId = _events.ExecuteEvent()) +private: + GuidVector _spawners; + bool _isInPhaseOne; +}; + +struct npc_akama_shade : public ScriptedAI +{ + npc_akama_shade(Creature* creature) : ScriptedAI(creature), _summons(me) + { + Initialize(); + _instance = creature->GetInstanceScript(); + } + + void Initialize() + { + _isInCombat = false; + _hasYelledOnce = false; + _chosen.Clear(); + _summons.DespawnAll(); + _events.Reset(); + } + + void Reset() override + { + Initialize(); + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + DoCastSelf(SPELL_STEALTH); + + if (_instance->GetBossState(DATA_SHADE_OF_AKAMA) != DONE) + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void JustSummoned(Creature* summon) override + { + _summons.Summon(summon); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_THREAT && !_isInCombat) + { + _isInCombat = true; + me->SetWalk(false); + me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { - switch (eventId) - { - case EVENT_SPAWN_WAVE_B: - DoCastSelf(SPELL_ASHTONGUE_WAVE_B); - _events.Repeat(Seconds(50), Seconds(60)); - break; - case EVENT_SUMMON_ASHTONGUE_SORCERER: // left - DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER); - _events.Repeat(Seconds(30), Seconds(35)); - break; - case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right - DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER); - _events.Repeat(Seconds(30), Seconds(40)); - break; - default: - break; - } + shade->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); + AttackStart(shade); + _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 2s); + _events.ScheduleEvent(EVENT_DESTRUCTIVE_POISON, 5s); + } + } + } + + void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override + { + if (me->HealthBelowPct(20) && !_hasYelledOnce) + { + _hasYelledOnce = true; + Talk(SAY_LOW_HEALTH); + } + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_SHADE_OF_AKAMA_DEAD) + { + _isInCombat = false; + me->CombatStop(true); + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + me->SetWalk(true); + _events.Reset(); + me->GetMotionMaster()->MovePoint(AKAMA_INTRO_WAYPOINT, AkamaWP[1]); + } + } + + void MovementInform(uint32 motionType, uint32 pointId) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (pointId == AKAMA_CHANNEL_WAYPOINT) + _events.ScheduleEvent(EVENT_SHADE_CHANNEL, 1s); + + else if (pointId == AKAMA_INTRO_WAYPOINT) + { + me->SetWalk(false); + _events.ScheduleEvent(EVENT_START_SOUL_RETRIEVE, 1s); + } + } + + void SummonBrokens() + { + for (uint8 i = 0; i < 18; i++) + { + if (TempSummon* summoned = me->SummonCreature(NPC_ASHTONGUE_BROKEN, BrokenPos[i])) + { + summoned->SetWalk(true); + summoned->GetMotionMaster()->MovePoint(0, BrokenWP[i]); + if (i == 9) //On Sniffs, npc that Yell "Special" is the tenth to be created + _chosen = summoned->GetGUID(); + } + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHADE_START: + _instance->SetBossState(DATA_SHADE_OF_AKAMA, IN_PROGRESS); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->RemoveAurasDueToSpell(SPELL_STEALTH); + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(AKAMA_CHANNEL_WAYPOINT, AkamaWP[0], false); + break; + case EVENT_SHADE_CHANNEL: + me->SetFacingTo(FACE_THE_PLATFORM); + DoCastSelf(SPELL_AKAMA_SOUL_CHANNEL); + me->SetFaction(FACTION_MONSTER_SPAR_BUDDY); + _events.ScheduleEvent(EVENT_FIXATE, 5s); + break; + case EVENT_FIXATE: + DoCast(SPELL_FIXATE); + break; + case EVENT_CHAIN_LIGHTNING: + DoCastVictim(SPELL_CHAIN_LIGHTNING); + _events.Repeat(Seconds(8), Seconds(15)); + break; + case EVENT_DESTRUCTIVE_POISON: + DoCastSelf(SPELL_DESTRUCTIVE_POISON); + _events.Repeat(Seconds(3), Seconds(7)); + break; + case EVENT_START_SOUL_RETRIEVE: + me->SetFacingTo(FACE_THE_DOOR); + DoCast(SPELL_AKAMA_SOUL_RETRIEVE); + _events.ScheduleEvent(EVENT_START_BROKEN_FREE, 15s); + break; + case EVENT_START_BROKEN_FREE: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + Talk(SAY_BROKEN_FREE_0); + SummonBrokens(); + _events.ScheduleEvent(EVENT_BROKEN_FREE_1, Seconds(10)); + break; + case EVENT_BROKEN_FREE_1: + Talk(SAY_BROKEN_FREE_1); + _events.ScheduleEvent(EVENT_BROKEN_FREE_2, Seconds(12)); + break; + case EVENT_BROKEN_FREE_2: + Talk(SAY_BROKEN_FREE_2); + _events.ScheduleEvent(EVENT_BROKEN_FREE_3, Seconds(15)); + break; + case EVENT_BROKEN_FREE_3: + if (Creature* special = ObjectAccessor::GetCreature(*me, _chosen)) + special->AI()->Talk(SAY_BROKEN_SPECIAL); + + _summons.DoAction(ACTION_BROKEN_EMOTE, _pred); + _events.ScheduleEvent(EVENT_BROKEN_FREE_4, Seconds(5)); + break; + case EVENT_BROKEN_FREE_4: + _summons.DoAction(ACTION_BROKEN_HAIL, _pred); + break; + default: + break; } } - private: - EventMap _events; - SummonList _summons; - bool _leftSide; - }; + if (me->GetFaction() == FACTION_MONSTER_SPAR_BUDDY) + { + if (!UpdateVictim()) + return; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); + } } + + void JustDied(Unit* /*killer*/) override + { + _summons.DespawnAll(); + Talk(SAY_DEAD); + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) + if (shade->IsAlive()) + shade->AI()->EnterEvadeMode(EVADE_REASON_OTHER); + } + + bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + if (gossipListId == 0) + { + CloseGossipMenuFor(player); + _events.ScheduleEvent(EVENT_SHADE_START, Milliseconds(500)); + } + return false; + } + +private: + InstanceScript* _instance; + EventMap _events; + SummonList _summons; + DummyEntryCheckPredicate _pred; + ObjectGuid _chosen; //Creature that should yell the speech special. + bool _isInCombat; + bool _hasYelledOnce; }; -class npc_ashtongue_sorcerer : public CreatureScript +struct npc_ashtongue_channeler : public PassiveAI { -public: - npc_ashtongue_sorcerer() : CreatureScript("npc_ashtongue_sorcerer") { } - - struct npc_ashtongue_sorcererAI : public ScriptedAI + npc_ashtongue_channeler(Creature* creature) : PassiveAI(creature) { - npc_ashtongue_sorcererAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - _instance = creature->GetInstanceScript(); - } + _instance = creature->GetInstanceScript(); + } - void Initialize() - { - _switchToCombat = false; - _inBanish = false; - } - - void Reset() override + void Reset() override + { + _scheduler.Schedule(Seconds(2), [this](TaskContext channel) { if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) { if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) - me->GetMotionMaster()->MovePoint(0, shade->GetPosition()); + DoCastSelf(SPELL_SHADE_SOUL_CHANNEL); - else if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); + else + me->DespawnOrUnsummon(Seconds(3)); } - Initialize(); - } - void JustDied(Unit* /*killer*/) override + channel.Repeat(Seconds(2)); + }); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; +}; + +struct npc_creature_generator_akama : public ScriptedAI +{ + npc_creature_generator_akama(Creature* creature) : ScriptedAI(creature), _summons(me) + { + Initialize(); + } + + void Initialize() + { + _leftSide = false; + _events.Reset(); + _summons.DespawnAll(); + } + + void Reset() override + { + Initialize(); + + if (me->GetPositionY() < MIDDLE_OF_ROOM) + _leftSide = true; + } + + void JustSummoned(Creature* summon) override + { + _summons.Summon(summon); + } + + void DoAction(int32 actionId) override + { + switch (actionId) { - me->DespawnOrUnsummon(Seconds(5)); - } - - void EnterEvadeMode(EvadeReason /*why*/) override { } - void JustEngagedWith(Unit* /*who*/) override { } - - void AttackStart(Unit* who) override - { - if (!_switchToCombat) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - { - if (!_inBanish && who->GetGUID() == _instance->GetGuidData(DATA_SHADE_OF_AKAMA) && me->IsWithinDist(who, 20.0f, false)) - { - _inBanish = true; - me->StopMoving(); - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + frand(-8.0f, 8.0f), me->GetPositionY() + frand(-8.0f, 8.0f), me->GetPositionZ()); - - _scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel) + case ACTION_START_SPAWNING: + if (_leftSide) { - if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) + _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Milliseconds(100)); + _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, 2s, 5s); + } + else + { + _events.ScheduleEvent(EVENT_SPAWN_WAVE_B, 10s); + _events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, 2s, 5s); + } + break; + case ACTION_STOP_SPAWNING: + _events.Reset(); + break; + case ACTION_DESPAWN_ALL_SPAWNS: + _events.Reset(); + _summons.DespawnAll(); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SPAWN_WAVE_B: + DoCastSelf(SPELL_ASHTONGUE_WAVE_B); + _events.Repeat(Seconds(50), Seconds(60)); + break; + case EVENT_SUMMON_ASHTONGUE_SORCERER: // left + DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER); + _events.Repeat(Seconds(30), Seconds(35)); + break; + case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right + DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER); + _events.Repeat(Seconds(30), Seconds(40)); + break; + default: + break; + } + } + } + +private: + EventMap _events; + SummonList _summons; + bool _leftSide; +}; + +struct npc_ashtongue_sorcerer : public ScriptedAI +{ + npc_ashtongue_sorcerer(Creature* creature) : ScriptedAI(creature) + { + Initialize(); + _instance = creature->GetInstanceScript(); + } + + void Initialize() + { + _switchToCombat = false; + _inBanish = false; + } + + void Reset() override + { + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) + { + if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + me->GetMotionMaster()->MovePoint(0, shade->GetPosition()); + + else if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); + } + Initialize(); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(Seconds(5)); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + void JustEngagedWith(Unit* /*who*/) override { } + + void AttackStart(Unit* who) override + { + if (!_switchToCombat) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!_inBanish && who->GetGUID() == _instance->GetGuidData(DATA_SHADE_OF_AKAMA) && me->IsWithinDist(who, 20.0f, false)) + { + _inBanish = true; + me->StopMoving(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + frand(-8.0f, 8.0f), me->GetPositionY() + frand(-8.0f, 8.0f), me->GetPositionZ()); + + _scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel) + { + if (Creature* shade = _instance->GetCreature(DATA_SHADE_OF_AKAMA)) + { + if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { - if (shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) - { - me->SetFacingToObject(shade); - DoCastSelf(SPELL_SHADE_SOUL_CHANNEL); - sorcer_channel.Repeat(Seconds(2)); - } - else - { - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - _switchToCombat = true; - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } + me->SetFacingToObject(shade); + DoCastSelf(SPELL_SHADE_SOUL_CHANNEL); + sorcer_channel.Repeat(Seconds(2)); } - }); - } + else + { + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + _switchToCombat = true; + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); + } + } + }); } - - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - TaskScheduler _scheduler; - bool _switchToCombat; - bool _inBanish; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; + bool _switchToCombat; + bool _inBanish; }; -class npc_ashtongue_defender : public CreatureScript +struct npc_ashtongue_defender : public ScriptedAI { -public: - npc_ashtongue_defender() : CreatureScript("npc_ashtongue_defender") { } - - struct npc_ashtongue_defenderAI : public ScriptedAI + npc_ashtongue_defender(Creature* creature) : ScriptedAI(creature) { - npc_ashtongue_defenderAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() override - { - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(Seconds(5)); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(5)); - _events.ScheduleEvent(EVENT_SHIELD_BASH, Seconds(10), Seconds(16)); - _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, Seconds(10), Seconds(16)); - _events.ScheduleEvent(EVENT_WINDFURY, Seconds(8), Seconds(12)); - } - - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DEBILITATING_STRIKE: - DoCastVictim(SPELL_DEBILITATING_STRIKE); - _events.Repeat(Seconds(20), Seconds(25)); - break; - case EVENT_HEROIC_STRIKE: - DoCastSelf(SPELL_HEROIC_STRIKE); - _events.Repeat(Seconds(5), Seconds(15)); - break; - case EVENT_SHIELD_BASH: - DoCastVictim(SPELL_SHIELD_BASH); - _events.Repeat(Seconds(10), Seconds(20)); - break; - case EVENT_WINDFURY: - DoCastVictim(SPELL_WINDFURY); - _events.Repeat(Seconds(6), Seconds(8)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _instance = creature->GetInstanceScript(); } -}; -class npc_ashtongue_rogue : public CreatureScript -{ -public: - npc_ashtongue_rogue() : CreatureScript("npc_ashtongue_rogue") { } - - struct npc_ashtongue_rogueAI : public ScriptedAI + void Reset() override { - npc_ashtongue_rogueAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() override - { - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(Seconds(5)); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_DEBILITATING_POISON, Milliseconds(500), Seconds(2)); - _events.ScheduleEvent(EVENT_EVISCERATE, Seconds(2), Seconds(5)); - } - - void EnterEvadeMode(EvadeReason /*why*/) override { } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DEBILITATING_POISON: - DoCastVictim(SPELL_DEBILITATING_POISON); - _events.Repeat(Seconds(15), Seconds(20)); - break; - case EVENT_EVISCERATE: - DoCastVictim(SPELL_EVISCERATE); - _events.Repeat(Seconds(12), Seconds(20)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); } -}; -class npc_ashtongue_elementalist : public CreatureScript -{ -public: - npc_ashtongue_elementalist() : CreatureScript("npc_ashtongue_elementalist") { } - - struct npc_ashtongue_elementalistAI : public ScriptedAI + void JustDied(Unit* /*killer*/) override { - npc_ashtongue_elementalistAI(Creature* creature) : ScriptedAI(creature) - { - _instance = creature->GetInstanceScript(); - } - - void Reset() override - { - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(Seconds(5)); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_RAIN_OF_FIRE, Seconds(18)); - _events.ScheduleEvent(EVENT_LIGHTNING_BOLT, Seconds(6)); - } - - void EnterEvadeMode(EvadeReason /*why*/) override { } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RAIN_OF_FIRE: - DoCastVictim(SPELL_RAIN_OF_FIRE); - _events.Repeat(Seconds(15), Seconds(20)); - break; - case EVENT_LIGHTNING_BOLT: - DoCastVictim(SPELL_LIGHTNING_BOLT); - _events.Repeat(Seconds(8), Seconds(15)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + me->DespawnOrUnsummon(Seconds(5)); } -}; -class npc_ashtongue_spiritbinder : public CreatureScript -{ -public: - npc_ashtongue_spiritbinder() : CreatureScript("npc_ashtongue_spiritbinder") { } - - struct npc_ashtongue_spiritbinderAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { - npc_ashtongue_spiritbinderAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - _instance = creature->GetInstanceScript(); - } - - void Initialize() - { - _spiritMend = false; - _chainHeal = false; - } - - void Reset() override - { - Initialize(); - - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - AttackStart(akama); - } - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(Seconds(5)); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_SPIRIT_HEAL, Seconds(5), Seconds(6)); - } - - void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override - { - if (!_spiritMend) - if (HealthBelowPct(30)) - { - DoCastSelf(SPELL_SPIRIT_MEND); - _spiritMend = true; - _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, Seconds(10),Seconds(15)); - } - - if (!_chainHeal) - if (HealthBelowPct(50)) - { - DoCastSelf(SPELL_CHAIN_HEAL); - _chainHeal = true; - _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, Seconds(10), Seconds(15)); - } - - } - - void EnterEvadeMode(EvadeReason /*why*/) override { } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SPIRIT_HEAL: - DoCastSelf(SPELL_SPIRITBINDER_SPIRIT_HEAL); - _events.Repeat(Seconds(13), Seconds(16)); - break; - case EVENT_SPIRIT_MEND_RESET: - _spiritMend = false; - break; - case EVENT_CHAIN_HEAL_RESET: - _chainHeal = false; - break; - default: - break; - } - } - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - EventMap _events; - bool _spiritMend; - bool _chainHeal; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _events.ScheduleEvent(EVENT_HEROIC_STRIKE, 5s); + _events.ScheduleEvent(EVENT_SHIELD_BASH, 10s, 16s); + _events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, 10s, 16s); + _events.ScheduleEvent(EVENT_WINDFURY, 8s, 12s); } -}; -class npc_ashtongue_broken : public CreatureScript -{ -public: - npc_ashtongue_broken() : CreatureScript("npc_ashtongue_broken") { } - struct npc_ashtongue_brokenAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - npc_ashtongue_brokenAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } + if (!UpdateVictim()) + return; - void MovementInform(uint32 motionType, uint32 /*pointId*/) override - { - if (motionType != POINT_MOTION_TYPE) - return; + _events.Update(diff); - if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) - me->SetFacingToObject(akama); - } - - void DoAction(int32 actionId) override + while (uint32 eventId = _events.ExecuteEvent()) { - switch (actionId) + switch (eventId) { - case ACTION_BROKEN_SPECIAL: - Talk(SAY_BROKEN_SPECIAL); + case EVENT_DEBILITATING_STRIKE: + DoCastVictim(SPELL_DEBILITATING_STRIKE); + _events.Repeat(Seconds(20), Seconds(25)); break; - case ACTION_BROKEN_HAIL: - me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); - Talk(SAY_BROKEN_HAIL); + case EVENT_HEROIC_STRIKE: + DoCastSelf(SPELL_HEROIC_STRIKE); + _events.Repeat(Seconds(5), Seconds(15)); break; - case ACTION_BROKEN_EMOTE: - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_KNEEL); + case EVENT_SHIELD_BASH: + DoCastVictim(SPELL_SHIELD_BASH); + _events.Repeat(Seconds(10), Seconds(20)); + break; + case EVENT_WINDFURY: + DoCastVictim(SPELL_WINDFURY); + _events.Repeat(Seconds(6), Seconds(8)); break; default: break; } } - private: - InstanceScript* _instance; - }; - - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); } + +private: + InstanceScript* _instance; + EventMap _events; +}; + +struct npc_ashtongue_rogue : public ScriptedAI +{ + npc_ashtongue_rogue(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() override + { + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(Seconds(5)); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_DEBILITATING_POISON, Milliseconds(500), Seconds(2)); + _events.ScheduleEvent(EVENT_EVISCERATE, 2s, 5s); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DEBILITATING_POISON: + DoCastVictim(SPELL_DEBILITATING_POISON); + _events.Repeat(Seconds(15), Seconds(20)); + break; + case EVENT_EVISCERATE: + DoCastVictim(SPELL_EVISCERATE); + _events.Repeat(Seconds(12), Seconds(20)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + EventMap _events; +}; + +struct npc_ashtongue_elementalist : public ScriptedAI +{ + npc_ashtongue_elementalist(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() override + { + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(Seconds(5)); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 18s); + _events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 6s); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RAIN_OF_FIRE: + DoCastVictim(SPELL_RAIN_OF_FIRE); + _events.Repeat(Seconds(15), Seconds(20)); + break; + case EVENT_LIGHTNING_BOLT: + DoCastVictim(SPELL_LIGHTNING_BOLT); + _events.Repeat(Seconds(8), Seconds(15)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + EventMap _events; +}; + +struct npc_ashtongue_spiritbinder : public ScriptedAI +{ + npc_ashtongue_spiritbinder(Creature* creature) : ScriptedAI(creature) + { + Initialize(); + _instance = creature->GetInstanceScript(); + } + + void Initialize() + { + _spiritMend = false; + _chainHeal = false; + } + + void Reset() override + { + Initialize(); + + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + AttackStart(akama); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(Seconds(5)); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_SPIRIT_HEAL, 5s, 6s); + } + + void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override + { + if (!_spiritMend) + if (HealthBelowPct(30)) + { + DoCastSelf(SPELL_SPIRIT_MEND); + _spiritMend = true; + _events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, 10s, 15s); + } + + if (!_chainHeal) + if (HealthBelowPct(50)) + { + DoCastSelf(SPELL_CHAIN_HEAL); + _chainHeal = true; + _events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, 10s, 15s); + } + + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SPIRIT_HEAL: + DoCastSelf(SPELL_SPIRITBINDER_SPIRIT_HEAL); + _events.Repeat(Seconds(13), Seconds(16)); + break; + case EVENT_SPIRIT_MEND_RESET: + _spiritMend = false; + break; + case EVENT_CHAIN_HEAL_RESET: + _chainHeal = false; + break; + default: + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + EventMap _events; + bool _spiritMend; + bool _chainHeal; +}; + +struct npc_ashtongue_broken : public ScriptedAI +{ + npc_ashtongue_broken(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + } + + void MovementInform(uint32 motionType, uint32 /*pointId*/) override + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (Creature* akama = _instance->GetCreature(DATA_AKAMA_SHADE)) + me->SetFacingToObject(akama); + } + + void DoAction(int32 actionId) override + { + switch (actionId) + { + case ACTION_BROKEN_SPECIAL: + Talk(SAY_BROKEN_SPECIAL); + break; + case ACTION_BROKEN_HAIL: + me->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + Talk(SAY_BROKEN_HAIL); + break; + case ACTION_BROKEN_EMOTE: + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_KNEEL); + break; + default: + break; + } + } + +private: + InstanceScript* _instance; }; // 40401 - Shade Soul Channel (serverside spell) -class spell_shade_soul_channel_serverside : public SpellScriptLoader +class spell_shade_soul_channel_serverside : public AuraScript { -public: - spell_shade_soul_channel_serverside() : SpellScriptLoader("spell_shade_soul_channel_serverside") { } - - class spell_shade_soul_channel_serverside_AuraScript : public AuraScript + bool Validate(SpellInfo const* /*spell*/) override { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_SHADE_SOUL_CHANNEL_2 }); - } + return ValidateSpellInfo({ SPELL_SHADE_SOUL_CHANNEL_2 }); + } - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2); - } - - void Register() override - { - AfterEffectRemove.Register(&spell_shade_soul_channel_serverside_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - return new spell_shade_soul_channel_serverside_AuraScript(); + GetTarget()->RemoveAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_shade_soul_channel_serverside::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 40520 - Shade Soul Channel -class spell_shade_soul_channel : public SpellScriptLoader +class spell_shade_soul_channel : public AuraScript { -public: - spell_shade_soul_channel() : SpellScriptLoader("spell_shade_soul_channel") { } - - class spell_shade_soul_channel_AuraScript : public AuraScript + void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - int32 const maxSlowEff = -99; - if (aurEff->GetAmount() < maxSlowEff) - if (AuraEffect* slowEff = GetEffect(EFFECT_0)) - slowEff->ChangeAmount(maxSlowEff); - } + int32 const maxSlowEff = -99; + if (aurEff->GetAmount() < maxSlowEff) + if (AuraEffect* slowEff = GetEffect(EFFECT_0)) + slowEff->ChangeAmount(maxSlowEff); + } - void Register() override - { - AfterEffectApply.Register(&spell_shade_soul_channel_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - } - }; - - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_shade_soul_channel_AuraScript(); + AfterEffectApply.Register(&spell_shade_soul_channel::OnApply, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); } }; void AddSC_boss_shade_of_akama() { - new boss_shade_of_akama(); - new npc_akama_shade(); - new npc_ashtongue_channeler(); - new npc_creature_generator_akama(); - new npc_ashtongue_sorcerer(); - new npc_ashtongue_defender(); - new npc_ashtongue_rogue(); - new npc_ashtongue_elementalist(); - new npc_ashtongue_spiritbinder(); - new npc_ashtongue_broken(); - new spell_shade_soul_channel_serverside(); - new spell_shade_soul_channel(); + RegisterBlackTempleCreatureAI(boss_shade_of_akama); + RegisterBlackTempleCreatureAI(npc_akama_shade); + RegisterBlackTempleCreatureAI(npc_ashtongue_channeler); + RegisterBlackTempleCreatureAI(npc_creature_generator_akama); + RegisterBlackTempleCreatureAI(npc_ashtongue_sorcerer); + RegisterBlackTempleCreatureAI(npc_ashtongue_defender); + RegisterBlackTempleCreatureAI(npc_ashtongue_rogue); + RegisterBlackTempleCreatureAI(npc_ashtongue_elementalist); + RegisterBlackTempleCreatureAI(npc_ashtongue_spiritbinder); + RegisterBlackTempleCreatureAI(npc_ashtongue_broken); + RegisterSpellScript(spell_shade_soul_channel_serverside); + RegisterSpellScript(spell_shade_soul_channel); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp index 16aefbc671..630b08f740 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp @@ -63,200 +63,165 @@ enum Actions { ACTION_DISABLE_VULCANO = 1 }; - -class boss_supremus : public CreatureScript +struct boss_supremus : public BossAI { -public: - boss_supremus() : CreatureScript("boss_supremus") { } + boss_supremus(Creature* creature) : BossAI(creature, DATA_SUPREMUS) { } - struct boss_supremusAI : public BossAI + void Reset() override { - boss_supremusAI(Creature* creature) : BossAI(creature, DATA_SUPREMUS) { } + _Reset(); + events.SetPhase(PHASE_INITIAL); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); + } - void Reset() override + void EnterEvadeMode(EvadeReason /*why*/) override + { + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + ChangePhase(); + events.ScheduleEvent(EVENT_BERSERK, 15min); + events.ScheduleEvent(EVENT_FLAME, 20s); + } + + void ChangePhase() + { + if (events.IsInPhase(PHASE_INITIAL) || events.IsInPhase(PHASE_CHASE)) { - _Reset(); - events.SetPhase(PHASE_INITIAL); + events.SetPhase(PHASE_STRIKE); + DummyEntryCheckPredicate pred; + summons.DoAction(ACTION_DISABLE_VULCANO, pred); + events.ScheduleEvent(EVENT_HATEFUL_STRIKE, Seconds(2), 0, PHASE_STRIKE); + me->RemoveAurasDueToSpell(SPELL_SNARE_SELF); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); } - - void EnterEvadeMode(EvadeReason /*why*/) override + else { - summons.DespawnAll(); - _DespawnAtEvade(); + events.SetPhase(PHASE_CHASE); + events.ScheduleEvent(EVENT_VOLCANO, Seconds(5), 0, PHASE_CHASE); + events.ScheduleEvent(EVENT_SWITCH_TARGET, Seconds(10), 0, PHASE_CHASE); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); + DoCast(SPELL_SNARE_SELF); } + ResetThreatList(); + DoZoneInCombat(); + events.ScheduleEvent(EVENT_SWITCH_PHASE, 1min); + } - void JustEngagedWith(Unit* who) override + Unit* CalculateHatefulStrikeTarget() + { + uint32 health = 0; + Unit* target = nullptr; + + for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) { - BossAI::JustEngagedWith(who); - ChangePhase(); - events.ScheduleEvent(EVENT_BERSERK, Minutes(15)); - events.ScheduleEvent(EVENT_FLAME, Seconds(20)); - } - - void ChangePhase() - { - if (events.IsInPhase(PHASE_INITIAL) || events.IsInPhase(PHASE_CHASE)) + Unit* unit = ref->GetVictim(); + if (me->IsWithinMeleeRange(unit)) { - events.SetPhase(PHASE_STRIKE); - DummyEntryCheckPredicate pred; - summons.DoAction(ACTION_DISABLE_VULCANO, pred); - events.ScheduleEvent(EVENT_HATEFUL_STRIKE, Seconds(2), 0, PHASE_STRIKE); - me->RemoveAurasDueToSpell(SPELL_SNARE_SELF); - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); - } - else - { - events.SetPhase(PHASE_CHASE); - events.ScheduleEvent(EVENT_VOLCANO, Seconds(5), 0, PHASE_CHASE); - events.ScheduleEvent(EVENT_SWITCH_TARGET, Seconds(10), 0, PHASE_CHASE); - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); - DoCast(SPELL_SNARE_SELF); - } - ResetThreatList(); - DoZoneInCombat(); - events.ScheduleEvent(EVENT_SWITCH_PHASE, Seconds(60)); - } - - Unit* CalculateHatefulStrikeTarget() - { - uint32 health = 0; - Unit* target = nullptr; - - for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) - { - Unit* unit = ref->GetVictim(); - if (me->IsWithinMeleeRange(unit)) + if (unit->GetHealth() > health) { - if (unit->GetHealth() > health) - { - health = unit->GetHealth(); - target = unit; - } + health = unit->GetHealth(); + target = unit; } } - - return target; } - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_BERSERK: - DoCastSelf(SPELL_BERSERK, true); - break; - case EVENT_FLAME: - DoCast(SPELL_MOLTEN_PUNCH); - events.Repeat(Seconds(15), Seconds(20)); - break; - case EVENT_HATEFUL_STRIKE: - if (Unit* target = CalculateHatefulStrikeTarget()) - DoCast(target, SPELL_HATEFUL_STRIKE); - events.Repeat(Seconds(5)); - break; - case EVENT_SWITCH_TARGET: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true)) - { - ResetThreatList(); - AddThreat(target, 1000000.0f); - DoCast(target, SPELL_CHARGE); - Talk(EMOTE_NEW_TARGET); - } - events.Repeat(Seconds(10)); - break; - case EVENT_VOLCANO: - DoCastAOE(SPELL_VOLCANIC_SUMMON, true); - Talk(EMOTE_GROUND_CRACK); - events.Repeat(Seconds(10)); - break; - case EVENT_SWITCH_PHASE: - ChangePhase(); - break; - default: - break; - } - } + return target; + } - }; - - CreatureAI* GetAI(Creature* creature) const override + void ExecuteEvent(uint32 eventId) override { - return GetBlackTempleAI(creature); + switch (eventId) + { + case EVENT_BERSERK: + DoCastSelf(SPELL_BERSERK, true); + break; + case EVENT_FLAME: + DoCast(SPELL_MOLTEN_PUNCH); + events.Repeat(Seconds(15), Seconds(20)); + break; + case EVENT_HATEFUL_STRIKE: + if (Unit* target = CalculateHatefulStrikeTarget()) + DoCast(target, SPELL_HATEFUL_STRIKE); + events.Repeat(Seconds(5)); + break; + case EVENT_SWITCH_TARGET: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true)) + { + ResetThreatList(); + AddThreat(target, 1000000.0f); + DoCast(target, SPELL_CHARGE); + Talk(EMOTE_NEW_TARGET); + } + events.Repeat(Seconds(10)); + break; + case EVENT_VOLCANO: + DoCastAOE(SPELL_VOLCANIC_SUMMON, true); + Talk(EMOTE_GROUND_CRACK); + events.Repeat(Seconds(10)); + break; + case EVENT_SWITCH_PHASE: + ChangePhase(); + break; + default: + break; + } } }; -class npc_molten_flame : public CreatureScript +struct npc_molten_flame : public NullCreatureAI { -public: - npc_molten_flame() : CreatureScript("npc_molten_flame") { } + npc_molten_flame(Creature* creature) : NullCreatureAI(creature) { } - struct npc_molten_flameAI : public NullCreatureAI + void InitializeAI() override { - npc_molten_flameAI(Creature* creature) : NullCreatureAI(creature) { } - - void InitializeAI() override - { - float x, y, z; - me->GetNearPoint(me, x, y, z, 100.0f, frand(0.f, 2.f * float(M_PI))); - me->GetMotionMaster()->MovePoint(0, x, y, z); - DoCastSelf(SPELL_MOLTEN_FLAME, true); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + float x, y, z; + me->GetNearPoint(me, x, y, z, 100.0f, frand(0.f, 2.f * float(M_PI))); + me->GetMotionMaster()->MovePoint(0, x, y, z); + DoCastSelf(SPELL_MOLTEN_FLAME, true); } }; -class npc_volcano : public CreatureScript +struct npc_volcano : public NullCreatureAI { -public: - npc_volcano() : CreatureScript("npc_volcano") { } + npc_volcano(Creature* creature) : NullCreatureAI(creature) { } - struct npc_volcanoAI : public NullCreatureAI + void Reset() override { - npc_volcanoAI(Creature* creature) : NullCreatureAI(creature) { } - - void Reset() override + _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) { - _scheduler.Schedule(Seconds(3), [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_VOLCANIC_ERUPTION); - }); - } - - void DoAction(int32 action) override - { - if (action == ACTION_DISABLE_VULCANO) - { - me->RemoveAurasDueToSpell(SPELL_VOLCANIC_ERUPTION); - me->RemoveAurasDueToSpell(SPELL_VOLCANIC_GEYSER); - } - } - - void UpdateAI(uint32 diff) override - { - _scheduler.Update(diff); - } - - private: - TaskScheduler _scheduler; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoCastSelf(SPELL_VOLCANIC_ERUPTION); + }); } + + void DoAction(int32 action) override + { + if (action == ACTION_DISABLE_VULCANO) + { + me->RemoveAurasDueToSpell(SPELL_VOLCANIC_ERUPTION); + me->RemoveAurasDueToSpell(SPELL_VOLCANIC_GEYSER); + } + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; }; void AddSC_boss_supremus() { - new boss_supremus(); - new npc_molten_flame(); - new npc_volcano(); + RegisterBlackTempleCreatureAI(boss_supremus); + RegisterBlackTempleCreatureAI(npc_molten_flame); + RegisterBlackTempleCreatureAI(npc_volcano); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index d16f1f9b5a..0b59a52da4 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -69,14 +69,13 @@ enum Spells SPELL_SPIRIT_VOLLEY = 40314, SPELL_SPIRIT_SHIELD = 40322, SPELL_SPIRIT_LANCE = 40157 - }; enum Npcs { - NPC_DOOM_BLOSSOM = 23123, - NPC_SHADOWY_CONSTRUCT = 23111, - NPC_VENGEFUL_SPIRIT = 23109 //Npc controlled by player + NPC_DOOM_BLOSSOM = 23123, + NPC_SHADOWY_CONSTRUCT = 23111, + NPC_VENGEFUL_SPIRIT = 23109 //Npc controlled by player }; enum Events @@ -108,263 +107,316 @@ uint32 const SkeletronSpells[4] = SPELL_SUMMON_SKELETRON_4 }; -class boss_teron_gorefiend : public CreatureScript +struct boss_teron_gorefiend : public BossAI { -public: - boss_teron_gorefiend() : CreatureScript("boss_teron_gorefiend") { } + boss_teron_gorefiend(Creature* creature) : BossAI(creature, DATA_TERON_GOREFIEND) { } - struct boss_teron_gorefiendAI : public BossAI + void Reset() override { - boss_teron_gorefiendAI(Creature* creature) : BossAI(creature, DATA_TERON_GOREFIEND) { } - - void Reset() override + _Reset(); + if (instance->GetData(DATA_TERON_GOREFIEND_INTRO)) { - _Reset(); - if (instance->GetData(DATA_TERON_GOREFIEND_INTRO)) + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + Talk(SAY_AGGRO); + events.SetPhase(PHASE_COMBAT); + events.ScheduleEvent(EVENT_ENRAGE, 10min); + events.ScheduleEvent(EVENT_INCINERATE, 12s); + events.ScheduleEvent(EVENT_SUMMON_DOOM_BLOSSOM, 8s); + events.ScheduleEvent(EVENT_SHADOW_DEATH, 8s); + events.ScheduleEvent(EVENT_CRUSHING_SHADOWS, 18s); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_INTRO && me->IsAlive()) + { + instance->SetData(DATA_TERON_GOREFIEND_INTRO, 0); + Talk(SAY_INTRO); + events.SetPhase(PHASE_INTRO); + events.ScheduleEvent(EVENT_FINISH_INTRO, 20s); + } + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (!events.IsInPhase(PHASE_INTRO) && !UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); + case EVENT_ENRAGE: + DoCast(SPELL_BERSERK); + break; + case EVENT_INCINERATE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_INCINERATE); + Talk(SAY_INCINERATE); + events.Repeat(Seconds(12), Seconds(20)); + break; + case EVENT_SUMMON_DOOM_BLOSSOM: + DoCastSelf(SPELL_SUMMON_DOOM_BLOSSOM, true); + Talk(SAY_BLOSSOM); + events.Repeat(Seconds(30), Seconds(40)); + break; + case EVENT_SHADOW_DEATH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true, true, -SPELL_SPIRITUAL_VENGEANCE)) + DoCast(target, SPELL_SHADOW_OF_DEATH); + events.Repeat(Seconds(30), Seconds(35)); + break; + case EVENT_CRUSHING_SHADOWS: + DoCastSelf(SPELL_CRUSHING_SHADOWS, { SPELLVALUE_MAX_TARGETS, 5 }); + Talk(SAY_CRUSHING); + events.Repeat(Seconds(18), Seconds(30)); + break; + case EVENT_FINISH_INTRO: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - Talk(SAY_AGGRO); - events.SetPhase(PHASE_COMBAT); - events.ScheduleEvent(EVENT_ENRAGE, Minutes(10)); - events.ScheduleEvent(EVENT_INCINERATE, Seconds(12)); - events.ScheduleEvent(EVENT_SUMMON_DOOM_BLOSSOM, Seconds(8)); - events.ScheduleEvent(EVENT_SHADOW_DEATH, Seconds(8)); - events.ScheduleEvent(EVENT_CRUSHING_SHADOWS, Seconds(18)); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); - summons.DespawnAll(); - _DespawnAtEvade(); - } - - void DoAction(int32 action) override - { - if (action == ACTION_START_INTRO && me->IsAlive()) - { - instance->SetData(DATA_TERON_GOREFIEND_INTRO, 0); - Talk(SAY_INTRO); - events.SetPhase(PHASE_INTRO); - events.ScheduleEvent(EVENT_FINISH_INTRO, Seconds(20)); - } - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); - _JustDied(); - } - - void UpdateAI(uint32 diff) override - { - if (!events.IsInPhase(PHASE_INTRO) && !UpdateVictim()) - return; - - events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ENRAGE: - DoCast(SPELL_BERSERK); - break; - case EVENT_INCINERATE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_INCINERATE); - Talk(SAY_INCINERATE); - events.Repeat(Seconds(12), Seconds(20)); - break; - case EVENT_SUMMON_DOOM_BLOSSOM: - DoCastSelf(SPELL_SUMMON_DOOM_BLOSSOM, true); - Talk(SAY_BLOSSOM); - events.Repeat(Seconds(30), Seconds(40)); - break; - case EVENT_SHADOW_DEATH: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true, true, -SPELL_SPIRITUAL_VENGEANCE)) - DoCast(target, SPELL_SHADOW_OF_DEATH); - events.Repeat(Seconds(30), Seconds(35)); - break; - case EVENT_CRUSHING_SHADOWS: - DoCastSelf(SPELL_CRUSHING_SHADOWS, { SPELLVALUE_MAX_TARGETS, 5 }); - Talk(SAY_CRUSHING); - events.Repeat(Seconds(18), Seconds(30)); - break; - case EVENT_FINISH_INTRO: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + DoMeleeAttackIfReady(); } }; -class npc_doom_blossom : public CreatureScript +struct npc_doom_blossom : public NullCreatureAI { -public: - npc_doom_blossom() : CreatureScript("npc_doom_blossom") { } + npc_doom_blossom(Creature* creature) : NullCreatureAI(creature), _instance(me->GetInstanceScript()) { } - struct npc_doom_blossomAI : public NullCreatureAI + void Reset() override { - npc_doom_blossomAI(Creature* creature) : NullCreatureAI(creature), _instance(me->GetInstanceScript()) { } + /* Workaround - Until SMSG_SET_PLAY_HOVER_ANIM be implemented */ + Position pos; + pos.Relocate(me); + pos.m_positionZ += 8.0f; + me->GetMotionMaster()->MoveTakeoff(0, pos); - void Reset() override + DoCast(SPELL_SUMMON_BLOSSOM_MOVE_TARGET); + _scheduler.CancelAll(); + DoZoneInCombat(); + _scheduler.Schedule(Seconds(12), [this](TaskContext shadowBolt) { - /* Workaround - Until SMSG_SET_PLAY_HOVER_ANIM be implemented */ - Position pos; - pos.Relocate(me); - pos.m_positionZ += 8.0f; - me->GetMotionMaster()->MoveTakeoff(0, pos); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SHADOWBOLT); - DoCast(SPELL_SUMMON_BLOSSOM_MOVE_TARGET); - _scheduler.CancelAll(); - me->SetInCombatWithZone(); - _scheduler.Schedule(Seconds(12), [this](TaskContext shadowBolt) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SHADOWBOLT); - - shadowBolt.Repeat(Seconds(2)); - }); - } - - void UpdateAI(uint32 diff) override - { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - _scheduler.Update(diff); - } - - private: - TaskScheduler _scheduler; - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + shadowBolt.Repeat(Seconds(2)); + }); } + + void UpdateAI(uint32 diff) override + { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; + InstanceScript* _instance; }; -class npc_shadowy_construct : public CreatureScript +struct npc_shadowy_construct : public ScriptedAI { -public: - npc_shadowy_construct() : CreatureScript("npc_shadowy_construct") { } - - struct npc_shadowy_constructAI : public ScriptedAI + npc_shadowy_construct(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { - npc_shadowy_constructAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) + //This creature must be immune everything, except spells of Vengeful Spirit. + creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_MAGIC, true); + } + + void Reset() override + { + if (_instance->GetBossState(DATA_TERON_GOREFIEND) != IN_PROGRESS) { - //This creature must be immune everything, except spells of Vengeful Spirit. - creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_MAGIC, true); + me->DespawnOrUnsummon(); + return; } - void Reset() override + targetGUID.Clear(); + _scheduler.CancelAll(); + _scheduler.Schedule(Seconds(12), [this](TaskContext atrophy) { - if (_instance->GetBossState(DATA_TERON_GOREFIEND) != IN_PROGRESS) + DoCastVictim(SPELL_ATROPHY); + atrophy.Repeat(Seconds(10), Seconds(12)); + }); + _scheduler.Schedule(Milliseconds(200), [this](TaskContext checkPlayer) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) { - me->DespawnOrUnsummon(); - return; - } - - targetGUID.Clear(); - _scheduler.CancelAll(); - _scheduler.Schedule(Seconds(12), [this](TaskContext atrophy) - { - DoCastVictim(SPELL_ATROPHY); - atrophy.Repeat(Seconds(10), Seconds(12)); - }); - _scheduler.Schedule(Milliseconds(200), [this](TaskContext checkPlayer) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID)) - { - if (!target->IsAlive() || !me->CanCreatureAttack(target)) - SelectNewTarget(); - } - else + if (!target->IsAlive() || !me->CanCreatureAttack(target)) SelectNewTarget(); + } + else + SelectNewTarget(); - checkPlayer.Repeat(Seconds(1)); - }); + checkPlayer.Repeat(Seconds(1)); + }); - if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND)) - teron->AI()->JustSummoned(me); + if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND)) + teron->AI()->JustSummoned(me); - SelectNewTarget(); - } + SelectNewTarget(); + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + _scheduler.Update(diff, [this] { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + DoMeleeAttackIfReady(); + }); + } - _scheduler.Update(diff, [this] - { - DoMeleeAttackIfReady(); - }); - } - - void SelectNewTarget() + void SelectNewTarget() + { + if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND)) { - if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND)) - { - Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, true, -SPELL_SPIRITUAL_VENGEANCE); - // He should target Vengeful Spirits only if has no other player available - if (!target) - target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0); + Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, true, -SPELL_SPIRITUAL_VENGEANCE); + // He should target Vengeful Spirits only if has no other player available + if (!target) + target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) - { - ResetThreatList(); - AttackStart(target); - AddThreat(target, 1000000.0f); - targetGUID = target->GetGUID(); - } + if (target) + { + ResetThreatList(); + AttackStart(target); + AddThreat(target, 1000000.0f); + targetGUID = target->GetGUID(); } } + } - private: - TaskScheduler _scheduler; - InstanceScript* _instance; - ObjectGuid targetGUID; - }; +private: + TaskScheduler _scheduler; + InstanceScript* _instance; + ObjectGuid targetGUID; +}; - CreatureAI* GetAI(Creature* creature) const override +// 40251 - Shadow of Death +class spell_teron_gorefiend_shadow_of_death : public AuraScript +{ + bool Validate(SpellInfo const* /*spell*/) override { - return GetBlackTempleAI(creature); + return ValidateSpellInfo( + { + SPELL_SUMMON_SPIRIT, + SPELL_POSSESS_SPIRIT_IMMUNE, + SPELL_SPIRITUAL_VENGEANCE, + SPELL_SUMMON_SKELETRON_1, + SPELL_SUMMON_SKELETRON_2, + SPELL_SUMMON_SKELETRON_3, + SPELL_SUMMON_SKELETRON_4 + }); + } + + void Absorb(AuraEffect* /*aurEff*/, DamageInfo& /*dmgInfo*/, uint32& /*absorbAmount*/) + { + PreventDefaultAction(); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode().HasFlag(AuraRemoveFlags::Expired)) + { + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_SUMMON_SPIRIT, true); + + for (uint8 i = 0; i < 4; ++i) + target->CastSpell(target, SkeletronSpells[i], true); + + target->CastSpell(target, SPELL_POSSESS_SPIRIT_IMMUNE, true); + target->CastSpell(target, SPELL_SPIRITUAL_VENGEANCE, true); + } + } + + void Register() override + { + OnEffectAbsorb.Register(&spell_teron_gorefiend_shadow_of_death::Absorb, EFFECT_0); + AfterEffectRemove.Register(&spell_teron_gorefiend_shadow_of_death::OnRemove, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 40268 - Spiritual Vengeance +class spell_teron_gorefiend_spiritual_vengeance : public AuraScript +{ + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->KillSelf(); + } + + void Register() override + { + AfterEffectRemove.Register(&spell_teron_gorefiend_spiritual_vengeance::OnRemove, EFFECT_0, SPELL_AURA_MOD_POSSESS, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 41999 - Shadow of Death Remove +class spell_teron_gorefiend_shadow_of_death_remove : public SpellScript +{ + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( + { + SPELL_SHADOW_OF_DEATH, + SPELL_POSSESS_SPIRIT_IMMUNE, + SPELL_SPIRITUAL_VENGEANCE + }); + } + + void RemoveAuras() + { + Unit* target = GetHitUnit(); + + target->RemoveAurasDueToSpell(SPELL_POSSESS_SPIRIT_IMMUNE); + target->RemoveAurasDueToSpell(SPELL_SPIRITUAL_VENGEANCE); + target->RemoveAurasDueToSpell(SPELL_SHADOW_OF_DEATH); + } + + void Register() override + { + OnHit.Register(&spell_teron_gorefiend_shadow_of_death_remove::RemoveAuras); } }; @@ -383,131 +435,13 @@ public: } }; -// 40251 - Shadow of Death -class spell_teron_gorefiend_shadow_of_death : public SpellScriptLoader -{ - public: - spell_teron_gorefiend_shadow_of_death() : SpellScriptLoader("spell_teron_gorefiend_shadow_of_death") { } - - class spell_teron_gorefiend_shadow_of_death_AuraScript : public AuraScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo( - { - SPELL_SUMMON_SPIRIT, - SPELL_POSSESS_SPIRIT_IMMUNE, - SPELL_SPIRITUAL_VENGEANCE, - SPELL_SUMMON_SKELETRON_1, - SPELL_SUMMON_SKELETRON_2, - SPELL_SUMMON_SKELETRON_3, - SPELL_SUMMON_SKELETRON_4 - }); - } - - void Absorb(AuraEffect* /*aurEff*/, DamageInfo& /*dmgInfo*/, uint32& /*absorbAmount*/) - { - PreventDefaultAction(); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (GetTargetApplication()->GetRemoveMode().HasFlag(AuraRemoveFlags::Expired)) - { - Unit* target = GetTarget(); - target->CastSpell(target, SPELL_SUMMON_SPIRIT, true); - - for (uint8 i = 0; i < 4; ++i) - target->CastSpell(target, SkeletronSpells[i], true); - - target->CastSpell(target, SPELL_POSSESS_SPIRIT_IMMUNE, true); - target->CastSpell(target, SPELL_SPIRITUAL_VENGEANCE, true); - } - } - - void Register() override - { - OnEffectAbsorb.Register(&spell_teron_gorefiend_shadow_of_death_AuraScript::Absorb, EFFECT_0); - AfterEffectRemove.Register(&spell_teron_gorefiend_shadow_of_death_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_teron_gorefiend_shadow_of_death_AuraScript(); - } -}; - -// 40268 - Spiritual Vengeance -class spell_teron_gorefiend_spiritual_vengeance : public SpellScriptLoader -{ - public: - spell_teron_gorefiend_spiritual_vengeance() : SpellScriptLoader("spell_teron_gorefiend_spiritual_vengeance") { } - - class spell_teron_gorefiend_spiritual_vengeance_AuraScript : public AuraScript - { - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->KillSelf(); - } - - void Register() override - { - AfterEffectRemove.Register(&spell_teron_gorefiend_spiritual_vengeance_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_POSSESS, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove.Register(&spell_teron_gorefiend_spiritual_vengeance_AuraScript::OnRemove, EFFECT_2, SPELL_AURA_MOD_PACIFY_SILENCE, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_teron_gorefiend_spiritual_vengeance_AuraScript(); - } -}; - -// 41999 - Shadow of Death Remove -class spell_teron_gorefiend_shadow_of_death_remove : public SpellScriptLoader -{ - public: - spell_teron_gorefiend_shadow_of_death_remove() : SpellScriptLoader("spell_teron_gorefiend_shadow_of_death_remove") { } - - class spell_teron_gorefiend_shadow_of_death_remove_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_SHADOW_OF_DEATH, SPELL_POSSESS_SPIRIT_IMMUNE, SPELL_SPIRITUAL_VENGEANCE }); - return false; - return true; - } - - void RemoveAuras() - { - Unit* target = GetHitUnit(); - - target->RemoveAurasDueToSpell(SPELL_POSSESS_SPIRIT_IMMUNE); - target->RemoveAurasDueToSpell(SPELL_SPIRITUAL_VENGEANCE); - target->RemoveAurasDueToSpell(SPELL_SHADOW_OF_DEATH); - } - - void Register() override - { - OnHit.Register(&spell_teron_gorefiend_shadow_of_death_remove_SpellScript::RemoveAuras); - } - - }; - - SpellScript* GetSpellScript() const override - { - return new spell_teron_gorefiend_shadow_of_death_remove_SpellScript(); - } -}; - void AddSC_boss_teron_gorefiend() { - new boss_teron_gorefiend(); - new npc_doom_blossom(); - new npc_shadowy_construct(); + RegisterBlackTempleCreatureAI(boss_teron_gorefiend); + RegisterBlackTempleCreatureAI(npc_doom_blossom); + RegisterBlackTempleCreatureAI(npc_shadowy_construct); + RegisterSpellScript(spell_teron_gorefiend_shadow_of_death); + RegisterSpellScript(spell_teron_gorefiend_spiritual_vengeance); + RegisterSpellScript(spell_teron_gorefiend_shadow_of_death_remove); new at_teron_gorefiend_entrance(); - new spell_teron_gorefiend_shadow_of_death(); - new spell_teron_gorefiend_spiritual_vengeance(); - new spell_teron_gorefiend_shadow_of_death_remove(); } diff --git a/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp b/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp index 789bf29c96..df1ad4581b 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp @@ -28,218 +28,205 @@ enum Texts { - SAY_AGGRO = 0, - SAY_NEEDLE = 1, - SAY_SLAY = 2, - SAY_SPECIAL = 3, - SAY_ENRAGE = 4, - SAY_DEATH = 5 + SAY_AGGRO = 0, + SAY_NEEDLE = 1, + SAY_SLAY = 2, + SAY_SPECIAL = 3, + SAY_ENRAGE = 4, + SAY_DEATH = 5 }; enum Spells { - SPELL_NEEDLE_SPINE_TARGETING = 39992, - SPELL_NEEDLE_SPINE = 39835, - SPELL_TIDAL_BURST = 39878, - SPELL_TIDAL_SHIELD = 39872, - SPELL_IMPALING_SPINE = 39837, - SPELL_CREATE_NAJENTUS_SPINE = 39956, - SPELL_HURL_SPINE = 39948, - SPELL_BERSERK = 26662 - + SPELL_NEEDLE_SPINE_TARGETING = 39992, + SPELL_NEEDLE_SPINE = 39835, + SPELL_TIDAL_BURST = 39878, + SPELL_TIDAL_SHIELD = 39872, + SPELL_IMPALING_SPINE = 39837, + SPELL_CREATE_NAJENTUS_SPINE = 39956, + SPELL_HURL_SPINE = 39948, + SPELL_BERSERK = 26662 }; enum Events { - EVENT_BERSERK = 1, - EVENT_YELL = 2, - EVENT_NEEDLE = 3, - EVENT_SPINE = 4, - EVENT_SHIELD = 5 + EVENT_BERSERK = 1, + EVENT_YELL = 2, + EVENT_NEEDLE = 3, + EVENT_SPINE = 4, + EVENT_SHIELD = 5 }; -class boss_najentus : public CreatureScript +enum Misc { -public: - boss_najentus() : CreatureScript("boss_najentus") { } + DATA_REMOVE_IMPALING_SPINE = 1, + ACTION_RESET_IMPALING_TARGET = 2 +}; - struct boss_najentusAI : public BossAI +struct boss_najentus : public BossAI +{ + boss_najentus(Creature* creature) : BossAI(creature, DATA_HIGH_WARLORD_NAJENTUS) { } + + void Reset() override { - boss_najentusAI(Creature* creature) : BossAI(creature, DATA_HIGH_WARLORD_NAJENTUS) { } - - void Reset() override - { - _Reset(); - SpineTargetGUID.Clear(); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - _DespawnAtEvade(); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - Talk(SAY_DEATH); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_HURL_SPINE && me->HasAura(SPELL_TIDAL_SHIELD)) - { - me->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); - DoCastSelf(SPELL_TIDAL_BURST, true); - events.RescheduleEvent(EVENT_SPINE, Seconds(2)); - } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_NEEDLE, Seconds(2)); - events.ScheduleEvent(EVENT_SHIELD, Seconds(60)); - events.ScheduleEvent(EVENT_SPINE, Seconds(30)); - events.ScheduleEvent(EVENT_BERSERK, Seconds(480)); - events.ScheduleEvent(EVENT_YELL, Seconds(45), Seconds(100)); - } - - bool RemoveImpalingSpine() - { - if (!SpineTargetGUID) - return false; - - Unit* target = ObjectAccessor::GetUnit(*me, SpineTargetGUID); - if (target && target->HasAura(SPELL_IMPALING_SPINE)) - target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); - SpineTargetGUID.Clear(); - return true; - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_SHIELD: - DoCastSelf(SPELL_TIDAL_SHIELD, true); - events.RescheduleEvent(EVENT_SPINE, Seconds(50)); - events.Repeat(Seconds(55), Seconds(60)); - break; - case EVENT_BERSERK: - Talk(SAY_ENRAGE); - DoCastSelf(SPELL_BERSERK, true); - break; - case EVENT_SPINE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200.0f, true)) - { - DoCast(target, SPELL_IMPALING_SPINE, true); - SpineTargetGUID = target->GetGUID(); - //must let target summon, otherwise you cannot click the spine - target->SummonGameObject(GO_NAJENTUS_SPINE, *target, QuaternionData(), 30); - Talk(SAY_NEEDLE); - } - events.Repeat(Seconds(20), Seconds(25)); - break; - case EVENT_NEEDLE: - DoCastSelf(SPELL_NEEDLE_SPINE_TARGETING, true); - events.Repeat(Seconds(2)); - break; - case EVENT_YELL: - Talk(SAY_SPECIAL); - events.Repeat(Seconds(25), Seconds(100)); - break; - default: - break; - } - } - - private: - ObjectGuid SpineTargetGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackTempleAI(creature); + _Reset(); + _spineTargetGUID.Clear(); } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + _DespawnAtEvade(); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_DEATH); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_HURL_SPINE && me->HasAura(SPELL_TIDAL_SHIELD)) + { + me->RemoveAurasDueToSpell(SPELL_TIDAL_SHIELD); + DoCastSelf(SPELL_TIDAL_BURST, true); + events.RescheduleEvent(EVENT_SPINE, Seconds(2)); + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_NEEDLE, 2s); + events.ScheduleEvent(EVENT_SHIELD, 1min); + events.ScheduleEvent(EVENT_SPINE, 30s); + events.ScheduleEvent(EVENT_BERSERK, 480s); + events.ScheduleEvent(EVENT_YELL, 45s, 100s); + } + + uint32 GetData(uint32 data) const override + { + if (data == DATA_REMOVE_IMPALING_SPINE) + return RemoveImpalingSpine() ? 1 : 0; + return 0; + } + + void DoAction(int32 actionId) override + { + if (actionId == ACTION_RESET_IMPALING_TARGET) + _spineTargetGUID.Clear(); + } + + bool RemoveImpalingSpine() const + { + if (!_spineTargetGUID) + return false; + + Unit* target = ObjectAccessor::GetUnit(*me, _spineTargetGUID); + if (target && target->HasAura(SPELL_IMPALING_SPINE)) + target->RemoveAurasDueToSpell(SPELL_IMPALING_SPINE); + return true; + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_SHIELD: + DoCastSelf(SPELL_TIDAL_SHIELD, true); + events.RescheduleEvent(EVENT_SPINE, Seconds(50)); + events.Repeat(Seconds(55), Seconds(60)); + break; + case EVENT_BERSERK: + Talk(SAY_ENRAGE); + DoCastSelf(SPELL_BERSERK, true); + break; + case EVENT_SPINE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200.0f, true)) + { + DoCast(target, SPELL_IMPALING_SPINE, true); + _spineTargetGUID = target->GetGUID(); + //must let target summon, otherwise you cannot click the spine + target->SummonGameObject(GO_NAJENTUS_SPINE, target->GetPosition(), QuaternionData(), 30 * IN_MILLISECONDS); + Talk(SAY_NEEDLE); + } + events.Repeat(Seconds(20), Seconds(25)); + break; + case EVENT_NEEDLE: + DoCastSelf(SPELL_NEEDLE_SPINE_TARGETING, true); + events.Repeat(Seconds(2)); + break; + case EVENT_YELL: + Talk(SAY_SPECIAL); + events.Repeat(Seconds(25), Seconds(100)); + break; + default: + break; + } + } + +private: + ObjectGuid _spineTargetGUID; }; -class go_najentus_spine : public GameObjectScript +struct go_najentus_spine : public GameObjectAI { - public: - go_najentus_spine() : GameObjectScript("go_najentus_spine") { } + go_najentus_spine(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { } - struct go_najentus_spineAI : public GameObjectAI - { - go_najentus_spineAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } + bool GossipHello(Player* player) override + { + if (!_instance) + return false; - InstanceScript* instance; - - bool GossipHello(Player* player) override + if (Creature* najentus = _instance->GetCreature(DATA_HIGH_WARLORD_NAJENTUS)) + if (najentus->AI()->GetData(DATA_REMOVE_IMPALING_SPINE)) { - if (Creature* najentus = instance->GetCreature(DATA_HIGH_WARLORD_NAJENTUS)) - { - if (ENSURE_AI(boss_najentus::boss_najentusAI, najentus->AI())->RemoveImpalingSpine()) - { - me->CastSpell(player, SPELL_CREATE_NAJENTUS_SPINE, true); - me->Delete(); - } - } - return true; + najentus->AI()->DoAction(ACTION_RESET_IMPALING_TARGET); + me->CastSpell(player, SPELL_CREATE_NAJENTUS_SPINE, true); + me->Delete(); } - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetBlackTempleAI(go); - } + return true; + } +private: + InstanceScript* _instance; }; // 39992 - Needle Spine Targeting -class spell_najentus_needle_spine : public SpellScriptLoader +class spell_najentus_needle_spine : public SpellScript { - public: - spell_najentus_needle_spine() : SpellScriptLoader("spell_najentus_needle_spine") { } + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_NEEDLE_SPINE }); + } - class spell_najentus_needle_spine_SpellScript : public SpellScript - { - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_NEEDLE_SPINE }); - } + void FilterTargets(std::list& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_IMPALING_SPINE)); + } - void FilterTargets(std::list& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_IMPALING_SPINE)); - } + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_NEEDLE_SPINE, true); + } - void HandleScript(SpellEffIndex /*effIndex*/) - { - GetCaster()->CastSpell(GetHitUnit(), SPELL_NEEDLE_SPINE, true); - } - - void Register() override - { - OnObjectAreaTargetSelect.Register(&spell_najentus_needle_spine_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget.Register(&spell_najentus_needle_spine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_najentus_needle_spine_SpellScript(); - } + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_najentus_needle_spine::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget.Register(&spell_najentus_needle_spine::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; void AddSC_boss_najentus() { - new boss_najentus(); - new go_najentus_spine(); - new spell_najentus_needle_spine(); + RegisterBlackTempleCreatureAI(boss_najentus); + RegisterGameObjectAI(go_najentus_spine); + RegisterSpellScript(spell_najentus_needle_spine); } diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index d647379888..c69478a51f 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -76,6 +76,7 @@ ObjectData const creatureData[] = { NPC_BLOOD_ELF_COUNCIL_VOICE, DATA_BLOOD_ELF_COUNCIL_VOICE }, { NPC_BLACK_TEMPLE_TRIGGER, DATA_BLACK_TEMPLE_TRIGGER }, { NPC_MAIEV_SHADOWSONG, DATA_MAIEV }, + { NPC_RELIQUARY_COMBAT_TRIGGER, DATA_RELIQUARY_COMBAT_TRIGGER }, { 0, 0 } // END };