diff --git a/sql/updates/world/4.3.4/2023_12_19_00_world.sql b/sql/updates/world/4.3.4/2023_12_19_00_world.sql new file mode 100644 index 0000000000..230b082aef --- /dev/null +++ b/sql/updates/world/4.3.4/2023_12_19_00_world.sql @@ -0,0 +1,118 @@ +SET @CGUID := 254934; +DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+26; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+26; +INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `PhaseId`, `PhaseGroup`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `VerifiedBuild`) VALUES +(@CGUID+0, 44797, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -353.178985595703125, -700.6669921875, 888.1903076171875, 5.532693862915039062, 7200, 0, 0, 4149700, 0, 0, 0, 0, 0, 15595), -- Time Warden (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86003 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+1, 44652, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -279.110992431640625, -680.593994140625, 888.1912841796875, 3.106686115264892578, 7200, 0, 0, 4149700, 0, 0, 0, 0, 0, 15595), -- Slate Dragon (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86003 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+2, 44650, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -318.704986572265625, -722.68798828125, 888.1912841796875, 3.193952560424804687, 7200, 0, 0, 4149700, 0, 0, 0, 0, 0, 15595), -- Storm Rider (Area: 0 - Difficulty: 1) CreateObject2 - !!! might be temporary spawn !!! +(@CGUID+3, 44645, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -280.118011474609375, -659.385009765625, 888.18829345703125, 1.675516128540039062, 7200, 0, 0, 4149700, 0, 0, 0, 0, 0, 15595), -- Nether Scion (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86003 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+4, 44687, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -265.8909912109375, -740.02301025390625, 907.36334228515625, 2.338741064071655273, 7200, 0, 0, 26143110, 0, 0, 0, 0, 0, 15595), -- Proto-Behemoth (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 83412 - Force Flying) - !!! might be temporary spawn !!! +(@CGUID+5, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -347.079986572265625, -728.12799072265625, 891.76434326171875, 1.117010712623596191, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+6, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -347.5780029296875, -717.302001953125, 891.7633056640625, 1.047197580337524414, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+7, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -340.75, -722.47601318359375, 891.76434326171875, 1.169370532035827636, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+8, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -350.563995361328125, -721.66302490234375, 891.7633056640625, 1.01229095458984375, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+9, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -346.433990478515625, -724.04901123046875, 891.76434326171875, 1.099557399749755859, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+10, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -350.571014404296875, -725.4169921875, 891.7633056640625, 1.064650893211364746, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+11, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -342.00201416015625, -726.52801513671875, 891.76434326171875, 1.169370532035827636, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+12, 44641, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -344.8389892578125, -720.16302490234375, 891.76434326171875, 1.082104086875915527, 7200, 0, 0, 414970, 0, 0, 0, 0, 0, 15595), -- Orphaned Emerald Whelp (Area: 0 - Difficulty: 1) CreateObject2 (Auras: 86022 - Unresponsive) - !!! might be temporary spawn !!! +(@CGUID+13, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -358.9639892578125, -702.14801025390625, 888.1903076171875, 2.30383467674255371, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+14, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -348.537994384765625, -700.24700927734375, 888.1903076171875, 5.532693862915039062, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+15, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -352.803985595703125, -695.06402587890625, 888.1903076171875, 5.358160972595214843, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+16, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -353.764007568359375, -706.36102294921875, 888.1903076171875, 2.30383467674255371, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+17, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -314.985992431640625, -717.39599609375, 888.1903076171875, 0.261799395084381103, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+18, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -277.954986572265625, -687.78802490234375, 888.19232177734375, 3.159045934677124023, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+19, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -273.010009765625, -684.6939697265625, 888.1912841796875, 3.159045934677124023, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+20, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -321.9739990234375, -718.42401123046875, 888.1912841796875, 0.383972436189651489, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 +(@CGUID+21, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -284.868011474609375, -661.1510009765625, 888.1903076171875, 1.710422635078430175, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+22, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -273.9219970703125, -675.947998046875, 888.1893310546875, 6.195918560028076171, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+23, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -283.141998291015625, -685.32501220703125, 888.1912841796875, 3.159045934677124023, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+24, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -280.7239990234375, -674.46002197265625, 888.1903076171875, 0.087266460061073303, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) +(@CGUID+25, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -320.157989501953125, -727.9949951171875, 888.1912841796875, 3.246312379837036132, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326), -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 +(@CGUID+26, 44765, 671, 5334, 5334, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, 0, 0, -274.890625, -656.8350830078125, 888.1893310546875, 4.956735134124755859, 7200, 0, 0, 4679, 0, 0, 0, 0, 0, 27326); -- Spike (Area: The Bastion of Twilight - Difficulty: 5) CreateObject1 (Auras: 83480 - Spike Visual) + +SET @OGUID := 211121; +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+1; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `PhaseId`, `PhaseGroup`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES +(@OGUID+0, 205088, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, -346.6719970703125, -723.260009765625, 888.10601806640625, 5.532694816589355468, 0, 0, -0.3665008544921875, 0.93041771650314331, 7200, 255, 1, 15595), -- Whelp Cage Base (Area: 0 - Difficulty: 1) CreateObject2 +(@OGUID+1, 205087, 671, 5334, 0, 0x1 | 0x2 | 0x4 | 0x8, 169, 0, -346.6719970703125, -723.260009765625, 888.10601806640625, 5.532694816589355468, 0, 0, -0.3665008544921875, 0.93041771650314331, 7200, 255, 1, 15595); -- Whelp Cage (Area: 0 - Difficulty: 1) CreateObject2 + +DELETE FROM `gameobject_addon` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+1; + +DELETE FROM `spawn_group_template` WHERE `groupId`= 462; +INSERT INTO `spawn_group_template` (`groupId`, `groupName`, `groupFlags`) VALUES +(462, 'Bastion of Twilight - Halfus Wyrmbreaker Encounter Setup', 4); + +DELETE FROM `spawn_group` WHERE `groupId`= 462; +INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES +(462, 0, @CGUID+0), +(462, 0, @CGUID+1), +(462, 0, @CGUID+2), +(462, 0, @CGUID+3), +(462, 0, @CGUID+4), +(462, 0, @CGUID+5), +(462, 0, @CGUID+6), +(462, 0, @CGUID+7), +(462, 0, @CGUID+8), +(462, 0, @CGUID+9), +(462, 0, @CGUID+10), +(462, 0, @CGUID+11), +(462, 0, @CGUID+12), +(462, 0, @CGUID+13), +(462, 0, @CGUID+14), +(462, 0, @CGUID+15), +(462, 0, @CGUID+16), +(462, 0, @CGUID+17), +(462, 0, @CGUID+18), +(462, 0, @CGUID+19), +(462, 0, @CGUID+20), +(462, 0, @CGUID+21), +(462, 0, @CGUID+22), +(462, 0, @CGUID+23), +(462, 0, @CGUID+24), +(462, 0, @CGUID+25), +(462, 0, @CGUID+26), +(462, 0, 253808), +(462, 0, 253815), +(462, 0, 253820), +(462, 0, 253821), +(462, 0, 253861), +(462, 0, 253863), +(462, 0, 253864), +(462, 0, 253866), +(462, 0, 253868), +(462, 0, 253869), +(462, 0, 253871), +(462, 0, 253874), +(462, 0, 253876), +(462, 0, 253878), +(462, 1, @OGUID+0), +(462, 1, @OGUID+1); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_halfus_unresponsive', 'spell_halfus_fireball', 'spell_halfus_fireball_barrage'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(86003, 'spell_halfus_unresponsive'), +(86022, 'spell_halfus_unresponsive'), +(86058, 'spell_halfus_fireball'), +(83862, 'spell_halfus_fireball'), +(83719, 'spell_halfus_fireball_barrage'); + +UPDATE `creature_template` SET `npcflag`= 0x1000000 WHERE `entry` IN (44653, 46221, 46222, 46223, 44826, 46218, 46219, 46220, 44828, 46212, 46213, 46214, 44829, 46215, 46216, 46217); + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (44653, 46221, 46222, 46223, 44826, 46218, 46219, 46220, 44828, 46212, 46213, 46214, 44829, 46215, 46216, 46217); +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(44653, 83447, 1, 1), +(46221, 83447, 1, 1), +(46222, 83447, 1, 1), +(46223, 83447, 1, 1), +(44826, 83591, 1, 1), +(46218, 83591, 1, 1), +(46219, 83591, 1, 1), +(46220, 83591, 1, 1), +(44828, 83589, 1, 1), +(46212, 83589, 1, 1), +(46213, 83589, 1, 1), +(46214, 83589, 1, 1), +(44829, 83590, 1, 1), +(46215, 83590, 1, 1), +(46216, 83590, 1, 1), +(46217, 83590, 1, 1); diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h index c983e6065b..227a5607a2 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h @@ -63,11 +63,12 @@ enum BoTDataTypes // Encounter Related /*Halfus Wyrmbreaker*/ - DATA_UNRESPONSIVE_DRAGON_FIRST, - DATA_UNRESPONSIVE_DRAGON_SECOND, - DATA_CAST_DRAGON_BUFFS, - DATA_DRAGON_CAGE_ENABLED, - DATA_OPEN_ORPHANED_EMERALD_WHELP_CAGE, + DATA_ACTIVE_DRAGON_FLAGS, + DATA_SLATE_DRAGON, + DATA_NETHER_SCION, + DATA_STORM_RIDER, + DATA_TIME_WARDEN, + DATA_WHELP_CAGE, /*Theralion and Valiona*/ DATA_RANDOM_VALIONA_DUMMY, @@ -78,12 +79,6 @@ enum BoTDataTypes DATA_FULL_HEROIC_ID }; -enum BoTDataStates -{ - DRAGON_BUFFS_HALFUS_WYRMBREAKER = 0, - DRAGON_BUFFS_PROTO_BEHEMOTH, -}; - enum BoTCreatures { // Bosses @@ -160,13 +155,7 @@ enum BoTGameObjects enum BoTActions { // Halfus Wyrmbreaker - ACTION_ENABLE_MALEVOLENT_STRIKES = 1, - ACTION_ENABLE_FRENZIED_ASSAULT = 2, - ACTION_ENABLE_SHADOW_NOVA = 3, - ACTION_ENABLE_FIREBALL_BARRAGE = 1, - ACTION_ENABLE_SCORCHING_BREATH = 2, - ACTION_CAST_DRAGONS_VENGEANCE = 3, - ACTION_MOVE_OUT_OF_CAGE = 4, + ACTION_DRAGON_FREED = 0, // Theralion and Valiona ACTION_START_ARGUMENT_INTRO = 1, @@ -208,6 +197,17 @@ enum BoTWorldStates WORLD_STATE_ID_THE_ABYSS_WILL_GAZE_BACK_INTO_YOU = 5659 }; +enum BoTHalfusDragonFlags : uint8 +{ + DRAGON_FLAG_NETHER_SCION = 0x01, + DRAGON_FLAG_SLATE_DRAGON = 0x02, + DRAGON_FLAG_STORM_RIDER = 0x04, + DRAGON_FLAG_TIME_WARDEN = 0x08, + DRAGON_FLAG_EMERALD_WHELPS = 0x10, + + DRAGON_FLAG_ALL_ACTIVE = DRAGON_FLAG_NETHER_SCION | DRAGON_FLAG_SLATE_DRAGON | DRAGON_FLAG_STORM_RIDER | DRAGON_FLAG_TIME_WARDEN | DRAGON_FLAG_EMERALD_WHELPS +}; + template AI* GetBastionOfTwilightAI(Creature* creature) { diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_halfus_wyrmbreaker.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_halfus_wyrmbreaker.cpp index 118b616667..e66c65d7cd 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_halfus_wyrmbreaker.cpp +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_halfus_wyrmbreaker.cpp @@ -48,6 +48,7 @@ enum Spells SPELL_DANCING_FLAMES = 84106, SPELL_SUPERHEATED_BREATH = 83956, SPELL_FIREBALL = 86058, + SPELL_FIREBALL_SLOW = 83862, SPELL_FIREBALL_BARRAGE = 83706, SPELL_FIREBALL_BARRAGE_FAST = 83720, SPELL_FIREBALL_BARRAGE_SLOW = 83733, @@ -69,7 +70,7 @@ enum Events // Halfus Wyrmbreaker EVENT_SHADOW_NOVA = 1, EVENT_FURIOUS_ROAR, - EVENT_RESET_ACHIEVEMT, + EVENT_RESET_ACHIEVEMENT, EVENT_BERSERK, // Proto-Behemoth @@ -81,7 +82,13 @@ enum Events EVENT_LIFTOFF, EVENT_CAST_DEBUFF, EVENT_BIND_TO_HALFUS_WILL, - EVENT_MOVE_OUT_OF_CAGE + EVENT_MOVE_OUT_OF_CAGE, + EVENT_ENGAGE_WITH_PLAYERS +}; + +enum Actions +{ + ACTION_ORPHANED_EMERALD_WHELP_KILLED = 0, }; enum Texts @@ -93,47 +100,26 @@ enum Texts SAY_ANNOUNCE_FURIOUS_ROAR = 3 }; -Position const SpikePositions[] = +enum SpawnGroups { - { -348.538f, -700.247f, 888.19f, 5.53269f }, - { -353.764f, -706.361f, 888.19f, 2.30383f }, - { -352.804f, -695.064f, 888.19f, 5.35816f }, - { -358.964f, -702.148f, 888.19f, 2.30383f }, - { -320.158f, -727.995f, 888.191f, 3.24631f }, - { -274.891f, -656.835f, 888.189f, 4.95674f }, - { -284.868f, -661.151f, 888.19f, 1.71042f }, - { -277.955f, -687.788f, 888.192f, 3.15905f }, - { -314.986f, -717.396f, 888.19f, 0.261799f }, - { -280.724f, -674.46f, 888.19f, 0.0872665f }, - { -273.922f, -675.948f, 888.189f, 6.19592f }, - { -283.142f, -685.325f, 888.191f, 3.15905f }, - { -321.974f, -718.424f, 888.191f, 0.383972f }, - { -273.01f, -684.694f, 888.191f, 3.15905f } + SPAWN_GROUP_ID_ENCOUNTER_SETUP = 462 }; -Position const OrphanedEmeraldWhelpPositions[] = +struct EncounterDragonData { - { -342.002f, -726.528f, 891.764f, 1.16937f }, - { -340.75f, -722.476f, 891.764f, 1.16937f }, - { -350.564f, -721.663f, 891.763f, 1.01229f }, - { -347.08f, -728.128f, 891.764f, 1.11701f }, - { -346.434f, -724.049f, 891.764f, 1.09956f }, - { -347.578f, -717.302f, 891.763f, 1.0472f }, - { -350.571f, -725.417f, 891.763f, 1.06465f }, - { -344.839f, -720.163f, 891.764f, 1.0821f } + uint32 DataType = 0; + uint32 EncounterCreatureId = 0; }; -Position const NetherScionPos = { -280.118f, -659.385f, 888.188f, 1.67552f }; -Position const SlateDragonPos = { -279.111f, -680.594f, 888.191f, 3.10669f }; -Position const StormRiderPos = { -318.705f, -722.688f, 888.191f, 3.19395f }; -Position const TimeWardenPos = { -353.179f, -700.667f, 888.19f, 5.53269f }; -Position const ProtoBehemothPos = { -265.891f, -740.023f, 907.363f, 2.33874f }; +static constexpr std::array const DragonData = +{ + EncounterDragonData(DATA_SLATE_DRAGON, NPC_SLATE_DRAGON_ENCOUNTER), + EncounterDragonData(DATA_NETHER_SCION, NPC_NETHER_SCION_ENCOUNTER), + EncounterDragonData(DATA_STORM_RIDER, NPC_STORM_RIDER_ENCOUNTER), + EncounterDragonData(DATA_TIME_WARDEN, NPC_TIME_WARDEN_ENCOUNTER) +}; -Position const WhelpCageBasePos = { -346.672f, -723.26f, 888.106f, 5.53269f }; -QuaternionData const WhelpCageBaseRot = QuaternionData(0.0f, 0.0f, -0.366501f, 0.930418f); - -Position const WhelpCagePos = { -346.672f, -723.26f, 888.106f, 5.53269f }; -QuaternionData const WhelpCageRot = QuaternionData(0.0f, 0.0f, -0.366501f, 0.930418f); +static constexpr uint8 OrphanedEmeraldWhelpPackSize = 8; struct boss_halfus_wyrmbreaker final : public BossAI { @@ -142,29 +128,17 @@ struct boss_halfus_wyrmbreaker final : public BossAI void JustAppeared() override { - instance->SetData(DATA_CAST_DRAGON_BUFFS, DRAGON_BUFFS_HALFUS_WYRMBREAKER); + uint8 activeDragonFlags = static_cast(instance->GetData(DATA_ACTIVE_DRAGON_FLAGS)); + if ((activeDragonFlags & DRAGON_FLAG_SLATE_DRAGON) != 0) + DoCastSelf(SPELL_MALEVOLENT_STRIKES); - if (GameObject* cageBase = me->SummonGameObject(GO_WHELP_CAGE_BASE, WhelpCageBasePos, WhelpCageBaseRot, WEEK, GO_SUMMON_TIMED_DESPAWN)) - _cageBaseGUID = cageBase->GetGUID(); + if ((activeDragonFlags & DRAGON_FLAG_NETHER_SCION) != 0) + DoCastSelf(SPELL_FRENZIED_ASSAULT); - if (GameObject* cage = me->SummonGameObject(GO_WHELP_CAGE, WhelpCagePos, WhelpCageRot, WEEK, GO_SUMMON_TIMED_DESPAWN)) - _cageGUID = cage->GetGUID(); + if ((activeDragonFlags & DRAGON_FLAG_STORM_RIDER) != 0) + DoCastSelf(SPELL_SHADOW_WRAPPED); - if (Map* map = me->GetMap()) - { - map->SummonCreature(NPC_NETHER_SCION, NetherScionPos); - map->SummonCreature(NPC_SLATE_DRAGON, SlateDragonPos); - map->SummonCreature(NPC_STORM_RIDER, StormRiderPos); - map->SummonCreature(NPC_TIME_WARDEN, TimeWardenPos); - } - - for (uint8 i = 0; i < 8; i++) - DoSummon(NPC_ORPHANED_EMERALD_WELP, OrphanedEmeraldWhelpPositions[i]); - - for (uint8 i = 0; i < 14; i++) - DoSummon(NPC_SPIKE, SpikePositions[i]); - - DoSummon(NPC_PROTO_BEHEMOTH, ProtoBehemothPos); + instance->instance->SpawnGroupSpawn(SPAWN_GROUP_ID_ENCOUNTER_SETUP, true); } void JustEngagedWith(Unit* who) override @@ -176,19 +150,24 @@ struct boss_halfus_wyrmbreaker final : public BossAI events.ScheduleEvent(EVENT_BERSERK, 10min); if (Creature* protoBehemoth = instance->GetCreature(DATA_PROTO_BEHEMOTH)) - protoBehemoth->AI()->DoZoneInCombat(); + DoZoneInCombat(protoBehemoth); - if (instance->GetData(DATA_DRAGON_CAGE_ENABLED)) - if (GameObject* cage = ObjectAccessor::GetGameObject(*me, _cageGUID)) + for (EncounterDragonData const& dragonData : DragonData) + if (Creature* dragon = instance->GetCreature(dragonData.DataType)) + if (dragon->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) + dragon->UpdateEntry(dragonData.EncounterCreatureId); + + if ((static_cast(instance->GetData(DATA_ACTIVE_DRAGON_FLAGS) & DRAGON_FLAG_EMERALD_WHELPS) != 0)) + if (GameObject* cage = instance->GetGameObject(DATA_WHELP_CAGE)) cage->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); if (me->HasAura(SPELL_SHADOW_WRAPPED)) - events.ScheduleEvent(EVENT_SHADOW_NOVA, Seconds(7)); + events.ScheduleEvent(EVENT_SHADOW_NOVA, 7s); } void KilledUnit(Unit* victim) override { - if (victim->GetTypeId() == TYPEID_PLAYER) + if (victim->IsPlayer()) Talk(SAY_SLAY); } @@ -196,12 +175,7 @@ struct boss_halfus_wyrmbreaker final : public BossAI { _JustDied(); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - - if (GameObject* cage = ObjectAccessor::GetGameObject(*me, _cageGUID)) - cage->DespawnOrUnsummon(); - - if (GameObject* cageBase = ObjectAccessor::GetGameObject(*me, _cageBaseGUID)) - cageBase->DespawnOrUnsummon(); + instance->instance->SpawnGroupDespawn(SPAWN_GROUP_ID_ENCOUNTER_SETUP); } void EnterEvadeMode(EvadeReason /*why*/) override @@ -209,13 +183,7 @@ struct boss_halfus_wyrmbreaker final : public BossAI _EnterEvadeMode(); summons.DespawnAll(); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - - if (GameObject* cage = ObjectAccessor::GetGameObject(*me, _cageGUID)) - cage->DespawnOrUnsummon(); - - if (GameObject* cageBase = ObjectAccessor::GetGameObject(*me, _cageBaseGUID)) - cageBase->DespawnOrUnsummon(); - + instance->instance->SpawnGroupDespawn(SPAWN_GROUP_ID_ENCOUNTER_SETUP); _DespawnAtEvade(); } @@ -240,13 +208,13 @@ struct boss_halfus_wyrmbreaker final : public BossAI { _theOnlyEscapeAchievementState = IN_PROGRESS; instance->DoUpdateWorldState(WORLD_STATE_ID_THE_ONLY_ESCAPE, 1); - events.ScheduleEvent(EVENT_RESET_ACHIEVEMT, Seconds(10)); + events.ScheduleEvent(EVENT_RESET_ACHIEVEMENT, 10s); } else if (_theOnlyEscapeAchievementState == IN_PROGRESS) { _theOnlyEscapeAchievementState = DONE; instance->DoUpdateWorldState(WORLD_STATE_ID_THE_ONLY_ESCAPE, 2); - events.CancelEvent(EVENT_RESET_ACHIEVEMT); + events.CancelEvent(EVENT_RESET_ACHIEVEMENT); } break; default: @@ -263,24 +231,6 @@ struct boss_halfus_wyrmbreaker final : public BossAI } } - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_ENABLE_MALEVOLENT_STRIKES: - me->AddAura(SPELL_MALEVOLENT_STRIKES, me); - break; - case ACTION_ENABLE_FRENZIED_ASSAULT: - me->AddAura(SPELL_FRENZIED_ASSAULT, me); - break; - case ACTION_ENABLE_SHADOW_NOVA: - me->AddAura(SPELL_SHADOW_WRAPPED, me); - break; - default: - break; - } - } - void UpdateAI(uint32 diff) override { if (!UpdateVictim()) @@ -316,7 +266,7 @@ struct boss_halfus_wyrmbreaker final : public BossAI _furiousRoarCount = 0; } break; - case EVENT_RESET_ACHIEVEMT: + case EVENT_RESET_ACHIEVEMENT: _theOnlyEscapeAchievementState = NOT_STARTED; break; case EVENT_BERSERK: @@ -331,8 +281,6 @@ struct boss_halfus_wyrmbreaker final : public BossAI } private: - ObjectGuid _cageGUID; - ObjectGuid _cageBaseGUID; bool _announcedOrphanedEmeraldWhelpBinding; bool _furiousRoarEnabled; uint8 _theOnlyEscapeAchievementState; @@ -341,36 +289,45 @@ private: struct npc_halfus_proto_behemoth final : public PassiveAI { - npc_halfus_proto_behemoth(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) {} + npc_halfus_proto_behemoth(Creature* creature) : PassiveAI(creature), _instance(nullptr), _killedEmeraldWhelps(0) { } + + void InitializeAI() override + { + _instance = me->GetInstanceScript(); + } + + void JustAppeared() override + { + uint8 activeDragonFlags = static_cast(_instance->GetData(DATA_ACTIVE_DRAGON_FLAGS)); + if ((activeDragonFlags & DRAGON_FLAG_EMERALD_WHELPS) != 0) + DoCastSelf(SPELL_SUPERHEATED_BREATH); + + if ((activeDragonFlags & DRAGON_FLAG_TIME_WARDEN) != 0) + DoCastSelf(SPELL_DANCING_FLAMES); + } void JustEngagedWith(Unit* /*who*/) override { _events.ScheduleEvent(EVENT_FIREBALL, 1s); if (me->HasAura(SPELL_DANCING_FLAMES)) + { _events.ScheduleEvent(EVENT_FIREBALL_BARRAGE, 13s); - - if (me->HasAura(SPELL_SUPERHEATED_BREATH)) - _events.ScheduleEvent(EVENT_SCORCHING_BREATH, 24s); - } - - void JustAppeared() override - { - _instance->SetData(DATA_CAST_DRAGON_BUFFS, DRAGON_BUFFS_PROTO_BEHEMOTH); + if (me->HasAura(SPELL_SUPERHEATED_BREATH)) + _events.ScheduleEvent(EVENT_SCORCHING_BREATH, 24s); + } + else if (me->HasAura(SPELL_SUPERHEATED_BREATH)) + _events.ScheduleEvent(EVENT_SCORCHING_BREATH, 13s); } void DoAction(int32 action) override { switch (action) { - case ACTION_CAST_DRAGONS_VENGEANCE: - DoCastSelf(SPELL_DRAGONS_VENGEANCE, true); - break; - case ACTION_ENABLE_SCORCHING_BREATH: - me->AddAura(SPELL_SUPERHEATED_BREATH, me); - break; - case ACTION_ENABLE_FIREBALL_BARRAGE: - me->AddAura(SPELL_DANCING_FLAMES, me); + case ACTION_ORPHANED_EMERALD_WHELP_KILLED: + ++_killedEmeraldWhelps; + if (_killedEmeraldWhelps == OrphanedEmeraldWhelpPackSize) + DoCastAOE(SPELL_DRAGONS_VENGEANCE, true); break; default: break; @@ -389,16 +346,26 @@ struct npc_halfus_proto_behemoth final : public PassiveAI switch (eventId) { case EVENT_FIREBALL: - DoCastAOE(SPELL_FIREBALL); - _events.Repeat(2s + 500ms); + if (!me->HasAura(SPELL_TIME_DILATION)) + { + DoCastAOE(SPELL_FIREBALL, CastSpellExtraArgs().AddSpellMod(SPELLVALUE_MAX_TARGETS, 1)); + _events.Repeat(2s + 500ms); + } + else + { + DoCastAOE(SPELL_FIREBALL_SLOW, CastSpellExtraArgs().AddSpellMod(SPELLVALUE_MAX_TARGETS, 1)); + _events.Repeat(3s + 500ms); + } break; case EVENT_FIREBALL_BARRAGE: DoCastSelf(SPELL_FIREBALL_BARRAGE); _events.Repeat(31s); + _events.RescheduleEvent(EVENT_FIREBALL, 11s); break; case EVENT_SCORCHING_BREATH: DoCastSelf(SPELL_SCORCHING_BREATH); _events.Repeat(31s); + _events.RescheduleEvent(EVENT_FIREBALL, 11s); break; default: break; @@ -409,25 +376,19 @@ struct npc_halfus_proto_behemoth final : public PassiveAI private: EventMap _events; InstanceScript* _instance; + uint8 _killedEmeraldWhelps; }; struct npc_halfus_enslaved_dragon final : public ScriptedAI { - npc_halfus_enslaved_dragon(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) {} + npc_halfus_enslaved_dragon(Creature* creature) : ScriptedAI(creature), _instance(nullptr) { } - void Reset() override + void InitializeAI() override { - _events.Reset(); - - if (_instance->GetData(DATA_UNRESPONSIVE_DRAGON_FIRST) == me->GetEntry() - || _instance->GetData(DATA_UNRESPONSIVE_DRAGON_SECOND) == me->GetEntry()) - { - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - if (me->GetEntry() == NPC_ORPHANED_EMERALD_WELP) - DoCastSelf(SPELL_UNRESPONSIVE_WHELP, true); - else - DoCastSelf(SPELL_UNRESPONSIVE_DRAGON, true); - } + _instance = me->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + if (isUnresponsive()) + DoCastSelf(me->GetEntry() != NPC_ORPHANED_EMERALD_WELP ? SPELL_UNRESPONSIVE_DRAGON : SPELL_UNRESPONSIVE_WHELP); } void JustDied(Unit* /*killer*/) override @@ -436,28 +397,35 @@ struct npc_halfus_enslaved_dragon final : public ScriptedAI me->SendSetPlayHoverAnim(false); me->DespawnOrUnsummon(6s); - if (me->GetEntry() != NPC_ORPHANED_EMERALD_WELP) - if (Creature* protoBehemoth = _instance->GetCreature(DATA_PROTO_BEHEMOTH)) - protoBehemoth->AI()->DoAction(ACTION_CAST_DRAGONS_VENGEANCE); - } - - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spell) override - { - if (spell->HasEffect(SPELL_EFFECT_SEND_EVENT)) + if (Creature* protoBehemoth = _instance->GetCreature(DATA_PROTO_BEHEMOTH)) { - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - me->RemoveAllAuras(); - _events.ScheduleEvent(EVENT_LIFTOFF, 1ms); + if (me->GetOriginalEntry() != NPC_ORPHANED_EMERALD_WELP) + protoBehemoth->CastSpell(nullptr, SPELL_DRAGONS_VENGEANCE, true); + else if (CreatureAI* ai = protoBehemoth->AI()) + ai->DoAction(ACTION_ORPHANED_EMERALD_WHELP_KILLED); } - else if (spell->Id == SPELL_BIND_WILL_TRIGGERED) - if (Player* player = me->SelectNearestPlayer(100.0f)) - me->AI()->AttackStart(player); } void DoAction(int32 action) override { - if (action == ACTION_MOVE_OUT_OF_CAGE) - _events.ScheduleEvent(EVENT_MOVE_OUT_OF_CAGE, 250ms); + switch (action) + { + case ACTION_DRAGON_FREED: + if (me->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + me->RemoveAllAuras(); + _events.ScheduleEvent(EVENT_LIFTOFF, 1ms); + } + else if (me->GetEntry() == NPC_ORPHANED_EMERALD_WELP && me->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + _events.ScheduleEvent(EVENT_MOVE_OUT_OF_CAGE, 1ms); + } + break; + default: + break; + } } void UpdateAI(uint32 diff) override @@ -475,20 +443,21 @@ struct npc_halfus_enslaved_dragon final : public ScriptedAI { case EVENT_LIFTOFF: { - Position pos = me->GetPosition(); - pos.m_positionZ += 5.5f; - me->GetMotionMaster()->MoveTakeoff(0, pos); - _events.ScheduleEvent(EVENT_CAST_DEBUFF, 1s + 800ms); + Position const pos = Position(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.5f, me->GetOrientation()); + me->GetMotionMaster()->MoveTakeoff(0, pos, 4.f); + me->SetDisableGravity(true); + me->SetHover(true); + _events.ScheduleEvent(EVENT_CAST_DEBUFF, 2s + 500ms); break; } case EVENT_MOVE_OUT_OF_CAGE: { float angle = me->GetOrientation(); - float x = me->GetPositionX() + cos(angle) * 20.0f; - float y = me->GetPositionY() + sin(angle) * 20.0f; + float x = me->GetPositionX() + std::cos(angle) * 20.f; + float y = me->GetPositionY() + std::sin(angle) * 20.f; float z = 888.1f; - me->GetMotionMaster()->MovePoint(0, x, y, z, true); - _events.ScheduleEvent(EVENT_CAST_DEBUFF, 2s + 600ms); + me->GetMotionMaster()->MovePoint(0, x, y, z); + _events.ScheduleEvent(EVENT_CAST_DEBUFF, 2s + 500ms); break; } case EVENT_CAST_DEBUFF: @@ -499,43 +468,43 @@ struct npc_halfus_enslaved_dragon final : public ScriptedAI if (!halfus || !protoBehemoth) break; - if (me->GetEntry() != NPC_ORPHANED_EMERALD_WELP) - { - me->SetDisableGravity(true); - me->SetHover(true); - } - switch (me->GetEntry()) { case NPC_NETHER_SCION_ENCOUNTER: me->SetFacingToObject(halfus); - DoCastSelf(SPELL_NETHER_BLINDNESS, true); + DoCastSelf(SPELL_NETHER_BLINDNESS); break; case NPC_SLATE_DRAGON_ENCOUNTER: me->SetFacingToObject(halfus); - DoCastSelf(SPELL_STONE_TOUCH, true); + DoCastSelf(SPELL_STONE_TOUCH); break; case NPC_STORM_RIDER_ENCOUNTER: me->SetFacingToObject(halfus); - DoCastSelf(SPELL_CYCLONE_WINDS, true); + DoCastSelf(SPELL_CYCLONE_WINDS); break; case NPC_TIME_WARDEN_ENCOUNTER: me->SetFacingToObject(protoBehemoth); - DoCastSelf(SPELL_TIME_DILATION, true); + DoCastSelf(SPELL_TIME_DILATION); break; case NPC_ORPHANED_EMERALD_WELP: me->SetFacingToObject(protoBehemoth); - DoCastSelf(SPELL_ATROPHIC_POISON, true); + DoCastSelf(SPELL_ATROPHIC_POISON); break; default: break; } - _events.ScheduleEvent(EVENT_BIND_TO_HALFUS_WILL, 1s + 850ms); + _events.ScheduleEvent(EVENT_BIND_TO_HALFUS_WILL, 2s); break; } case EVENT_BIND_TO_HALFUS_WILL: - if (_instance->GetCreature(DATA_HALFUS_WYRMBREAKER)) - DoCastSelf(SPELL_BIND_WILL, true); + DoCastSelf(SPELL_BIND_WILL); + _events.ScheduleEvent(EVENT_ENGAGE_WITH_PLAYERS, 1s); + break; + case EVENT_ENGAGE_WITH_PLAYERS: + me->SetReactState(REACT_AGGRESSIVE); + if (!me->IsEngaged()) + if (Unit* target = me->SelectNearestTarget(100.f)) + me->EngageWithTarget(target); break; default: break; @@ -547,6 +516,27 @@ struct npc_halfus_enslaved_dragon final : public ScriptedAI private: EventMap _events; InstanceScript* _instance; + + bool isUnresponsive() + { + uint8 activeDragonFlags = static_cast(_instance->GetData(DATA_ACTIVE_DRAGON_FLAGS)); + if (me->GetEntry() == NPC_SLATE_DRAGON && (activeDragonFlags & DRAGON_FLAG_SLATE_DRAGON) == 0) + return true; + + if (me->GetEntry() == NPC_NETHER_SCION && (activeDragonFlags & DRAGON_FLAG_NETHER_SCION) == 0) + return true; + + if (me->GetEntry() == NPC_STORM_RIDER && (activeDragonFlags & DRAGON_FLAG_STORM_RIDER) == 0) + return true; + + if (me->GetEntry() == NPC_TIME_WARDEN && (activeDragonFlags & DRAGON_FLAG_TIME_WARDEN) == 0) + return true; + + if (me->GetEntry() == NPC_ORPHANED_EMERALD_WELP && (activeDragonFlags & DRAGON_FLAG_EMERALD_WHELPS) == 0) + return true; + + return false; + } }; struct go_halfus_whelp_cage final : public GameObjectAI @@ -555,8 +545,18 @@ struct go_halfus_whelp_cage final : public GameObjectAI bool OnReportUse(Player* /*player*/) override { + if (me->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE)) + return true; + me->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - _instance->SetData(DATA_OPEN_ORPHANED_EMERALD_WHELP_CAGE, DONE); + + // There is no event linked to releasing the whelps so we have to resort to grid searching. + std::vector whelpVector; + me->GetCreatureListWithEntryInGrid(whelpVector, NPC_ORPHANED_EMERALD_WELP, 20.f); + for (Creature* whelp : whelpVector) + if (CreatureAI* ai = whelp->AI()) + ai->DoAction(ACTION_DRAGON_FREED); + return true; } @@ -584,35 +584,51 @@ class spell_halfus_fireball final : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_FIREBALL_BARRAGE_FAST, - SPELL_FIREBALL_BARRAGE_SLOW - }); - } - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - Trinity::Containers::RandomResize(targets, 1); - } - - void HandleHit(SpellEffIndex /*effIndex*/) - { - if (Unit* caster = GetCaster()) { - if (!caster->HasAura(SPELL_TIME_DILATION)) - caster->CastSpell(GetHitUnit(), SPELL_FIREBALL_BARRAGE_FAST, true); - else - caster->CastSpell(GetHitUnit(), SPELL_FIREBALL_BARRAGE_SLOW, true); - } + SPELL_FIREBALL_SLOW, + SPELL_FIREBALL_BARRAGE_FAST, + SPELL_FIREBALL_BARRAGE_SLOW + }); + } + + void HandleDummyEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), GetSpellInfo()->Id == SPELL_FIREBALL_SLOW ? SPELL_FIREBALL_BARRAGE_SLOW : SPELL_FIREBALL_BARRAGE_FAST, true); } void Register() override { - OnObjectAreaTargetSelect.Register(&spell_halfus_fireball::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); - OnEffectHitTarget.Register(&spell_halfus_fireball::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget.Register(&spell_halfus_fireball::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_halfus_fireball_barrage final : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_FIREBALL_BARRAGE_FAST, + SPELL_FIREBALL_BARRAGE_SLOW, + SPELL_TIME_DILATION + }); + } + + void FilterTargets(std::list& targets) + { + if (targets.size() > 1) + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleDummyEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), GetCaster()->HasAura(SPELL_TIME_DILATION) ? SPELL_FIREBALL_BARRAGE_SLOW : SPELL_FIREBALL_BARRAGE_FAST, true); + } + + void Register() override + { + OnObjectAreaTargetSelect.Register(&spell_halfus_fireball_barrage::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + OnEffectHitTarget.Register(&spell_halfus_fireball_barrage::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -657,33 +673,17 @@ class spell_halfus_cyclone_winds final : public SpellScript } }; -class DancingFlamesDistanceCheck -{ - public: - DancingFlamesDistanceCheck(Unit* caster) : _caster(caster) { } - - bool operator()(WorldObject* object) - { - return (object->GetDistance2d(_caster) <= 40.0f || object->GetDistance2d(_caster) >= 100.0f); - } - private: - Unit* _caster; -}; - class spell_halfus_dancing_flames final : public SpellScript { void FilterTargets(std::list& targets) { - if (targets.empty()) + if (targets.size() < 1) return; - if (Unit* caster = GetCaster()) - targets.remove_if(DancingFlamesDistanceCheck(caster)); + targets.remove_if([caster = GetCaster()](WorldObject const* target) { return (target->GetDistance2d(caster) <= 40.0f || target->GetDistance2d(caster) >= 100.0f); }); - if (targets.empty()) - return; - - Trinity::Containers::RandomResize(targets, 1); + if (targets.size() > 1) + Trinity::Containers::RandomResize(targets, 1); } void Register() override @@ -691,6 +691,20 @@ class spell_halfus_dancing_flames final : public SpellScript OnObjectAreaTargetSelect.Register(&spell_halfus_dancing_flames::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); } }; + +class spell_halfus_unresponsive final : public SpellScript +{ + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (GetHitUnit()->IsCreature()) + GetHitUnit()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void Register() override + { + OnEffectHitTarget.Register(&spell_halfus_unresponsive::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; } void AddSC_boss_halfus_wyrmbreaker() @@ -703,7 +717,9 @@ void AddSC_boss_halfus_wyrmbreaker() RegisterGameObjectAI(go_halfus_whelp_cage); RegisterSpellScript(spell_halfus_bind_will); RegisterSpellScript(spell_halfus_fireball); + RegisterSpellScript(spell_halfus_fireball_barrage); RegisterSpellScript(spell_halfus_stone_touch); RegisterSpellScript(spell_halfus_cyclone_winds); RegisterSpellScript(spell_halfus_dancing_flames); + RegisterSpellScript(spell_halfus_unresponsive); } diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp index f575eb4b45..739cf256af 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "CreatureAI.h" +#include "Containers.h" #include "bastion_of_twilight.h" #include "GameObject.h" #include "InstanceScript.h" @@ -39,6 +40,10 @@ ObjectData const creatureData[] = { BOSS_CHOGALL, DATA_CHOGALL }, { BOSS_SINESTRA, DATA_SINESTRA }, { NPC_PROTO_BEHEMOTH, DATA_PROTO_BEHEMOTH }, + { NPC_SLATE_DRAGON, DATA_SLATE_DRAGON }, + { NPC_NETHER_SCION, DATA_NETHER_SCION }, + { NPC_STORM_RIDER, DATA_STORM_RIDER }, + { NPC_TIME_WARDEN, DATA_TIME_WARDEN }, { NPC_ASCENDANT_COUNCIL_CONTROLLER, DATA_ASCENDANT_COUNCIL_CONTROLLER }, { NPC_CORRUPTION, DATA_CORRUPTION }, { NPC_CHOGALL, DATA_CHOGALL_EVENT }, @@ -48,6 +53,7 @@ ObjectData const creatureData[] = ObjectData const gameobjectData[] = { { GO_GRIM_BATOL_RAID_TRAP_DOOR, DATA_GRIM_BATOL_RAID_TRAP_DOOR }, + { GO_WHELP_CAGE, DATA_WHELP_CAGE }, { 0, 0 } // END }; @@ -63,13 +69,12 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } // END }; -uint32 HalfusDragonEntries[] = +enum MapEvents { - NPC_NETHER_SCION, - NPC_SLATE_DRAGON, - NPC_STORM_RIDER, - NPC_TIME_WARDEN, - NPC_ORPHANED_EMERALD_WELP + EVENT_ID_NETHER_SCION_FREED = 26077, + EVENT_ID_SLATE_DRAGON_FREED = 26078, + EVENT_ID_STORM_RIDER_FREED = 26079, + EVENT_ID_TIME_WARDEN_FREED = 26064 }; Position const BreathFlightTargetStalkerSortPos = { -740.677f, -592.328f, 859.455f }; @@ -87,30 +92,19 @@ class instance_bastion_of_twilight final : public InstanceMapScript SetBossNumber(!map->IsHeroic() ? EncounterCountNormal : EncounterCountHeroic); // Sinestra only in heroic mode LoadDoorData(doorData); LoadObjectData(creatureData, gameobjectData); - _unresponsiveDragonEntryFirst = 0; - _unresponsiveDragonEntrySecond = 0; - _deadOrphanedEmeraldWhelps = 0; - _fullHeroicId = instance->IsHeroic(); - GenerateHalfusDragonData(); - } + _activeDragonFlags = DRAGON_FLAG_ALL_ACTIVE; - void GenerateHalfusDragonData() - { - for (uint8 i = 0; i < 5; i++) - _activeDragonEntries.insert(HalfusDragonEntries[i]); - - if (!instance->IsHeroic()) + if (!map->IsHeroic()) { - for (uint8 i = 0; i < 2; i++) - { - uint32 entry = Trinity::Containers::SelectRandomContainerElement(_activeDragonEntries); - _activeDragonEntries.erase(entry); - if (i == 0) - _unresponsiveDragonEntryFirst = entry; - else - _unresponsiveDragonEntrySecond = entry; - } + _activeDragonFlags = 0; + std::vector activeDragons = { DRAGON_FLAG_NETHER_SCION, DRAGON_FLAG_SLATE_DRAGON, DRAGON_FLAG_STORM_RIDER, DRAGON_FLAG_TIME_WARDEN, DRAGON_FLAG_EMERALD_WHELPS }; + Trinity::Containers::RandomResize(activeDragons, 3); + for (BoTHalfusDragonFlags flag : activeDragons) + _activeDragonFlags |= flag; } + + if ((_activeDragonFlags & DRAGON_FLAG_TIME_WARDEN) != 0) + events.ScheduleEvent(EVENT_CAST_DANCING_FLAMES, 1s); } void OnCreatureCreate(Creature* creature) override @@ -119,20 +113,8 @@ class instance_bastion_of_twilight final : public InstanceMapScript switch (creature->GetEntry()) { - case NPC_NETHER_SCION: - case NPC_SLATE_DRAGON: - case NPC_STORM_RIDER: - case NPC_TIME_WARDEN: - if (Creature* halfus = GetCreature(DATA_HALFUS_WYRMBREAKER)) - halfus->AI()->JustSummoned(creature); - [[fallthrough]]; - case NPC_ORPHANED_EMERALD_WELP: - case NPC_SPIKE: - _halfusEncounterGUIDs.insert(creature->GetGUID()); - break; case NPC_INVISIBLE_STALKER: - if (creature->GetPositionZ() < 850.0f) - _dancingFlamesInvisibleStalkerGUIDs.insert(creature->GetGUID()); + _dancingFlamesInvisibleStalkerGUIDs.insert(creature->GetGUID()); break; case NPC_COLLAPSING_TWILIGHT_PORTAL: if (Creature* valiona = GetCreature(DATA_VALIONA)) @@ -175,12 +157,16 @@ class instance_bastion_of_twilight final : public InstanceMapScript } } + void OnCreatureRemove(Creature* creature) override + { + InstanceScript::OnCreatureRemove(creature); + if (creature->GetEntry() == NPC_INVISIBLE_STALKER) + _dancingFlamesInvisibleStalkerGUIDs.erase(creature->GetGUID()); + } + void OnGameObjectCreate(GameObject* go) override { InstanceScript::OnGameObjectCreate(go); - - if (go->GetEntry() == GO_GRIM_BATOL_RAID_TRAP_DOOR && instance->IsHeroic() && _fullHeroicId && GetBossState(DATA_CHOGALL) == DONE) - go->SetGoState(GO_STATE_ACTIVE); } bool SetBossState(uint32 type, EncounterState state) override @@ -191,51 +177,8 @@ class instance_bastion_of_twilight final : public InstanceMapScript switch (type) { case DATA_HALFUS_WYRMBREAKER: - if (state == IN_PROGRESS) + if (state == DONE) { - for (ObjectGuid guid : _halfusEncounterGUIDs) - { - if (Creature* creature = instance->GetCreature(guid)) - { - if (creature->GetEntry() != NPC_SPIKE - && creature->GetEntry() != _unresponsiveDragonEntryFirst - && creature->GetEntry() != _unresponsiveDragonEntrySecond) - { - switch (creature->GetEntry()) - { - case NPC_NETHER_SCION: - creature->UpdateEntry(NPC_NETHER_SCION_ENCOUNTER); - break; - case NPC_SLATE_DRAGON: - creature->UpdateEntry(NPC_SLATE_DRAGON_ENCOUNTER); - break; - case NPC_STORM_RIDER: - creature->UpdateEntry(NPC_STORM_RIDER_ENCOUNTER); - break; - case NPC_TIME_WARDEN: - creature->UpdateEntry(NPC_TIME_WARDEN_ENCOUNTER); - break; - default: - break; - } - - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - if (creature->GetEntry() != NPC_ORPHANED_EMERALD_WELP) - creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } - } - } - } - else if (state == FAIL) - { - _halfusEncounterGUIDs.clear(); - _deadOrphanedEmeraldWhelps = 0; - events.CancelEvent(EVENT_CAST_DANCING_FLAMES); - } - else if (state == DONE) - { - events.CancelEvent(EVENT_CAST_DANCING_FLAMES); if (Creature* chogall = GetCreature(DATA_CHOGALL_EVENT)) chogall->AI()->DoAction(ACTION_TALK_HALFUS_WYRMBREAKER_DEAD); } @@ -270,66 +213,13 @@ class instance_bastion_of_twilight final : public InstanceMapScript default: break; } - - if (state == DONE && !instance->IsHeroic()) - _fullHeroicId = 0; return true; } - void OnUnitDeath(Unit* unit) override - { - if (unit->GetEntry() == NPC_ORPHANED_EMERALD_WELP) - { - _deadOrphanedEmeraldWhelps++; - if (_deadOrphanedEmeraldWhelps == 8) - if (Creature* protoBehemoth = GetCreature(DATA_PROTO_BEHEMOTH)) - protoBehemoth->AI()->DoAction(ACTION_CAST_DRAGONS_VENGEANCE); - } - } - - void SetData(uint32 type, uint32 data) override + void SetData(uint32 type, uint32 /*data*/) override { switch (type) { - case DATA_CAST_DRAGON_BUFFS: - if (data == DRAGON_BUFFS_HALFUS_WYRMBREAKER) - { - if (Creature* halfus = GetCreature(DATA_HALFUS_WYRMBREAKER)) - { - for (uint32 entry : _activeDragonEntries) - { - if (entry == NPC_SLATE_DRAGON) - halfus->AI()->DoAction(ACTION_ENABLE_MALEVOLENT_STRIKES); - if (entry == NPC_NETHER_SCION) - halfus->AI()->DoAction(ACTION_ENABLE_FRENZIED_ASSAULT); - if (entry == NPC_STORM_RIDER) - halfus->AI()->DoAction(ACTION_ENABLE_SHADOW_NOVA); - } - } - } - else if (data == DRAGON_BUFFS_PROTO_BEHEMOTH) - { - if (Creature* protoBehemoth = GetCreature(DATA_PROTO_BEHEMOTH)) - { - for (uint32 entry : _activeDragonEntries) - { - if (entry == NPC_ORPHANED_EMERALD_WELP) - protoBehemoth->AI()->DoAction(ACTION_ENABLE_SCORCHING_BREATH); - if (entry == NPC_TIME_WARDEN) - { - protoBehemoth->AI()->DoAction(ACTION_ENABLE_FIREBALL_BARRAGE); - events.RescheduleEvent(EVENT_CAST_DANCING_FLAMES, 500ms, 1s); - } - } - } - } - break; - case DATA_OPEN_ORPHANED_EMERALD_WHELP_CAGE: - for (ObjectGuid guid : _halfusEncounterGUIDs) - if (Creature* orphanedEmeraldWhelp = instance->GetCreature(guid)) - if (orphanedEmeraldWhelp->GetEntry() == NPC_ORPHANED_EMERALD_WELP) - orphanedEmeraldWhelp->AI()->DoAction(ACTION_MOVE_OUT_OF_CAGE); - break; case DATA_AT_HALFUS_WYRMBREAKER_INTRO: if (GetBossState(DATA_HALFUS_WYRMBREAKER) != DONE) if (Creature* chogall = GetCreature(DATA_CHOGALL_EVENT)) @@ -392,12 +282,6 @@ class instance_bastion_of_twilight final : public InstanceMapScript { switch (type) { - case DATA_UNRESPONSIVE_DRAGON_FIRST: - return _unresponsiveDragonEntryFirst; - case DATA_UNRESPONSIVE_DRAGON_SECOND: - return _unresponsiveDragonEntrySecond; - case DATA_DRAGON_CAGE_ENABLED: - return uint8((instance->IsHeroic() || HasActiveOrphanedEmeraldWhelps())); case DATA_COLLAPSING_TWILIGHT_PORTAL_COUNT: { uint8 portalCount = 0; @@ -407,7 +291,9 @@ class instance_bastion_of_twilight final : public InstanceMapScript return portalCount; } case DATA_FULL_HEROIC_ID: - return _fullHeroicId; + return false; + case DATA_ACTIVE_DRAGON_FLAGS: + return _activeDragonFlags; default: return 0; } @@ -423,12 +309,33 @@ class instance_bastion_of_twilight final : public InstanceMapScript switch (eventId) { case EVENT_CAST_DANCING_FLAMES: - if (ObjectGuid guid = Trinity::Containers::SelectRandomContainerElement(_dancingFlamesInvisibleStalkerGUIDs)) - if (Creature* cataclysmStalker = instance->GetCreature(guid)) - cataclysmStalker->CastSpell(cataclysmStalker, SPELL_DANCING_FLAMES_VISUAL, true); + { + if (_dancingFlamesInvisibleStalkerGUIDs.size() < 1) + { + events.Repeat(1s); + break; + } + + // Between one and three stalkers cast the dancing flames at the same time. We now have to select a range within the guidset + uint32 castingStalkerNum = std::min(urand(1, 3), (_dancingFlamesInvisibleStalkerGUIDs.size() - 1)); + GuidSet::const_iterator startIterator = _dancingFlamesInvisibleStalkerGUIDs.begin(); + GuidSet::const_iterator endIterator = _dancingFlamesInvisibleStalkerGUIDs.begin(); + std::advance(endIterator, castingStalkerNum); + + if (_dancingFlamesInvisibleStalkerGUIDs.size() > (castingStalkerNum)) + { + uint32 offset = urand(0, _dancingFlamesInvisibleStalkerGUIDs.size() - castingStalkerNum); + std::advance(startIterator, offset); + std::advance(endIterator, offset); + } + + for (GuidSet::const_iterator itr = startIterator; itr != endIterator; ++itr) + if (Creature* cataclysmStalker = instance->GetCreature(*itr)) + cataclysmStalker->CastSpell(cataclysmStalker, SPELL_DANCING_FLAMES_VISUAL); events.Repeat(500ms, 1s); break; + } case EVENT_CHOGALL_TALK_THERALION_AND_VALIONA_DEAD: if (Creature* chogall = GetCreature(DATA_CHOGALL)) chogall->AI()->DoAction(ACTION_TALK_THERALION_AND_VALIONA_DEAD); @@ -439,50 +346,33 @@ class instance_bastion_of_twilight final : public InstanceMapScript } } - void WriteSaveDataMore(std::ostringstream& data) override + void ProcessEvent(WorldObject* objTarget, uint32 eventId, WorldObject* /*invoker*/) override { - data << _unresponsiveDragonEntryFirst << ' ' - << _unresponsiveDragonEntrySecond << ' ' - << _fullHeroicId; - } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> _unresponsiveDragonEntryFirst; - data >> _unresponsiveDragonEntrySecond; - data >> _fullHeroicId; - - if (_unresponsiveDragonEntryFirst && _unresponsiveDragonEntrySecond) + switch (eventId) { - // Clear default generated unresponsive dragon selection and replace it with our saved data - _activeDragonEntries.clear(); - for (uint8 i = 0; i < 5; i++) - _activeDragonEntries.insert(HalfusDragonEntries[i]); - - _activeDragonEntries.erase(_unresponsiveDragonEntryFirst); - _activeDragonEntries.erase(_unresponsiveDragonEntrySecond); + // These events are sent by the Free Dragon spells in Halfus Wyrmbreaker's encounter. Though it makes zero sense to use them in this context, we will just + // do so to follow Blizzard's intention. Probably some intern's doing or so. + case EVENT_ID_SLATE_DRAGON_FREED: + case EVENT_ID_NETHER_SCION_FREED: + case EVENT_ID_STORM_RIDER_FREED: + case EVENT_ID_TIME_WARDEN_FREED: + if (objTarget->IsCreature()) + if (CreatureAI* ai = objTarget->ToCreature()->AI()) + ai->DoAction(ACTION_DRAGON_FREED); + break; + default: + break; } } - bool HasActiveOrphanedEmeraldWhelps() const - { - return (_unresponsiveDragonEntryFirst != NPC_ORPHANED_EMERALD_WELP - && _unresponsiveDragonEntrySecond != NPC_ORPHANED_EMERALD_WELP); - } - private: EventMap events; - GuidSet _halfusEncounterGUIDs; GuidSet _dancingFlamesInvisibleStalkerGUIDs; GuidSet _valionaDummyGUIDs; GuidSet _unstableTwilightGUIDs; GuidSet _collapsingTwilightPortalGUIDs; ObjectGuid _valionaAuraDummyGUID; - std::set _activeDragonEntries; - uint32 _unresponsiveDragonEntryFirst; - uint32 _unresponsiveDragonEntrySecond; - uint8 _deadOrphanedEmeraldWhelps; - uint8 _fullHeroicId; + uint8 _activeDragonFlags; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override