Scripts/BoT: updated and modernized Halfus Wyrmbreaker encounter

* moved several mechanics from instance script into the boss script itself
* changed the unresponsive dragon selection from two saved variables into a single generated flag
* corrected timer layout for the Proto-Behemoth and handled a missing mechanic of the Time-Dilation debuff
* moved all encounter spawns into spawngroups
* simplified and cleaned up the dragon ads script
This commit is contained in:
Ovahlord committed 2023-12-19 07:46:11 +01:00
1 parent d8ef0352e1
commit abfddaa915
4 files changed
+437 -413

No files matched your search

@@ -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);
@@ -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<class AI>
AI* GetBastionOfTwilightAI(Creature* creature)
{
@@ -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<EncounterDragonData, 4> 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<uint8>(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<uint8>(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<uint8>(_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<uint8>(_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<Creature*> 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<WorldObject*>& 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<WorldObject*>& 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<WorldObject*>& 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);
}
@@ -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<BoTHalfusDragonFlags> 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<uint32>(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<uint32> _activeDragonEntries;
uint32 _unresponsiveDragonEntryFirst;
uint32 _unresponsiveDragonEntrySecond;
uint8 _deadOrphanedEmeraldWhelps;
uint8 _fullHeroicId;
uint8 _activeDragonFlags;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override