diff --git a/data/sql/updates/db_world/2026_01_26_00.sql b/data/sql/updates/db_world/2026_01_26_00.sql new file mode 100644 index 000000000..3550eb62a --- /dev/null +++ b/data/sql/updates/db_world/2026_01_26_00.sql @@ -0,0 +1,9 @@ +-- DB update 2026_01_24_01 -> 2026_01_26_00 +-- +DELETE FROM `gossip_menu_option` WHERE `MenuID` IN (7815, 7820, 8760, 10363) AND `OptionID` = 1; +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, +`OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES +(7815, 1, 1, 'Let me browse your goods.', 8097, 3, 128, 0, 0, 0, 0, '', 0, 0), +(7820, 1, 1, 'Let me browse your goods.', 8097, 3, 128, 0, 0, 0, 0, '', 0, 0), +(8760, 1, 1, 'Let me browse your goods.', 8097, 3, 128, 0, 0, 0, 0, '', 0, 0), +(10363, 1, 1, 'Let me browse your goods.', 8097, 3, 128, 0, 0, 0, 0, '', 0, 0); diff --git a/data/sql/updates/db_world/2026_01_26_01.sql b/data/sql/updates/db_world/2026_01_26_01.sql new file mode 100644 index 000000000..15598ad98 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_26_01.sql @@ -0,0 +1,16 @@ +-- DB update 2026_01_26_00 -> 2026_01_26_01 +-- +-- Remove Weather-Beaten Journal from Dark Runed Chest ref +DELETE FROM `reference_loot_template` WHERE (`Entry` = 35037) AND (`Item` IN (34109)); + +-- Add Weather-Beaten Journal to Bag of Fishing Treasures +SET @CHANCE := 20; +DELETE FROM `item_loot_template` WHERE (`Entry` = 35348) AND (`Item` IN (34109)); +INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(35348, 34109, 0, @CHANCE, 0, 1, 0, 1, 1, 'Weather-Beaten Journal'); + +-- Add Weather-Beaten Journal to Bag of Fishing Treasures +SET @CHANCE := 15; +DELETE FROM `item_loot_template` WHERE (`Entry` = 34863) AND (`Item` IN (34109)); +INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34863, 34109, 0, @CHANCE, 0, 1, 0, 1, 1, 'Weather-Beaten Journal'); diff --git a/data/sql/updates/db_world/2026_01_26_02.sql b/data/sql/updates/db_world/2026_01_26_02.sql new file mode 100644 index 000000000..2e41f4c89 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_26_02.sql @@ -0,0 +1,21 @@ +-- DB update 2026_01_26_01 -> 2026_01_26_02 +-- +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 20040); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(20040, 0, 0, 0, 0, 0, 100, 0, 20950, 25000, 17000, 29900, 0, 0, 11, 37102, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - In Combat - Cast \'Knock Away\''), +(20040, 0, 1, 0, 0, 1, 100, 0, 20000, 30000, 20000, 30000, 0, 0, 11, 35035, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - In Combat - Start Countercharge Phase (Phase 1)'), +(20040, 0, 2, 0, 8, 1, 100, 0, 35035, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Spell \'Countercharge\' Successful - Enter Countercharge Phase'), +(20040, 0, 3, 6, 105, 2, 10, 0, 3600, 3600, 3600, 3600, 0, 50, 11, 35039, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Hostile Casting in Range - Cast \'Countercharge\' if I have a Charge (Phase 2)'), +(20040, 0, 4, 5, 8, 0, 100, 512, 34946, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Spellhit \'Golem Repair\' - Store Targetlist'), +(20040, 0, 5, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2004000, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Spellhit \'Golem Repair\' - Run Script'), +(20040, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 28, 35035, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Hostile Casting in Range - If Interrupt Successful, Remove Charge'), +(20040, 0, 7, 0, 0, 2, 50, 0, 1000, 1000, 1000, 1000, 0, 0, 11, 35035, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - In Combat, Every 1000ms - Refresh Charge on Self (Phase 2)'), +(20040, 0, 8, 0, 0, 2, 100, 0, 15000, 15000, 15000, 15000, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - In Combat - After 15s, Return to Initial Phase (Phase 2)'), +(20040, 0, 9, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crystalcore Devastator - On Aggro - Set Initial Phase'); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceEntry` = 20040) AND (`ConditionTypeOrReference` = 1) AND (`ConditionValue1` = 35035); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(22, 8, 20040, 0, 0, 1, 1, 35035, 0, 0, 1, 0, 0, '', 'Only Refresh Countercharge (35035) Aura if it is not already present'), +(22, 4, 20040, 0, 0, 1, 1, 35035, 0, 0, 0, 0, 0, '', 'Only Interrupt if Crystalcore Devastator has a charge of Countercharge (35035) to spend'); + +DELETE FROM `spell_script_names` WHERE `spell_id` = 35035 AND `ScriptName` = 'spell_the_eye_countercharge_aura'; diff --git a/data/sql/updates/db_world/2026_01_27_00.sql b/data/sql/updates/db_world/2026_01_27_00.sql new file mode 100644 index 000000000..79bdc4ac7 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_00.sql @@ -0,0 +1,3 @@ +-- DB update 2026_01_26_02 -> 2026_01_27_00 +-- Adds "Disoriented" and "Sapped" Immunties to "Maruading Crust Burster" outcome from MoP and Retail +UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` | 2 | 536870912 WHERE `entry` = 16857; diff --git a/data/sql/updates/db_world/2026_01_27_01.sql b/data/sql/updates/db_world/2026_01_27_01.sql new file mode 100644 index 000000000..047d9b919 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_01.sql @@ -0,0 +1,8 @@ +-- DB update 2026_01_27_00 -> 2026_01_27_01 +-- Updates the trainer option from "Train me." to "I seek training in Fishing." +UPDATE `gossip_menu_option` SET `OptionText` = 'I seek training in Fishing.', `OptionBroadcastTextID` = 34245 WHERE `MenuID` = 10437 AND `OptionID` = 0; + +-- Adds "I would like to buy from you." to gossip menu. Can't parse sniff to validate which 1 out of 5 "I would like to buy from you." is the correct one. +DELETE FROM `gossip_menu_option` WHERE `MenuID` = 10437 AND `OptionID` = 1; +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES +(10437, 1, 1, 'I would like to buy from you.', 9992, 3, 128, 0, 0, 0, 0, '', 0, 0); diff --git a/data/sql/updates/db_world/2026_01_27_02.sql b/data/sql/updates/db_world/2026_01_27_02.sql new file mode 100644 index 000000000..d39d4fa9e --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_02.sql @@ -0,0 +1,59 @@ +-- DB update 2026_01_27_01 -> 2026_01_27_02 +-- +UPDATE `creature_template` SET `lootid` = 30921 WHERE (`entry` = 31321); +DELETE FROM `creature_loot_template` WHERE (`Entry` = 31321); + +UPDATE `creature_template` SET `lootid` = 30922 WHERE (`entry` = 31320); +DELETE FROM `creature_loot_template` WHERE (`Entry` = 31320); + +UPDATE `creature_template` SET `lootid` = 31255 WHERE (`entry` = 31322); +DELETE FROM `creature_loot_template` WHERE `Entry` = 31322; + +UPDATE `creature_template` SET `lootid` = 30894 WHERE (`entry` = 31323); +DELETE FROM `creature_loot_template` WHERE `Entry` = 31323; + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 31322; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 31322); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(31322, 0, 0, 0, 0, 0, 100, 0, 5200, 9500, 11750, 16250, 0, 0, 11, 60960, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Saronite Shaper - In Combat - Cast \'War Stomp\''); + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 31320; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 31320); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(31320, 0, 0, 1, 8, 0, 100, 512, 58283, 0, 0, 0, 0, 0, 33, 31481, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Spellhit \'Throw Rock\' - Quest Credit'), +(31320, 0, 1, 2, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Spellhit \'Throw Rock\' - Say Line 0'), +(31320, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 2, 1692, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Spellhit \'Throw Rock\' - Set Faction 1692'), +(31320, 0, 3, 4, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 2, 1693, 0, 0, 0, 0, 0, 19, 31321, 15, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Spellhit \'Throw Rock\' - Set Faction 1693'), +(31320, 0, 4, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 31321, 15, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Spellhit \'Throw Rock\' - Start Attacking'), +(31320, 0, 5, 0, 25, 0, 100, 512, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - On Reset - Reset Faction'), +(31320, 0, 6, 0, 2, 0, 100, 1, 0, 30, 0, 0, 0, 0, 11, 50420, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - Between 0-30% Health - Cast \'Enrage\' (No Repeat)'), +(31320, 0, 7, 0, 0, 0, 100, 0, 3000, 4000, 7000, 8000, 0, 0, 11, 13446, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - In Combat - Cast \'Strike\''), +(31320, 0, 8, 0, 0, 0, 100, 0, 6000, 7000, 10000, 11000, 0, 0, 11, 10966, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Umbral Brute - In Combat - Cast \'Uppercut\''); + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 31321; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 31321); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(31321, 0, 0, 0, 25, 0, 100, 512, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Runesmith - On Reset - Reset Faction'), +(31321, 0, 1, 0, 0, 0, 100, 0, 3200, 7500, 9750, 13250, 0, 0, 11, 46202, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Runesmith - In Combat - Cast \'Pierce Armor\''); + +UPDATE `gameobject` SET `phaseMask` = `phaseMask`|4 WHERE `id` = 193004 AND `guid` IN (99724, 99725, 99726, 99727); + +DELETE FROM `creature_text` WHERE (`CreatureID` = 30922); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(30922, 0, 0, 'No one throws rocks at me!', 12, 0, 100, 0, 0, 0, 32217, 0, 'Matchmaker (13147)'), +(30922, 0, 1, 'You wouldn\'t like me when I\'m angry...', 12, 0, 100, 0, 0, 0, 32218, 0, 'Matchmaker (13147)'), +(30922, 0, 2, 'Finally! An excuse to squash you!', 12, 0, 100, 0, 0, 0, 32220, 0, 'Matchmaker (13147)'), +(30922, 0, 3, 'You die for good this time, skeleton!', 12, 0, 100, 0, 0, 0, 32221, 0, 'Matchmaker (13147)'), +(30922, 0, 4, 'Last straw...', 12, 0, 100, 0, 0, 0, 32222, 0, 'Matchmaker (13147)'), +(30922, 0, 5, 'I was waiting for a reason to tear you bone from bone!', 12, 0, 100, 0, 0, 0, 32223, 0, 'Matchmaker (13147)'), +(30922, 0, 6, 'That\'s the last mistake you\'ll make, skeleton.', 12, 0, 100, 0, 0, 0, 32224, 0, 'Matchmaker (13147)'); + +DELETE FROM `creature_text` WHERE (`CreatureID` = 31320); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(31320, 0, 0, 'No one throws rocks at me!', 12, 0, 100, 0, 0, 0, 32217, 0, 'Matchmaker (13147)'), +(31320, 0, 1, 'You wouldn\'t like me when I\'m angry...', 12, 0, 100, 0, 0, 0, 32218, 0, 'Matchmaker (13147)'), +(31320, 0, 2, 'Finally! An excuse to squash you!', 12, 0, 100, 0, 0, 0, 32220, 0, 'Matchmaker (13147)'), +(31320, 0, 3, 'You die for good this time, skeleton!', 12, 0, 100, 0, 0, 0, 32221, 0, 'Matchmaker (13147)'), +(31320, 0, 4, 'Last straw...', 12, 0, 100, 0, 0, 0, 32222, 0, 'Matchmaker (13147)'), +(31320, 0, 5, 'I was waiting for a reason to tear you bone from bone!', 12, 0, 100, 0, 0, 0, 32223, 0, 'Matchmaker (13147)'), +(31320, 0, 6, 'That\'s the last mistake you\'ll make, skeleton.', 12, 0, 100, 0, 0, 0, 32224, 0, 'Matchmaker (13147)'); diff --git a/data/sql/updates/db_world/2026_01_27_03.sql b/data/sql/updates/db_world/2026_01_27_03.sql new file mode 100644 index 000000000..2dd0ebed5 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_03.sql @@ -0,0 +1,32 @@ +-- DB update 2026_01_27_02 -> 2026_01_27_03 +-- +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28352); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28352, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 190555, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - On Respawn - Summon Gameobject \'Nerubian Crater\''), +(28352, 0, 1, 2, 8, 0, 100, 1, 51381, 0, 0, 0, 0, 0, 80, 2835200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - On Spellhit \'Toss Grenade\' - Run Script (No Repeat)'), +(28352, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 33, 28352, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - On Spellhit \'Toss Grenade\' - Quest Credit (No Repeat)'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2835200); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2835200, 9, 0, 0, 0, 0, 100, 0, 4200, 4200, 0, 0, 0, 0, 11, 44762, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Camera Shake - Med\''), +(2835200, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 48456, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Shredder Smoke\''), +(2835200, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51435, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Cast \'Summon Skimmer\''), +(2835200, 9, 8, 0, 0, 0, 100, 0, 11300, 11300, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 20, 190555, 5, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Despawn Instant'), +(2835200, 9, 9, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nethurbian Crater KC Bunny - Actionlist - Despawn Instant'); + +DELETE FROM `gameobject` WHERE `id` = 190555 AND `guid` BETWEEN 58160 AND 58168; +DELETE FROM `creature` WHERE `id1` = 28369 AND `guid` BETWEEN 115685 AND 115691; +UPDATE `creature` SET `spawntimesecs` = 120 WHERE `id1` = 28352 AND `guid` BETWEEN 114082 AND 114091; + +UPDATE `creature_template` SET `AIName` = 'SmartAI', `speed_run` = 2 WHERE `entry` = 28369; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28369); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28369, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 40148, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Burning Skimmer - On Respawn - Cast \'Immolation\''), +(28369, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Burning Skimmer - On Respawn - Set Run On'), +(28369, 0, 2, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 89, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Burning Skimmer - On Respawn - Start Random Movement'), +(28369, 0, 3, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 37, 10000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Burning Skimmer - On Respawn - Kill Self'); diff --git a/data/sql/updates/db_world/2026_01_27_04.sql b/data/sql/updates/db_world/2026_01_27_04.sql new file mode 100644 index 000000000..92cf741ce --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_04.sql @@ -0,0 +1,12 @@ +-- DB update 2026_01_27_03 -> 2026_01_27_04 +-- +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28203); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28203, 0, 0, 1, 8, 0, 100, 512, 50918, 0, 0, 0, 0, 0, 11, 50919, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Gorged Lurking Basilisk - On Spellhit \'Gluttonous Lurkers: Create Basilisk Crystals Cover\' - Cast \'Create Basilisk Crystals\''), +(28203, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Gorged Lurking Basilisk - On Spellhit \'Gluttonous Lurkers: Create Basilisk Crystals Cover\' - Despawn Instant'); + +DELETE FROM `creature_template_addon` WHERE (`entry` = 28203); +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES +(28203, 0, 0, 0, 1, 0, 0, '50917'); + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` = 28203 AND `spell_id` = 50919; diff --git a/data/sql/updates/db_world/2026_01_27_05.sql b/data/sql/updates/db_world/2026_01_27_05.sql new file mode 100644 index 000000000..3921bd720 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_27_05.sql @@ -0,0 +1,28 @@ +-- DB update 2026_01_27_04 -> 2026_01_27_05 +-- +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24718); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(24718, 0, 0, 0, 10, 0, 100, 512, 1, 5, 60000, 60000, 0, 0, 80, 2471800, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Within 1-5 Range Out of Combat LoS - Run Script'), +(24718, 0, 1, 0, 8, 1, 100, 512, 44562, 0, 5000, 5000, 0, 0, 80, 2471801, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - On Spellhit \'Bluff\' - Run Script (Phase 1)'), +(24718, 0, 2, 0, 60, 1, 100, 0, 60000, 60000, 60000, 60000, 0, 0, 80, 2471802, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - On Update - Reset Self (Phase 1)'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2471800); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2471800, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Say Line 1'), +(2471800, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Event Phase 1'), +(2471800, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Rooted On'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2471801); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2471801, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Event Phase 0'), +(2471801, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 24823, 20, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Say Line 0'), +(2471801, 9, 2, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Say Line 2'), +(2471801, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 19, 24823, 20, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Data 0 1'), +(2471801, 9, 4, 0, 0, 0, 100, 0, 10000, 10000, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Rooted Off'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2471802); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2471802, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Event Phase 0'), +(2471802, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lebronski - Actionlist - Set Rooted Off'); + +UPDATE `conditions` SET `Comment` = 'Only fire Event for \'Iron Rune Constructs and You: The Bluff\' if Invoker is Iron Rune Construct (24823)' WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 1) AND (`SourceEntry` = 24718) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 24823) AND (`ConditionValue3` = 0); diff --git a/data/sql/updates/db_world/2026_01_28_00.sql b/data/sql/updates/db_world/2026_01_28_00.sql new file mode 100644 index 000000000..d82f99233 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_28_00.sql @@ -0,0 +1,10 @@ +-- DB update 2026_01_27_05 -> 2026_01_28_00 +-- +SET @ENTRY := 24705; + +UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 128 WHERE `entry` = @ENTRY; + +DELETE FROM `creature_template_model` WHERE `CreatureID` = @ENTRY; +INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES +(@ENTRY, 0, 1126, 1, 0, 51831), +(@ENTRY, 1, 11686, 1, 1, 51831); diff --git a/data/sql/updates/db_world/2026_01_29_00.sql b/data/sql/updates/db_world/2026_01_29_00.sql new file mode 100644 index 000000000..e49a071b9 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_29_00.sql @@ -0,0 +1,289 @@ +-- DB update 2026_01_28_00 -> 2026_01_29_00 +-- +-- Add BreadcrumbForQuestId column to quest_template_addon +-- + +ALTER TABLE `quest_template_addon` +ADD COLUMN `BreadcrumbForQuestId` mediumint unsigned NOT NULL DEFAULT '0' AFTER `ExclusiveGroup`; + +-- Assisting Arch Druid Runetotem +UPDATE `quest_template_addon` SET `NextQuestID` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 3761 WHERE `ID` IN (936, 3762, 3784); + +-- Assisting Arch Druid Staghelm +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 3764 WHERE `ID` IN (3763, 3789, 3790, 10520); + +-- Lost Deathstalkers +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 429 WHERE `ID` = 428; + +-- On Guard in Stonetalon +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1085 WHERE `ID` = 1070; + +-- The Crown of Will +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 518 WHERE `ID` = 495; + +-- Camp Mojache +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 7489 WHERE `ID` = 7492; + +-- Feathermoon Stronghold +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 7488 WHERE `ID` = 7494; + +-- Journey to Stonetalon Peak +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1057 WHERE `ID` = 1056; + +-- Castpipe's Task +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2930 WHERE `ID` = 2931; + +-- Kayneth Stillwind +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1011 WHERE `ID` = 4581; + +-- Carendin Summons +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1472 WHERE `ID` = 10605; + +-- Seeking Strahad (Horde) +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 1801 WHERE `ID` IN (2996, 3001); + +-- Seeking Strahad (Alliance) +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1758 WHERE `ID` = 1798; + +-- A Helping Hand +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 9517 WHERE `ID` = 9533; + +-- Trouble In Darkshore? +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 729 WHERE `ID` = 730; + +-- Yorus Barleybrew +UPDATE `quest_template_addon` SET `NextQuestID` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 1699 WHERE `ID` IN (1698, 10371); + +-- Speak with Ruga +UPDATE `quest_template_addon` SET `PrevQuestId` = 0 WHERE `ID` = 1824; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1824 WHERE `ID` = 1823; + +-- A Strange One +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4505 WHERE `ID` = 6605; + +-- A Call to Arms: The Plaguelands! (horde) +UPDATE `quest_template_addon` SET `NextQuestID` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 5096 WHERE `ID` IN (5093, 5094, 5095, 10374); + +-- A Call to Arms: The Plaguelands! (alliance) +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 5092 WHERE `ID` IN (5066, 5090, 5091, 10373); + +-- Trouble in Winterspring! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 5082 WHERE `ID` = 6603; + +-- Neeka Bloodscar +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1420 WHERE `ID` = 1418; + +-- Taking Back Silithus +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 8280 WHERE `ID` IN (8275, 8276); + +-- To Winterspring! & Starfall +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 5244 WHERE `ID` IN (5249, 5250); + +-- Tinkee Steamboil +UPDATE `quest_template_addon` SET `PrevQuestID` = 4810 WHERE `ID` = 4734; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4734 WHERE `ID` = 4907; + +-- Westbrook Garrison Needs Help! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 11 WHERE `ID` = 239; + +-- Elmore's Task +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 353; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 353 WHERE `ID` = 1097; + +-- Brother Anton +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 261 WHERE `ID` = 6141; + +-- Chillwind Camp +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 8414; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 8414 WHERE `ID` = 8415; + +-- Report to Jennea +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1920 WHERE `ID` = 1919; + +-- High Sorcerer Andromath +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1938 WHERE `ID` = 1939; + +-- Vital Supplies +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 1395; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1395 WHERE `ID` = 1477; + +-- Tabetha's Task +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2846 WHERE `ID` = 2861; + +-- James Hyal +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 1302; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1302 WHERE `ID` = 1301; + +-- Morgan Stern +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1204 WHERE `ID` = 1260; + +-- Mayara Brightwing +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4764 WHERE `ID` = 4766; + +-- Tinkmaster Overspark +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2922 WHERE `ID` = 2923; + +-- Knowledge of the Orb of Orahil +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 1799 WHERE `ID` IN (4965, 4967, 4968, 4969); + +-- In Search of Menara Voidrender +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 1796 WHERE `ID` IN (4736, 4737, 4738, 4739); + +-- Gakin's Summons / The Slaughtered Lamb +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 1688 WHERE `ID` IN (1685, 1715); + +-- Gakin's Summons +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 1716; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1716 WHERE `ID` = 1717; + +-- Jonespyre's Request +UPDATE `quest_template_addon` SET `PrevQuestID` = 3785 WHERE `ID` = 3791; +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 3791 WHERE `ID` IN (3787, 3788); + +-- Malin's Request +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 691 WHERE `ID` = 690; + +-- Report to Anastasia +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1960 WHERE `ID` = 1959; + +-- Speak with Deino +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1944 WHERE `ID` = 1943; + +-- Torwa Pathfinder +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 9052; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 9052 WHERE `ID` = 9063; + +-- The Hermit +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 148 WHERE `ID` = 165; + +-- Deliveries to Sven +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 95 WHERE `ID` = 164; + +-- Raven Hill +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 5 WHERE `ID` = 163; + +-- Enraged Wildkin +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4861 WHERE `ID` = 6604; + +-- Ironband's Excavation +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 297 WHERE `ID` = 436; + +-- Stonegear's Search +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 466 WHERE `ID` = 467; + +-- Mountaineer Stormpike's Task +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1338 WHERE `ID` = 1339; + +-- Report to Mountaineer Rockgar +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 455; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 455 WHERE `ID` = 468; + +-- Find Bingles +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2038 WHERE `ID` = 2039; + +-- The Greenwarden +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 276 WHERE `ID` = 463; + +-- Rejold's New Brew +UPDATE `quest_template_addon` SET `PrevQuestID` = 315 WHERE `ID` = 413; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 413 WHERE `ID` = 415; + +-- Klockmort's Essentials +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2924 WHERE `ID` = 2925; + +-- Speak with Shoni +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2040 WHERE `ID` = 2041; + +-- Imperial Plate Armor +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 7652 WHERE `ID` IN (10891, 10892); + +-- I Know A Guy... / To Gadgetzan You Go! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6610 WHERE `ID` IN (6611, 6612); + +-- Alliance Trauma +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6624 WHERE `ID` = 6625; + +-- I Got Nothin' Left! +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6607 WHERE `ID` = 6609; + +-- Trollbane +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 639 WHERE `ID` = 638; + +-- Horde Trauma +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 6622 WHERE `ID` = 6623; + +-- The Hermit of Witch Hill / The Hermit of Swamplight Manor +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1218 WHERE `ID` IN (11177, 11225); + +-- Vivian Lagrave +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4134 WHERE `ID` = 4133; + +-- Vivian Lagrave and the Darkstone Tablet +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4768 WHERE `ID` = 4769; + +-- Yuka Screwspigot +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 4136 WHERE `ID` = 4324; + +-- Help Watcher Biggs +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1396 WHERE `ID` = 9609; + +-- Taking a Stand +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 12503 WHERE `ID` = 12795; +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` IN (12503, 12596); + +-- The Exiles of Ulduar +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 12930 WHERE `ID` = 12885; + +-- Assist Exarch Orelis +UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 10241; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 10241 WHERE `ID` = 11038; + +-- Off To Area 52 / Out of This World Produce! / A Strange Vision / Parts for the Rocket-Chief / A Mystifying Vision +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 10186 WHERE `ID` IN (10183, 11036, 11037, 11040, 11042); + +-- Horde Warlock Voidwalker questlines +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (10789, 1478, 1473, 1471, 10790, 1506, 1501, 1504, 10788, 9529, 9619); +UPDATE `quest_template_addon` SET `PrevQuestId` = 1473 WHERE `ID` = 1471; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1473 WHERE `ID` IN (10789, 1478); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1501 WHERE `ID` IN (10790, 1506); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 9529 WHERE `ID` = 10788; + +-- Horde Mage level 10 quests +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (1881, 1883, 9402); +UPDATE `quest_template_addon` SET `PrevQuestId` = 0 WHERE `ID` = 1884; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1882 WHERE `ID` = 1881; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1884 WHERE `ID` = 1883; +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 1882 WHERE `ID` IN (1882, 1884, 9402); + +-- Alliance Mage level 10 quests +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (1860, 1879); +UPDATE `quest_template_addon` SET `PrevQuestId` = 0 WHERE `ID` = 1880; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1861 WHERE `ID` = 1860; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 1880 WHERE `ID` = 1879; +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 1861 WHERE `ID` IN (1861, 1880, 9595); + +-- SI:7 / Erion's Behest / Kingly Shakedown +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 2260 WHERE `ID` = 2259; +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 2298 WHERE `ID` = 2299; +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 2281 WHERE `ID` IN (2260, 2298, 2300); + +-- Alliance Rogue level 10 quests +UPDATE `quest_template_addon` SET `PrevQuestId` = 0, `ExclusiveGroup` = 2206 WHERE `ID` IN (2206, 2238, 2242); +UPDATE `quest_template_addon` SET `NextQuestId` = 0, `ExclusiveGroup` = 0 WHERE `ID` IN (2218, 2205, 2241); +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2238 WHERE `ID` = 2218; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2206 WHERE `ID` = 2205; +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 2242 WHERE `ID` = 2241; + +-- Find Sage Mistwalker (breadcrumb for The Artifacts of Steel Gate) +UPDATE `quest_template_addon` SET `PrevQuestID` = 0, `ExclusiveGroup` = 0 WHERE (`ID` = 11286); +UPDATE `quest_template_addon` SET `ExclusiveGroup` = 0, `BreadcrumbForQuestId` = 11286 WHERE `ID` = 11287; + +-- Judgment Day Comes! (Alliance/Horde breadcrumbs for Honor Above All Else) +UPDATE `quest_template_addon` SET `BreadcrumbForQuestId` = 13036 WHERE `ID` IN (13226, 13227); + +-- Remove redundant conditions now handled by BreadcrumbForQuestId +-- Quest 8280 (Securing the Supply Lines) no longer needs conditions requiring 8275/8276 rewarded +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` = 8280 AND `ConditionTypeOrReference` = 8 AND `ConditionValue1` IN (8275, 8276); + +-- Judgment Day Comes! (13226/13227) no longer needs conditions checking 13036 (Honor Above All Else) +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` IN (13226, 13227) AND `ConditionValue1` = 13036; diff --git a/data/sql/updates/db_world/2026_01_29_01.sql b/data/sql/updates/db_world/2026_01_29_01.sql new file mode 100644 index 000000000..de3f08ce4 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_29_01.sql @@ -0,0 +1,21 @@ +-- DB update 2026_01_29_00 -> 2026_01_29_01 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 51774 AND `ScriptName` = 'spell_taunt_brann'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(51774, 'spell_taunt_brann'); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 51774) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 28070) AND (`ConditionValue3` = 0); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 51774, 0, 0, 31, 0, 3, 28070, 0, 0, 0, 0, '', 'Target of Taunt (51774) is Brann Bronzebeard (28070) in Halls of Stone Tribunal Event.'); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27983) AND (`source_type` = 0) AND (`id` IN (2)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(27983, 0, 2, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51774, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dark Rune Protector - On Respawn - Cast \'Taunt\''); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27984) AND (`source_type` = 0) AND (`id` IN (4)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(27984, 0, 4, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51774, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dark Rune Stormcaller - On Respawn - Cast \'Taunt\''); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27985) AND (`source_type` = 0) AND (`id` IN (3)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(27985, 0, 3, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51774, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Golem Custodian - On Respawn - Cast \'Taunt\''); diff --git a/data/sql/updates/db_world/2026_01_29_02.sql b/data/sql/updates/db_world/2026_01_29_02.sql new file mode 100644 index 000000000..a35896818 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_29_02.sql @@ -0,0 +1,19 @@ +-- DB update 2026_01_29_01 -> 2026_01_29_02 +-- +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2895202) AND (`source_type` = 9) AND (`id` IN (5)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2895202, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Reset Script - Set Active Off'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2895200); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2895200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Success Script - Set Active On'), +(2895200, 9, 1, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Success Script - Say Line 0'), +(2895200, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 15, 12721, 0, 0, 0, 0, 0, 18, 60, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Success Script - Quest Credit \'Rampage\''), +(2895200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Success Script - Summon Creature Group 1'), +(2895200, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 92, 0, 45579, 0, 0, 0, 0, 9, 28988, 0, 100, 0, 0, 0, 0, 0, 'Akali - Actionlist - Interrupt Spell \'Fire Channeling\''), +(2895200, 9, 5, 0, 0, 0, 100, 0, 4600, 4600, 0, 0, 0, 0, 19, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Akali - Quest Success Script - Remove Flag Immune To NPC\'s'), +(2895200, 9, 6, 0, 0, 0, 100, 0, 55000, 55000, 0, 0, 0, 0, 12, 28996, 8, 0, 0, 0, 0, 8, 0, 0, 0, 0, 6882.03, -4571, 442.312, 2.37365, 'Akali - Quest Success Script - Summon Creature \'Prophet of Akali\''); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28996) AND (`source_type` = 0) AND (`id` IN (7)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28996, 0, 7, 0, 37, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Prophet of Akali - On Initialize - Set Active On'); diff --git a/data/sql/updates/db_world/2026_01_29_03.sql b/data/sql/updates/db_world/2026_01_29_03.sql new file mode 100644 index 000000000..cdd8e0d14 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_29_03.sql @@ -0,0 +1,4 @@ +-- DB update 2026_01_29_02 -> 2026_01_29_03 +-- Wotlk armor value +UPDATE `creature_classlevelstats` SET `basearmor`=10643 WHERE `level`=83 AND `class`=1; +UPDATE `creature_classlevelstats` SET `basearmor`=10643 WHERE `level`=83 AND `class`=2; diff --git a/data/sql/updates/db_world/2026_01_30_00.sql b/data/sql/updates/db_world/2026_01_30_00.sql new file mode 100644 index 000000000..e4bc6e645 --- /dev/null +++ b/data/sql/updates/db_world/2026_01_30_00.sql @@ -0,0 +1,6 @@ +-- DB update 2026_01_29_03 -> 2026_01_30_00 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` IN (56072, 56070); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(56072, 'spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger'), +(56070, 'spell_wyrmrest_skytalon_summon_red_dragon_buddy'); diff --git a/data/sql/updates/db_world/2026_01_30_01.sql b/data/sql/updates/db_world/2026_01_30_01.sql new file mode 100644 index 000000000..30a247c2e --- /dev/null +++ b/data/sql/updates/db_world/2026_01_30_01.sql @@ -0,0 +1,54 @@ +-- DB update 2026_01_30_00 -> 2026_01_30_01 +DELETE FROM `smart_scripts` WHERE `entryorguid` = 23377 AND `id` = 3 AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(23377, 0, 3, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 53, 1, 23377, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Skyguard Ace - On Respawn - Start Waypoint Movement'); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 23377 AND `id` IN (4, 5, 6) AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(23377,0,4,0,38,0,100,0,2,2,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0.0,0.0,0.0,0.0,'On Data Set - Talk 2'), +(23377,0,5,0,38,0,100,0,3,3,0,0,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0.0,0.0,0.0,0.0,'On Data Set - Talk 3'); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 2183800 AND `source_type` = 9; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2183800, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Set Immune Flags'), +(2183800, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 24240, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Summon Lightning Spell'), +(2183800, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 11, 39579, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Shadow Form'), +(2183800, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Summon Talk'), +(2183800, 9, 4, 0, 0, 0, 100, 0, 10000, 10000, 0, 0, 0, 0, 19, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Remove Immune Flags'), +(2183800, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Attack Invoker'); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 2183801 AND `source_type` = 9; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2183801, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 40726, 0, 0, 0, 0, 0, 5, 0, 1, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Cast "Chosen One"'), +(2183801, 9, 1, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 11, 40722, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 'Terokk - On Script - Cast "Will of the Arakkoa God"'); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 21838 AND `id` = 19 AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(21838, 0, 19, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 12, 23377, 3, 240000, 0, 0, 0, 8, 0, 0, 0, 0, -3771.6, 3499.32, 317.88, 2.5, 'Terokk - On Aggro Summon "Skyguard Ace"'); + +UPDATE `smart_scripts` SET `target_type` = 19 WHERE `entryorguid` = 21838 AND `id` IN (4, 7, 13, 14) AND `source_type` = 0; +UPDATE `smart_scripts` SET `action_param1` = 2, `action_param2` = 2, `comment` = 'Terokk - Between 0-50% Health - Set Data 2 2 (Skyguard Ace) (No Repeat)' WHERE `entryorguid` = 21838 AND `id` = 4 AND `source_type` = 0; +UPDATE `smart_scripts` SET `target_param1` = 23377 WHERE `entryorguid` = 21838 AND `id` IN (4, 7, 13, 14) AND `source_type` = 0; +UPDATE `smart_scripts` SET `action_param1` = 1, `action_param2` = 1 WHERE `entryorguid` = 21838 AND `id` = 7 AND `source_type` = 0; + +DELETE FROM `creature_text` WHERE `CreatureID` = 21838 AND `GroupID` = 3; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES + (21838,3,0,'Who calls me to this world? The stars are not yet aligned... my powers fail me! You will pay for this!',14,0,100.0,0,0,0,21639,0,'Terokk'); + +UPDATE `creature_text` SET `Text` = 'Kwa! You cannot kill me, I am immortal!' WHERE `CreatureID` = 21838 AND `GroupID` = 1; +UPDATE `creature_text` SET `BroadcastTextId` = 24020 WHERE `CreatureID` = 21838 AND `GroupID` = 1; + +DELETE FROM `creature_text` WHERE `CreatureID` = 23377; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23377,1,0,'Quickly! Use the flames and support ground troops. Its ancient magic should cleanse Terokk''s shield.',14,0,100.0,0,0,0,24021,0,'Skyguard Ace'), +(23377,2,0,'Enemy sighted! Fall into formation and prepare for bombing maneuvers!',14,0,100.0,0,0,0,21439,0,'Skyguard Ace'), +(23377,3,0,'They did it! Enemy down! Return to base!',14,0,100.0,0,0,0,21437,0,'Skyguard Ace'); + +UPDATE `creature_template` SET `unit_flags` = 2 WHERE `entry` = 23377; + +DELETE FROM `waypoints` WHERE `entry` = 23377; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `point_comment`) VALUES +(23377, 1, -3774.55, 3514.51, 325.551, NULL, 0, 'Skyguard Ace'), +(23377, 2, -3794.88, 3497.48, 325.551, NULL, 0, 'Skyguard Ace'), +(23377, 3, -3808.63, 3515.7, 325.551, NULL, 0, 'Skyguard Ace'), +(23377, 4, -3783.6, 3524.59, 325.551, NULL, 0, 'Skyguard Ace'); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index f714491bf..e199cbc09 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -714,7 +714,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (me->IsRooted()) // Rooted inhabit type, never move/reposition continue; - CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f)); + if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE) + CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f)); + continue; } else if (distanceToTarget < spellMinRange || !(isWithinLOSInMap || isSpellIgnoreLOS)) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 326caf426..13c6f6bf0 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -336,6 +336,9 @@ inline void Battleground::_CheckSafePositions(uint32 diff) for (auto const& [playerGuid, player] : GetPlayers()) { + if (player->IsGameMaster()) + continue; + Position pos = player->GetPosition(); Position const* startPos = GetTeamStartPosition(player->GetBgTeamId()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b23de7959..82e67db4e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -12852,9 +12852,21 @@ void Player::ResurectUsingRequestData() void Player::SetClientControl(Unit* target, bool allowMove, bool packetOnly /*= false*/) { + ASSERT(target); + // refuse to grant control if target has UNIT_STATE_CHARMED + if (target->HasUnitState(UNIT_STATE_CHARMED) && (GetGUID() != target->GetCharmerGUID())) + { + LOG_ERROR("entities.player", "Player '{}' attempt to client control '{}', which is charmed by GUID {}", GetName(), target->GetName(), target->GetCharmerGUID().ToString()); + return; + } + + // still affected by some aura that shouldn't allow control, only allow on last such aura to be removed + if (target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED)) + allowMove = false; + WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size() + 1); data << target->GetPackGUID(); - data << uint8((allowMove && !target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED)) ? 1 : 0); + data << uint8(allowMove ? 1 : 0); SendDirectMessage(&data); // We want to set the packet only diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7a2f5af21..b570441cb 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1447,6 +1447,7 @@ public: bool SatisfyQuestConditions(Quest const* qInfo, bool msg); bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const; bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const; + bool SatisfyQuestBreadcrumb(Quest const* qInfo, bool msg) const; bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const; bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg) const; bool SatisfyQuestDay(Quest const* qInfo, bool msg) const; diff --git a/src/server/game/Entities/Player/PlayerQuest.cpp b/src/server/game/Entities/Player/PlayerQuest.cpp index a2a99a4bd..edfe48c9a 100644 --- a/src/server/game/Entities/Player/PlayerQuest.cpp +++ b/src/server/game/Entities/Player/PlayerQuest.cpp @@ -239,7 +239,7 @@ bool Player::CanSeeStartQuest(Quest const* quest) if (!sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) && - SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) && + SatisfyQuestPrevChain(quest, false) && SatisfyQuestBreadcrumb(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) && SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false)) { return GetLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= quest->GetMinLevel(); @@ -256,6 +256,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg) && SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg) && SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg) && SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg) + && SatisfyQuestBreadcrumb(quest, msg) && SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg) && SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg) && SatisfyQuestConditions(quest, msg); @@ -1217,6 +1218,39 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const return true; } +bool Player::SatisfyQuestBreadcrumb(Quest const* qInfo, bool msg) const +{ + uint32 breadcrumbForQuestId = qInfo->GetBreadcrumbForQuestId(); + if (breadcrumbForQuestId) + { + QuestStatus status = GetQuestStatus(breadcrumbForQuestId); + if (status != QUEST_STATUS_NONE || IsQuestRewarded(breadcrumbForQuestId)) + { + if (msg) + SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); + + return false; + } + } + + if (std::vector const* breadcrumbs = sObjectMgr->GetBreadcrumbsForQuest(qInfo->GetQuestId())) + { + for (uint32 breadcrumbQuestId : *breadcrumbs) + { + QuestStatus status = GetQuestStatus(breadcrumbQuestId); + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED) + { + if (msg) + SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); + + return false; + } + } + } + + return true; +} + bool Player::SatisfyQuestNextChain(Quest const* qInfo, bool msg) const { uint32 nextQuest = qInfo->GetNextQuestInChain(); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e6db65263..dd6aef12c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5177,7 +5177,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U // Xinef: if stealer has same aura Aura* curAura = stealer->GetAura(aura->GetId()); if (!curAura || (!curAura->IsPermanent() && curAura->GetDuration() < (int32)dur)) - if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID())) + if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, stealer->GetGUID())) { // created aura must not be single target aura,, so stealer won't loose it on recast if (newAura->IsSingleTarget()) @@ -5189,6 +5189,13 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U } // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]); + + // Reset periodic timers so stolen HoTs tick properly + // For stolen auras we need fresh tick counters since no ticks have occurred yet + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect* aurEff = newAura->GetEffect(i)) + aurEff->ResetPeriodic(true); + newAura->ApplyForTargets(); } } @@ -11124,6 +11131,8 @@ void Unit::SetCharm(Unit* charm, bool apply) } else { + charm->ClearUnitState(UNIT_STATE_CHARMED); + if (IsPlayer()) { if (!RemoveGuidValue(UNIT_FIELD_CHARM, charm->GetGUID())) @@ -18631,7 +18640,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au ASSERT(type != CHARM_TYPE_POSSESS || charmer->IsPlayer()); if (type == CHARM_TYPE_VEHICLE && !IsVehicle()) // pussywizard throw 1; - ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle()); + ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle())); LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {} ({}), charmed {} ({}), type {}.", charmer->GetEntry(), charmer->GetGUID().ToString(), GetEntry(), GetGUID().ToString(), uint32(type)); @@ -18804,6 +18813,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au else if (IsPlayer()) RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); + AddUnitState(UNIT_STATE_CHARMED); + if (Creature* creature = ToCreature()) creature->RefreshSwimmingFlag(); diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index af52a9891..dc80e1fba 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -169,7 +169,7 @@ enum UnitState { UNIT_STATE_DIED = 0x00000001, // player has fake death aura UNIT_STATE_MELEE_ATTACKING = 0x00000002, // player is melee attacking someone - //UNIT_STATE_MELEE_ATTACK_BY = 0x00000004, // player is melee attack by someone + UNIT_STATE_CHARMED = 0x00000004, // having any kind of charm aura on self UNIT_STATE_STUNNED = 0x00000008, UNIT_STATE_ROAMING = 0x00000010, UNIT_STATE_CHASE = 0x00000020, @@ -201,7 +201,7 @@ enum UnitState UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // should not be changed outside the core and should be placed at the end UNIT_STATE_LOGOUT_TIMER = 0x80000000, // Unit is logging out - UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE + UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_CHARMED | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED | UNIT_STATE_DISTRACTED | UNIT_STATE_ISOLATED | UNIT_STATE_ATTACK_PLAYER | UNIT_STATE_CASTING | UNIT_STATE_POSSESSED | UNIT_STATE_CHARGING | UNIT_STATE_JUMPING | UNIT_STATE_MOVE | UNIT_STATE_ROTATING diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index d18e721ad..5fbc91a4e 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -26,6 +26,7 @@ #include "TemporarySummon.h" #include "Unit.h" #include "Util.h" +#include Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) : _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE) @@ -562,6 +563,11 @@ bool Vehicle::IsVehicleInUse() return false; } +bool Vehicle::IsControllableVehicle() const +{ + return std::ranges::any_of(Seats, [](auto const& seat) { return seat.second.SeatInfo->CanControl(); }); +} + void Vehicle::TeleportVehicle(float x, float y, float z, float ang) { _me->GetMap()->LoadGrid(x, y); diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index 04594870b..d7359760c 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -51,6 +51,7 @@ public: void RemoveAllPassengers(); void Dismiss(); bool IsVehicleInUse(); + [[nodiscard]] bool IsControllableVehicle() const; void TeleportVehicle(float x, float y, float z, float ang); SeatMap Seats; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b0f3f5613..175bdd7c2 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4738,10 +4738,10 @@ void ObjectMgr::LoadQuests() } // Load `quest_template_addon` - // 0 1 2 3 4 5 6 7 8 - result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay, " - //9 10 11 12 13 14 15 16 17 - "RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, RewardMailSenderEntry, SpecialFlags FROM quest_template_addon LEFT JOIN quest_mail_sender ON Id=QuestId"); + // 0 1 2 3 4 5 6 7 8 + result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, BreadcrumbForQuestId, RewardMailTemplateID, " + //9 10 11 12 13 14 15 16 17 18 + "RewardMailDelay, RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, RewardMailSenderEntry, SpecialFlags FROM quest_template_addon LEFT JOIN quest_mail_sender ON Id=QuestId"); if (!result) { @@ -5318,12 +5318,54 @@ void ObjectMgr::LoadQuests() if (qinfo->ExclusiveGroup) mExclusiveQuestGroups.insert(std::pair(qinfo->ExclusiveGroup, qinfo->GetQuestId())); + + if (uint32 breadcrumbForQuestId = qinfo->GetBreadcrumbForQuestId()) + { + if (_questTemplates.find(breadcrumbForQuestId) == _questTemplates.end()) + LOG_ERROR("sql.sql", "Quest {} has BreadcrumbForQuestId {}, but no such quest exists", qinfo->GetQuestId(), breadcrumbForQuestId); + else + _breadcrumbsForQuest[breadcrumbForQuestId].push_back(qinfo->GetQuestId()); + + if (qinfo->GetNextQuestId()) + LOG_ERROR("sql.sql", "Quest {} is a breadcrumb quest but also has NextQuestID {} set", qinfo->GetQuestId(), qinfo->GetNextQuestId()); + if (qinfo->GetExclusiveGroup()) + LOG_ERROR("sql.sql", "Quest {} is a breadcrumb quest but also has ExclusiveGroup {} set", qinfo->GetQuestId(), qinfo->GetExclusiveGroup()); + } + if (qinfo->TimeAllowed) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED); if (qinfo->RequiredPlayerKills) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL); } + for (auto const& [questId, quest] : _questTemplates) + { + if (sDisableMgr->IsDisabledFor(DISABLE_TYPE_QUEST, questId, nullptr)) + continue; + + uint32 breadcrumbForQuestId = quest->GetBreadcrumbForQuestId(); + if (!breadcrumbForQuestId) + continue; + + std::set visitedQuests; + visitedQuests.insert(questId); + + while (breadcrumbForQuestId) + { + if (!visitedQuests.insert(breadcrumbForQuestId).second) + { + LOG_ERROR("sql.sql", "Breadcrumb quests {} and {} form a loop", questId, breadcrumbForQuestId); + break; + } + + Quest const* targetQuest = GetQuestTemplate(breadcrumbForQuestId); + if (!targetQuest) + break; + + breadcrumbForQuestId = targetQuest->GetBreadcrumbForQuestId(); + } + } + // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) { diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 0acf11080..37bf94b7d 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1146,6 +1146,18 @@ public: ExclusiveQuestGroups mExclusiveQuestGroups; + typedef std::unordered_map> BreadcrumbQuestMap; + BreadcrumbQuestMap _breadcrumbsForQuest; + + [[nodiscard]] std::vector const* GetBreadcrumbsForQuest(uint32 questId) const + { + auto itr = _breadcrumbsForQuest.find(questId); + if (itr != _breadcrumbsForQuest.end()) + return &itr->second; + + return nullptr; + } + MailLevelReward const* GetMailLevelReward(uint32 level, uint32 raceMask) { MailLevelRewardContainer::const_iterator map_itr = _mailLevelRewardStore.find(level); diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 513a789ef..0d9581a2e 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -128,11 +128,11 @@ namespace Movement // MoveSplineFlag::Enter_Cycle support dropped //if (splineflags & SPLINEFLAG_ENTER_CYCLE) //cyclic_point = 1; // shouldn't be modified, came from client - spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point); + spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point, args.initialOrientation); } else { - spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]); + spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation); } // init spline timestamps diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp index 9c65619b5..5baf32027 100644 --- a/src/server/game/Movement/Spline/Spline.cpp +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -199,18 +199,20 @@ namespace Movement return length; } - void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m) + void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation) { m_mode = m; cyclic = false; + initialOrientation = orientation; (this->*initializers[m_mode])(controls, count, cyclic, 0); } - void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) + void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation) { m_mode = m; cyclic = true; + initialOrientation = orientation; (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point); } @@ -253,14 +255,18 @@ namespace Movement if (cyclic_point == 0) points[0] = controls[count - 1]; else - points[0] = controls[0].lerp(controls[1], -1); + points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; points[high_index + 1] = controls[cyclic_point]; points[high_index + 2] = controls[cyclic_point + 1]; } else { - points[0] = controls[0].lerp(controls[1], -1); + if (m_mode == ModeCatmullrom) + points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; + else + points[0] = controls[0].lerp(controls[1], -1); + points[high_index + 1] = controls[count - 1]; } diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index 9645eb607..ef0b6aee5 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -48,6 +48,7 @@ namespace Movement uint8 m_mode{UninitializedMode}; bool cyclic{false}; + float initialOrientation{0}; enum { @@ -116,8 +117,8 @@ namespace Movement [[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];} /** Initializes spline. Don't call other methods while spline not initialized. */ - void init_spline(const Vector3* controls, index_type count, EvaluationMode m); - void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point); + void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation); + void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation); /** As i can see there are a lot of ways how spline can be initialized would be no harm to have some custom initializers. */ @@ -170,8 +171,8 @@ namespace Movement void computeIndex(float t, index_type& out_idx, float& out_u) const; /** Initializes spline. Don't call other methods while spline not initialized. */ - void init_spline(const Vector3* controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);} - void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point);} + void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation = 0) { SplineBase::init_spline(controls, count, m, orientation);} + void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation = 0) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point, orientation);} /** Initializes lengths with SplineBase::SegLength method. */ void initLengths(); diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index dff4763a4..867471737 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -177,17 +177,18 @@ void Quest::LoadQuestTemplateAddon(Field* fields) PrevQuestId = fields[4].Get(); NextQuestId = fields[5].Get(); ExclusiveGroup = fields[6].Get(); - RewardMailTemplateId = fields[7].Get(); - RewardMailDelay = fields[8].Get(); - RequiredSkillId = fields[9].Get(); - RequiredSkillPoints = fields[10].Get(); - RequiredMinRepFaction = fields[11].Get(); - RequiredMaxRepFaction = fields[12].Get(); - RequiredMinRepValue = fields[13].Get(); - RequiredMaxRepValue = fields[14].Get(); - StartItemCount = fields[15].Get(); - RewardMailSenderEntry = fields[16].Get(); - SpecialFlags = fields[17].Get(); + BreadcrumbForQuestId = fields[7].Get(); + RewardMailTemplateId = fields[8].Get(); + RewardMailDelay = fields[9].Get(); + RequiredSkillId = fields[10].Get(); + RequiredSkillPoints = fields[11].Get(); + RequiredMinRepFaction = fields[12].Get(); + RequiredMaxRepFaction = fields[13].Get(); + RequiredMinRepValue = fields[14].Get(); + RequiredMaxRepValue = fields[15].Get(); + StartItemCount = fields[16].Get(); + RewardMailSenderEntry = fields[17].Get(); + SpecialFlags = fields[18].Get(); if ((SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) && !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT)) { diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 97bd2f759..f074592c0 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -249,6 +249,7 @@ public: [[nodiscard]] int32 GetPrevQuestId() const { return PrevQuestId; } [[nodiscard]] uint32 GetNextQuestId() const { return NextQuestId; } [[nodiscard]] int32 GetExclusiveGroup() const { return ExclusiveGroup; } + [[nodiscard]] uint32 GetBreadcrumbForQuestId() const { return BreadcrumbForQuestId; } [[nodiscard]] uint32 GetNextQuestInChain() const { return RewardNextQuest; } [[nodiscard]] uint32 GetCharTitleId() const { return RewardTitleId; } [[nodiscard]] uint32 GetPlayersSlain() const { return RequiredPlayerKills; } @@ -390,6 +391,7 @@ protected: int32 PrevQuestId = 0; uint32 NextQuestId = 0; int32 ExclusiveGroup = 0; + uint32 BreadcrumbForQuestId = 0; uint32 RewardMailTemplateId = 0; uint32 RewardMailDelay = 0; uint32 RequiredSkillId = 0; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp index 72ee8b461..aeb35cbf3 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp @@ -89,14 +89,16 @@ struct boss_priestess_delrissa : public BossAI void InitializeAI() override { ScriptedAI::InitializeAI(); - std::list helpersList; - for (uint8 i = 0; i < MAX_HELPERS_COUNT; ++i) - helpersList.push_back(helpersEntries[i]); - Acore::Containers::RandomResize(helpersList, MAX_ACTIVE_HELPERS); - uint8 j = 0; - for (std::list::const_iterator itr = helpersList.begin(); itr != helpersList.end(); ++itr, ++j) - me->SummonCreature(*itr, helpersLocations[j], TEMPSUMMON_MANUAL_DESPAWN, 0); + if (instance->GetBossState(DATA_DELRISSA) != DONE) + { + std::vector helpersList(std::begin(helpersEntries), std::end(helpersEntries)); + Acore::Containers::RandomResize(helpersList, MAX_ACTIVE_HELPERS); + + uint8 j = 0; + for (uint32 entry : helpersList) + me->SummonCreature(entry, helpersLocations[j++], TEMPSUMMON_MANUAL_DESPAWN, 0); + } } void JustSummoned(Creature* summon) override diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index 6b6d656fa..e59ef59c7 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -52,6 +52,11 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } // END }; +BossBoundaryData const boundaries = +{ + { DATA_KAELTHAS, new RectangleBoundary(118.64f, 178.63f, 125.69f, 210.70f) } +}; + Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f }; class instance_magisters_terrace : public InstanceMapScript @@ -65,6 +70,7 @@ public: { SetHeaders(DataHeader); SetBossNumber(MAX_ENCOUNTER); + LoadBossBoundaries(boundaries); SetPersistentDataCount(MAX_PERSISTENT_DATA); LoadObjectData(creatureData, gameobjectData); LoadDoorData(doorData); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index bdf1ba118..d77608b47 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -188,1271 +188,1189 @@ enum MalygosLightOverrides LIGHT_OBSCURE_ARCANE_RUNES = 1825, }; -class boss_malygos : public CreatureScript +struct boss_malygos : public ScriptedAI { -public: - boss_malygos() : CreatureScript("boss_malygos") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_malygos(Creature* c) : ScriptedAI(c), summons(me) { - return GetEyeOfEternityAI(pCreature); + pInstance = me->GetInstanceScript(); } - struct boss_malygosAI : public ScriptedAI + InstanceScript* pInstance; + EventMap events; + SummonList summons; + + uint32 timer1, timer2; + uint8 IntroCounter; + bool bLockHealthCheck; + + void InitializeAI() override { - boss_malygosAI(Creature* c) : ScriptedAI(c), summons(me) + me->SetDisableGravity(true); + Reset(); + } + + void Reset() override + { + events.Reset(); + events.SetPhase(PHASE_NONE); + summons.DespawnAll(); + + timer1 = MalygosIntroIntervals[4]; + timer2 = INTRO_MOVEMENT_INTERVAL; + IntroCounter = 0; + bLockHealthCheck = false; + + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + + me->SetAnimTier(AnimTier::Fly); + + if (pInstance) { - pInstance = me->GetInstanceScript(); + pInstance->SetData(DATA_ENCOUNTER_STATUS, NOT_STARTED); + pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_YOU_DONT_HAVE_AN_ENTERNITY_EVENT); + } + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE) + { + switch (id) + { + case MI_POINT_INTRO_SIDE_0: + case MI_POINT_INTRO_SIDE_1: + case MI_POINT_INTRO_SIDE_2: + case MI_POINT_INTRO_SIDE_3: + { + float angle = me->GetOrientation(); + float dist = 75.0f; + if (Creature* c = me->SummonCreature(NPC_PORTAL, me->GetPositionX() + cos(angle) * dist, me->GetPositionY() + std::sin(angle) * dist, me->GetPositionZ(), FourSidesPos[id].GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 13000)) + me->CastSpell(c, SPELL_PORTAL_BEAM, false); + timer2 = INTRO_MOVEMENT_INTERVAL - 10000; + } + break; + + case MI_POINT_INTRO_CENTER_AIR: + events.RescheduleEvent(EVENT_INTRO_LAND, 0ms, 1); + break; + case MI_POINT_VORTEX_CENTER: + if (Creature* c = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 15000)) + c->CastSpell(c, SPELL_VORTEX_VISUAL, true); + events.RescheduleEvent(EVENT_START_VORTEX_REAL, 1s, 1); + break; + case MI_POINT_CENTER_GROUND_PH_2: + events.RescheduleEvent(EVENT_START_PHASE_2_FLY_UP, 0ms, 1); + break; + case MI_POINT_CIRCLE_OUTSIDE_PH_2: + events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 0ms, 1); + break; + case MI_POINT_SURGE_OF_POWER_CENTER: + events.RescheduleEvent(EVENT_SURGE_OF_POWER_WARNING, 0ms, 1); + break; + case MI_POINT_INTRO_LAND: + me->SetDisableGravity(false); + events.RescheduleEvent(EVENT_START_FIGHT, 0ms, 1); + break; + case MI_POINT_VORTEX_TAKEOFF: + events.RescheduleEvent(EVENT_VORTEX_FLY_TO_CENTER, 0ms, 1); + break; + case MI_POINT_VORTEX_LAND: + me->SetDisableGravity(false); + events.RescheduleEvent(EVENT_VORTEX_LAND_1, 0ms, 1); + break; + case MI_POINT_CENTER_AIR_PH_2: + me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_ARCANE_RUNES, 5s); + break; + case MI_POINT_PH_3_FIGHT_POSITION: + events.RescheduleEvent(EVENT_START_PHASE_3, 6s, 1); + break; + } + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_POWER_SPARK_MALYGOS_BUFF) + { + if (!bLockHealthCheck) + { + Talk(SAY_BUFFED_BY_SPARK); + } + else + me->RemoveAura(SPELL_POWER_SPARK_MALYGOS_BUFF); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.Reset(); + DoZoneInCombat(); + + Talk(SAY_PHASE_1); + + events.RescheduleEvent(EVENT_INTRO_MOVE_CENTER, 0ms, 1); + if (pInstance) + pInstance->SetData(DATA_ENCOUNTER_STATUS, IN_PROGRESS); + } + + void AttackStart(Unit* victim) override + { + if (!victim) + return; + + if (me->GetVictim() && me->GetVictim()->GetGUID() == victim->GetGUID() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)) + { + if (!me->GetGuidValue(UNIT_FIELD_TARGET)) + me->SetTarget(victim->GetGUID()); + } + else if (me->Attack(victim, true)) + { + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)) + me->GetMotionMaster()->MoveChase(victim); + else + me->SetTarget(); + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth() && !me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) // allow dying only in phase 3! + { + damage = 0; + return; } - InstanceScript* pInstance; - EventMap events; - SummonList summons; - - uint32 timer1, timer2; - uint8 IntroCounter; - bool bLockHealthCheck; - - void InitializeAI() override + if (!bLockHealthCheck && me->HealthBelowPctDamaged(50, damage)) { - me->SetDisableGravity(true); - Reset(); + bLockHealthCheck = true; + events.RescheduleEvent(EVENT_START_PHASE_2, 0ms, 1); } + } - void Reset() override + void UpdateAI(uint32 diff) override + { + HandleIntroSpeech(diff); + + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - events.Reset(); - events.SetPhase(PHASE_NONE); + case 0: + break; + case EVENT_BERSERK: + me->CastSpell(me, SPELL_BERSERK, true); + Talk(EMOTE_BERSERK); + + break; + case EVENT_INTRO_MOVE_CENTER: + { + if (pInstance) + pInstance->SetData(DATA_SET_IRIS_INACTIVE, 0); summons.DespawnAll(); - - timer1 = MalygosIntroIntervals[4]; - timer2 = INTRO_MOVEMENT_INTERVAL; - IntroCounter = 0; - bLockHealthCheck = false; - - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); - - me->SetAnimTier(AnimTier::Fly); - + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + float angle = CenterPos.GetAngle(me); + float x = CenterPos.GetPositionX() + cos(angle) * 35.0f; + float y = CenterPos.GetPositionY() + std::sin(angle) * 35.0f; + float z = FourSidesPos[0].GetPositionZ(); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_CENTER_AIR, x, y, z); + break; + } + case EVENT_INTRO_LAND: + { + me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_LAND, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ(), FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Ground); + break; + } + case EVENT_START_FIGHT: + { if (pInstance) { - pInstance->SetData(DATA_ENCOUNTER_STATUS, NOT_STARTED); - pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_YOU_DONT_HAVE_AN_ENTERNITY_EVENT); + pInstance->SetData(DATA_HIDE_IRIS_AND_PORTAL, 0); + pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_YOU_DONT_HAVE_AN_ENTERNITY_EVENT); } - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE) + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); + if (Unit* target = me->SelectNearestTarget(250.0f)) { - switch (id) - { - case MI_POINT_INTRO_SIDE_0: - case MI_POINT_INTRO_SIDE_1: - case MI_POINT_INTRO_SIDE_2: - case MI_POINT_INTRO_SIDE_3: - { - float angle = me->GetOrientation(); - float dist = 75.0f; - if (Creature* c = me->SummonCreature(NPC_PORTAL, me->GetPositionX() + cos(angle) * dist, me->GetPositionY() + std::sin(angle) * dist, me->GetPositionZ(), FourSidesPos[id].GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 13000)) - me->CastSpell(c, SPELL_PORTAL_BEAM, false); - timer2 = INTRO_MOVEMENT_INTERVAL - 10000; - } - break; - - case MI_POINT_INTRO_CENTER_AIR: - events.RescheduleEvent(EVENT_INTRO_LAND, 0ms, 1); - break; - case MI_POINT_VORTEX_CENTER: - if (Creature* c = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 15000)) - c->CastSpell(c, SPELL_VORTEX_VISUAL, true); - events.RescheduleEvent(EVENT_START_VORTEX_REAL, 1s, 1); - break; - case MI_POINT_CENTER_GROUND_PH_2: - events.RescheduleEvent(EVENT_START_PHASE_2_FLY_UP, 0ms, 1); - break; - case MI_POINT_CIRCLE_OUTSIDE_PH_2: - events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 0ms, 1); - break; - case MI_POINT_SURGE_OF_POWER_CENTER: - events.RescheduleEvent(EVENT_SURGE_OF_POWER_WARNING, 0ms, 1); - break; - case MI_POINT_INTRO_LAND: - me->SetDisableGravity(false); - events.RescheduleEvent(EVENT_START_FIGHT, 0ms, 1); - break; - case MI_POINT_VORTEX_TAKEOFF: - events.RescheduleEvent(EVENT_VORTEX_FLY_TO_CENTER, 0ms, 1); - break; - case MI_POINT_VORTEX_LAND: - me->SetDisableGravity(false); - events.RescheduleEvent(EVENT_VORTEX_LAND_1, 0ms, 1); - break; - case MI_POINT_CENTER_AIR_PH_2: - me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_ARCANE_RUNES, 5s); - break; - case MI_POINT_PH_3_FIGHT_POSITION: - events.RescheduleEvent(EVENT_START_PHASE_3, 6s, 1); - break; - } + AttackStart(target); + me->GetMotionMaster()->MoveChase(target); } - } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + events.SetPhase(PHASE_ONE); + events.RescheduleEvent(EVENT_BERSERK, 10min, 0); + events.RescheduleEvent(EVENT_SPELL_ARCANE_BREATH, 9s, 12s, 1); + events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 2s, 5s, 1); + events.RescheduleEvent(EVENT_SUMMON_POWER_SPARK, 10s, 15s, 1); + events.RescheduleEvent(EVENT_START_VORTEX_0, 30s, 1); + break; + } + case EVENT_SPELL_ARCANE_BREATH: + me->CastSpell(me->GetVictim(), SPELL_ARCANE_BREATH, false); + events.Repeat(12s, 15s); + break; + case EVENT_SPELL_ARCANE_STORM: + me->CastCustomSpell(SPELL_ARCANE_STORM, SPELLVALUE_MAX_TARGETS, DUNGEON_MODE(5, 12), me, true); + events.Repeat(10s, 15s); + break; + case EVENT_SUMMON_POWER_SPARK: { - if (spell->Id == SPELL_POWER_SPARK_MALYGOS_BUFF) + uint8 random = urand(0, 3); + if (Creature* c = me->SummonCreature(NPC_PORTAL, FourSidesPos[random], TEMPSUMMON_TIMED_DESPAWN, 6000)) + c->CastSpell(c, SPELL_PORTAL_BEAM, false); + if (Creature* c = me->SummonCreature(NPC_POWER_SPARK, FourSidesPos[random], TEMPSUMMON_MANUAL_DESPAWN, 0)) { - if (!bLockHealthCheck) - { - Talk(SAY_BUFFED_BY_SPARK); - } - else - me->RemoveAura(SPELL_POWER_SPARK_MALYGOS_BUFF); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.Reset(); - DoZoneInCombat(); - - Talk(SAY_PHASE_1); - - events.RescheduleEvent(EVENT_INTRO_MOVE_CENTER, 0ms, 1); - if (pInstance) - pInstance->SetData(DATA_ENCOUNTER_STATUS, IN_PROGRESS); - } - - void AttackStart(Unit* victim) override - { - if (!victim) - return; - - if (me->GetVictim() && me->GetVictim()->GetGUID() == victim->GetGUID() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)) - { - if (!me->GetGuidValue(UNIT_FIELD_TARGET)) - me->SetTarget(victim->GetGUID()); - } - else if (me->Attack(victim, true)) - { - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)) - me->GetMotionMaster()->MoveChase(victim); - else - me->SetTarget(); - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth() && !me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) // allow dying only in phase 3! - { - damage = 0; - return; + c->AI()->DoAction(1); + c->AI()->Talk(EMOTE_POWER_SPARK); } - if (!bLockHealthCheck && me->HealthBelowPctDamaged(50, damage)) - { - bLockHealthCheck = true; - events.RescheduleEvent(EVENT_START_PHASE_2, 0ms, 1); - } + events.Repeat(20s, 30s); } - - void UpdateAI(uint32 diff) override + break; + case EVENT_START_VORTEX_0: { - HandleIntroSpeech(diff); + bLockHealthCheck = true; + Talk(SAY_MAGIC_BLAST); + EntryCheckPredicate pred(NPC_POWER_SPARK); + summons.DoAction(2, pred); // stop following + me->SetUnitFlag(UNIT_FLAG_PACIFIED); - if (!UpdateVictim()) - return; + me->SendMeleeAttackStop(me->GetVictim()); + me->SetTarget(); - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_BERSERK: - me->CastSpell(me, SPELL_BERSERK, true); - Talk(EMOTE_BERSERK); - - break; - case EVENT_INTRO_MOVE_CENTER: - { - if (pInstance) - pInstance->SetData(DATA_SET_IRIS_INACTIVE, 0); - summons.DespawnAll(); - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - float angle = CenterPos.GetAngle(me); - float x = CenterPos.GetPositionX() + cos(angle) * 35.0f; - float y = CenterPos.GetPositionY() + std::sin(angle) * 35.0f; - float z = FourSidesPos[0].GetPositionZ(); - me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_CENTER_AIR, x, y, z); - break; - } - case EVENT_INTRO_LAND: - { - me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_LAND, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ(), FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Ground); - break; - } - case EVENT_START_FIGHT: - { - if (pInstance) - { - pInstance->SetData(DATA_HIDE_IRIS_AND_PORTAL, 0); - pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_YOU_DONT_HAVE_AN_ENTERNITY_EVENT); - } - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); - if (Unit* target = me->SelectNearestTarget(250.0f)) - { - AttackStart(target); - me->GetMotionMaster()->MoveChase(target); - } - - events.SetPhase(PHASE_ONE); - events.RescheduleEvent(EVENT_BERSERK, 10min, 0); - events.RescheduleEvent(EVENT_SPELL_ARCANE_BREATH, 9s, 12s, 1); - events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 2s, 5s, 1); - events.RescheduleEvent(EVENT_SUMMON_POWER_SPARK, 10s, 15s, 1); - events.RescheduleEvent(EVENT_START_VORTEX_0, 30s, 1); - break; - } - case EVENT_SPELL_ARCANE_BREATH: - me->CastSpell(me->GetVictim(), SPELL_ARCANE_BREATH, false); - events.Repeat(12s, 15s); - break; - case EVENT_SPELL_ARCANE_STORM: - me->CastCustomSpell(SPELL_ARCANE_STORM, SPELLVALUE_MAX_TARGETS, DUNGEON_MODE(5, 12), me, true); - events.Repeat(10s, 15s); - break; - case EVENT_SUMMON_POWER_SPARK: - { - uint8 random = urand(0, 3); - if (Creature* c = me->SummonCreature(NPC_PORTAL, FourSidesPos[random], TEMPSUMMON_TIMED_DESPAWN, 6000)) - c->CastSpell(c, SPELL_PORTAL_BEAM, false); - if (Creature* c = me->SummonCreature(NPC_POWER_SPARK, FourSidesPos[random], TEMPSUMMON_MANUAL_DESPAWN, 0)) - { - c->AI()->DoAction(1); - c->AI()->Talk(EMOTE_POWER_SPARK); - } - - events.Repeat(20s, 30s); - } - break; - case EVENT_START_VORTEX_0: - { - bLockHealthCheck = true; - Talk(SAY_MAGIC_BLAST); - EntryCheckPredicate pred(NPC_POWER_SPARK); - summons.DoAction(2, pred); // stop following - me->SetUnitFlag(UNIT_FLAG_PACIFIED); - - me->SendMeleeAttackStop(me->GetVictim()); - me->SetTarget(); - - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_TAKEOFF, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ() + 20.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); - - events.DelayEvents(25s, 1); // don't delay berserk (group 0) - } - break; - case EVENT_VORTEX_FLY_TO_CENTER: - me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_CENTER, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 20.0f); - break; - case EVENT_START_VORTEX_REAL: - { - me->SendMeleeAttackStop(me->GetVictim()); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); - me->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); - - Position pos; - float angle = (me->GetOrientation() >= M_PI / 4 ? me->GetOrientation() - M_PI / 4 : 7 * M_PI / 4 + me->GetOrientation()); - pos.m_positionX = CenterPos.GetPositionX() + cos(angle) * 40.0f; - pos.m_positionY = CenterPos.GetPositionY() + std::sin(angle) * 40.0f; - pos.m_positionZ = CenterPos.GetPositionZ() + 20.0f; - pos.SetOrientation(pos.GetAngle(&CenterPos)); - - if (Creature* vp = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, pos, TEMPSUMMON_TIMED_DESPAWN, 14000)) - { - vp->SetDisableGravity(true); - - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - if (!PlayerList.IsEmpty()) - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (Player* pPlayer = i->GetSource()) - { - if (!pPlayer->IsAlive() || pPlayer->IsGameMaster()) - continue; - - Position plrpos; - float playerAngle = CenterPos.GetAngle(pPlayer); - plrpos.m_positionX = CenterPos.GetPositionX() + cos(playerAngle) * 5.0f; - plrpos.m_positionY = CenterPos.GetPositionY() + std::sin(playerAngle) * 5.0f; - plrpos.m_positionZ = CenterPos.GetPositionZ() + 18.0f; - plrpos.SetOrientation(plrpos.GetAngle(&CenterPos)); - - if (Creature* c = me->SummonCreature(NPC_VORTEX, plrpos, TEMPSUMMON_TIMED_DESPAWN, 15000)) - { - pPlayer->CastSpell(pPlayer, SPELL_FREEZE_ANIM, true); - pPlayer->CastSpell(c, SPELL_VORTEX_CONTROL_VEHICLE, true); - if (!pPlayer->GetVehicle()) // didn't work somehow, try again with a different way, if fails - break - { - pPlayer->EnterVehicle(c, 0); - if (!pPlayer->GetVehicle()) - continue; - } - //pPlayer->ClearUnitState(UNIT_STATE_ONVEHICLE); - - Movement::MoveSplineInit init(pPlayer); // TODO: has to be removed and handled with vehicle exit and vehicle enter code - init.MoveTo(CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ()); - init.SetFacing(pPlayer->GetOrientation()); - init.SetTransportExit(); - init.Launch(); - - pPlayer->SetUnitMovementFlags(MOVEMENTFLAG_NONE); - pPlayer->SetDisableGravity(true); - - WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); - data << pPlayer->GetPackGUID(); - pPlayer->SendMessageToSet(&data, true); - - sScriptMgr->AnticheatSetUnderACKmount(pPlayer); - - pPlayer->SetGuidValue(PLAYER_FARSIGHT, vp->GetGUID()); - c->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - } - } - - events.RescheduleEvent(EVENT_VORTEX_LAND_0, 11s, 1); - break; - } - case EVENT_VORTEX_LAND_0: - me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_LAND, CenterPos, FORCED_MOVEMENT_RUN, 0.f, true, true, AnimTier::Ground); - - break; - case EVENT_VORTEX_LAND_1: - { - bLockHealthCheck = false; - EntryCheckPredicate pred(NPC_POWER_SPARK); - summons.DoAction(1, pred); // resume following - me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); - if (Unit* target = me->GetVictim()) - { - AttackStart(target); - me->GetMotionMaster()->MoveChase(target); - } - events.RescheduleEvent(EVENT_START_VORTEX_0, 60s, 1); - break; - } - case EVENT_START_PHASE_2: - events.SetPhase(PHASE_TWO); - Talk(SAY_END_P1); - me->SetUnitFlag(UNIT_FLAG_PACIFIED); - me->SendMeleeAttackStop(); - me->SetTarget(); - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->GetMotionMaster()->MovePoint(MI_POINT_CENTER_GROUND_PH_2, CenterPos); - events.CancelEventGroup(1); // don't cancel berserk (group 0) - break; - case EVENT_START_PHASE_2_FLY_UP: - { - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(MI_POINT_CENTER_AIR_PH_2, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 32.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); - events.RescheduleEvent(EVENT_START_PHASE_2_MOVE_TO_SIDE, 22s + 500ms, 1); - break; - } - case EVENT_START_PHASE_2_MOVE_TO_SIDE: - Talk(SAY_PHASE_2); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); - me->GetMotionMaster()->MovePoint(MI_POINT_CIRCLE_OUTSIDE_PH_2, Phase2NorthPos); - events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 12s, 15s, 1); - events.RescheduleEvent(EVENT_SPELL_ARCANE_OVERLOAD, 8s, 1); - events.RescheduleEvent(EVENT_MOVE_TO_SURGE_OF_POWER, 55s, 1); - events.RescheduleEvent(EVENT_CHECK_TRASH_DEAD, 3s, 1); - - for (int i = 0; i < MAX_NEXUS_LORDS; i++) - { - float dist = 22.0f; - float angle = M_PI / 2 + ((float)i / MAX_NEXUS_LORDS) * 2 * M_PI; - if (Creature* disk = me->SummonCreature(NPC_HOVER_DISK, CenterPos.GetPositionX() + cos(angle) * dist, CenterPos.GetPositionY() + std::sin(angle) * dist, CenterPos.GetPositionZ() + 30.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) - if (Creature* c = me->SummonCreature(NPC_NEXUS_LORD, *disk, TEMPSUMMON_MANUAL_DESPAWN, 0)) - { - c->EnterVehicle(disk, 0); - disk->AI()->DoAction(1); // start moving - } - } - for (int i = 0; i < MAX_SCIONS_OF_ETERNITY; i++) - { - float dist = 30.0f; - float angle = 0.0f + ((float)i / MAX_SCIONS_OF_ETERNITY) * 2 * M_PI; - if (Creature* disk = me->SummonCreature(NPC_HOVER_DISK, CenterPos.GetPositionX() + cos(angle) * dist, CenterPos.GetPositionY() + std::sin(angle) * dist, CenterPos.GetPositionZ() + 30.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) - if (Creature* c = me->SummonCreature(NPC_SCION_OF_ETERNITY, *disk, TEMPSUMMON_MANUAL_DESPAWN, 0)) - { - c->EnterVehicle(disk, 0); - disk->AI()->DoAction(1); // start moving - } - } - - break; - case EVENT_SPELL_ARCANE_OVERLOAD: - { - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - float dist = urand(5, 30); - float angle = rand_norm() * 2 * M_PI; - float posx = CenterPos.GetPositionX() + cos(angle) * dist; - float posy = CenterPos.GetPositionY() + std::sin(angle) * dist; - me->SetFacingTo(me->GetAngle(posx, posy)); - me->CastSpell(posx, posy, CenterPos.GetPositionZ() + 1.5f, SPELL_ARCANE_OVERLOAD, true); - events.Repeat(15s); - events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 3s, 1); - } - break; - case EVENT_RESUME_FLYING_CIRCLES_PH_2: - { - float angle = CenterPos.GetAngle(me); - float dist = Phase2NorthPos.GetExactDist2d(&CenterPos); - float newangle = angle + 0.5f; - if (newangle >= 2 * M_PI) newangle -= 2 * M_PI; - me->GetMotionMaster()->MovePoint(MI_POINT_CIRCLE_OUTSIDE_PH_2, CenterPos.GetPositionX() + cos(newangle)*dist, CenterPos.GetPositionY() + std::sin(newangle)*dist, Phase2NorthPos.GetPositionZ()); - } - break; - case EVENT_MOVE_TO_SURGE_OF_POWER: - { - Talk(SAY_DEEP_BREATH); - float angle = CenterPos.GetAngle(me); - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - me->GetMotionMaster()->MovePoint(MI_POINT_SURGE_OF_POWER_CENTER, CenterPos.GetPositionX() + cos(angle) * 10.0f, CenterPos.GetPositionY() + std::sin(angle) * 10.0f, Phase2NorthPos.GetPositionZ()); - events.CancelEventGroup(1); // everything beside berserk - } - break; - case EVENT_SURGE_OF_POWER_WARNING: - Talk(EMOTE_SURGE_OF_POWER_WARNING_P2); - events.RescheduleEvent(EVENT_SPELL_SURGE_OF_POWER, 1500ms, 1); - break; - case EVENT_SPELL_SURGE_OF_POWER: - if (Creature* c = me->SummonCreature(NPC_SURGE_OF_POWER, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 10000)) - me->CastSpell(c, SPELL_SURGE_OF_POWER, false); - Talk(SAY_SURGE_OF_POWER); - events.RescheduleEvent(EVENT_CLEAR_TARGET, 10s, 1); - events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 10s, 1); - events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 17s, 25s, 1); - events.RescheduleEvent(EVENT_SPELL_ARCANE_OVERLOAD, 16s, 1); - events.RescheduleEvent(EVENT_MOVE_TO_SURGE_OF_POWER, 65s, 1); - events.RescheduleEvent(EVENT_CHECK_TRASH_DEAD, 3s, 1); - break; - case EVENT_CLEAR_TARGET: - me->SendMeleeAttackStop(); - me->SetTarget(); - break; - case EVENT_CHECK_TRASH_DEAD: - { - if (me->FindNearestCreature(NPC_SCION_OF_ETERNITY, 250.0f, true) || me->FindNearestCreature(NPC_NEXUS_LORD, 250.0f, true)) - events.Repeat(3s); - else - { - me->SendMeleeAttackStop(); - me->SetTarget(); - events.CancelEventGroup(1); - summons.DespawnAll(); - // start phase 3 - Talk(SAY_END_P2); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - me->GetMotionMaster()->MovePoint(MI_POINT_START_PH_3, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 70.0f); - events.RescheduleEvent(EVENT_LIGHT_DIMENSION_CHANGE, 1s, 1); - events.RescheduleEvent(EVENT_DESTROY_PLATFORM_0, 10s, 1); - } - } - break; - case EVENT_LIGHT_DIMENSION_CHANGE: - me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_CHANGE_DIMENSIONS, 2s); - break; - case EVENT_DESTROY_PLATFORM_0: - if (Creature* c = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 3000)) - { - c->SetFaction(me->GetFaction()); - c->CastSpell(c, SPELL_DESTROY_PLATFORM_VISUAL, true); - c->CastSpell(c, SPELL_DESTROY_PLATFORM_EFFECT, false); - } - me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_OBSCURE_SPACE, 1s); - events.RescheduleEvent(EVENT_MOVE_TO_PHASE_3_POSITION, 2s, 1); - break; - case EVENT_MOVE_TO_PHASE_3_POSITION: - { - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MovePoint(MI_POINT_PH_3_FIGHT_POSITION, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() - 5.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); - - me->GetThreatMgr().ClearAllThreat(); // players on vehicle are unattackable -> leads to EnterEvadeMode() because target is not acceptable! - - // mount players: - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - if (!PlayerList.IsEmpty()) - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (Player* pPlayer = i->GetSource()) - { - sScriptMgr->AnticheatSetUnderACKmount(pPlayer); - - if (!pPlayer->IsAlive() || pPlayer->IsGameMaster()) - continue; - - if (Creature* c = me->SummonCreature(NPC_WYRMREST_SKYTALON, pPlayer->GetPositionX(), pPlayer->GetPositionY(), pPlayer->GetPositionZ() - 20.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) - { - c->SetFaction(pPlayer->GetFaction()); - //pPlayer->CastCustomSpell(60683, SPELLVALUE_BASE_POINT0, 1, c, true); - c->m_Events.AddEventAtOffset(new EoEDrakeEnterVehicleEvent(*c, pPlayer->GetGUID()), 500ms); - AttackStart(c); - } - } - - events.RescheduleEvent(EVENT_SAY_PHASE_3_INTRO, 3s, 1); - } - break; - case EVENT_SAY_PHASE_3_INTRO: - Talk(SAY_INTRO_PHASE_3); - break; - case EVENT_START_PHASE_3: - events.SetPhase(PHASE_THREE); - me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_OBSCURE_ARCANE_RUNES, 1s); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetUnitFlag(UNIT_FLAG_PACIFIED | UNIT_FLAG_DISABLE_MOVE); - if (Unit* target = me->GetVictim()) - AttackStart(target); - events.RescheduleEvent(EVENT_SPELL_ARCANE_PULSE, 0ms, 1); - events.RescheduleEvent(EVENT_SPELL_STATIC_FIELD, 1s, 4s, 1); - events.RescheduleEvent(EVENT_SPELL_PH3_SURGE_OF_POWER, 4s, 7s, 1); - events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 12s, 15s, 1); - break; - case EVENT_SPELL_ARCANE_PULSE: - me->CastSpell(me, SPELL_ARCANE_PULSE, true); - events.Repeat(3s); - break; - case EVENT_SPELL_STATIC_FIELD: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, false)) - { - me->SetFacingToObject(target); - me->CastSpell(target, SPELL_STATIC_FIELD_MAIN, true); - } - events.Repeat(12s); - break; - case EVENT_SPELL_PH3_SURGE_OF_POWER: - me->CastSpell((Unit*)nullptr, SPELL_PH3_SURGE_OF_POWER, false); - events.Repeat(7s); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - if (pInstance) - { - pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_MALYGOS, 1); - pInstance->SetData(DATA_ENCOUNTER_STATUS, DONE); - } - } - - void KilledUnit(Unit* victim) override - { - if (victim && victim->GetGUID() == me->GetGUID()) - return; - - if (events.IsInPhase(PHASE_ONE)) - Talk(SAY_SLAY_P1); - else if (events.IsInPhase(PHASE_TWO)) - Talk(SAY_SLAY_P2); - else - Talk(SAY_SLAY_P3); - } - - void JustSummoned(Creature* summon) override - { - if (!summon) - return; - summons.Summon(summon); - switch (summon->GetEntry()) - { - case NPC_ARCANE_OVERLOAD: - summon->CastSpell(summon, SPELL_ARCANE_OVERLOAD_DMG, true); - summon->DespawnOrUnsummon(45s); - break; - case NPC_STATIC_FIELD: - summon->DespawnOrUnsummon(20s); - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason why) override - { + me->GetMotionMaster()->MoveIdle(); + me->StopMoving(); me->SetDisableGravity(true); - me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_GET_DEFAULT_FOR_MAP, 1s); + me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_TAKEOFF, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ() + 20.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); - ScriptedAI::EnterEvadeMode(why); + events.DelayEvents(25s, 1); // don't delay berserk (group 0) + } + break; + case EVENT_VORTEX_FLY_TO_CENTER: + me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_CENTER, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 20.0f); + break; + case EVENT_START_VORTEX_REAL: + { + me->SendMeleeAttackStop(me->GetVictim()); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); + me->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); + + Position pos; + float angle = (me->GetOrientation() >= M_PI / 4 ? me->GetOrientation() - M_PI / 4 : 7 * M_PI / 4 + me->GetOrientation()); + pos.m_positionX = CenterPos.GetPositionX() + cos(angle) * 40.0f; + pos.m_positionY = CenterPos.GetPositionY() + std::sin(angle) * 40.0f; + pos.m_positionZ = CenterPos.GetPositionZ() + 20.0f; + pos.SetOrientation(pos.GetAngle(&CenterPos)); + + if (Creature* vp = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, pos, TEMPSUMMON_TIMED_DESPAWN, 14000)) + { + vp->SetDisableGravity(true); + + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + if (!PlayerList.IsEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (Player* pPlayer = i->GetSource()) + { + if (!pPlayer->IsAlive() || pPlayer->IsGameMaster()) + continue; + + Position plrpos; + float playerAngle = CenterPos.GetAngle(pPlayer); + plrpos.m_positionX = CenterPos.GetPositionX() + cos(playerAngle) * 5.0f; + plrpos.m_positionY = CenterPos.GetPositionY() + std::sin(playerAngle) * 5.0f; + plrpos.m_positionZ = CenterPos.GetPositionZ() + 18.0f; + plrpos.SetOrientation(plrpos.GetAngle(&CenterPos)); + + if (Creature* c = me->SummonCreature(NPC_VORTEX, plrpos, TEMPSUMMON_TIMED_DESPAWN, 15000)) + { + pPlayer->CastSpell(pPlayer, SPELL_FREEZE_ANIM, true); + pPlayer->CastSpell(c, SPELL_VORTEX_CONTROL_VEHICLE, true); + if (!pPlayer->GetVehicle()) // didn't work somehow, try again with a different way, if fails - break + { + pPlayer->EnterVehicle(c, 0); + if (!pPlayer->GetVehicle()) + continue; + } + //pPlayer->ClearUnitState(UNIT_STATE_ONVEHICLE); + + Movement::MoveSplineInit init(pPlayer); // TODO: has to be removed and handled with vehicle exit and vehicle enter code + init.MoveTo(CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ()); + init.SetFacing(pPlayer->GetOrientation()); + init.SetTransportExit(); + init.Launch(); + + pPlayer->SetUnitMovementFlags(MOVEMENTFLAG_NONE); + pPlayer->SetDisableGravity(true); + + WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); + data << pPlayer->GetPackGUID(); + pPlayer->SendMessageToSet(&data, true); + + sScriptMgr->AnticheatSetUnderACKmount(pPlayer); + + pPlayer->SetGuidValue(PLAYER_FARSIGHT, vp->GetGUID()); + c->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + } + } + + events.RescheduleEvent(EVENT_VORTEX_LAND_0, 11s, 1); + break; + } + case EVENT_VORTEX_LAND_0: + me->GetMotionMaster()->MovePoint(MI_POINT_VORTEX_LAND, CenterPos, FORCED_MOVEMENT_RUN, 0.f, true, true, AnimTier::Ground); + + break; + case EVENT_VORTEX_LAND_1: + { + bLockHealthCheck = false; + EntryCheckPredicate pred(NPC_POWER_SPARK); + summons.DoAction(1, pred); // resume following + me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); + if (Unit* target = me->GetVictim()) + { + AttackStart(target); + me->GetMotionMaster()->MoveChase(target); + } + events.RescheduleEvent(EVENT_START_VORTEX_0, 60s, 1); + break; + } + case EVENT_START_PHASE_2: + events.SetPhase(PHASE_TWO); + Talk(SAY_END_P1); + me->SetUnitFlag(UNIT_FLAG_PACIFIED); + me->SendMeleeAttackStop(); + me->SetTarget(); + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->GetMotionMaster()->MovePoint(MI_POINT_CENTER_GROUND_PH_2, CenterPos); + events.CancelEventGroup(1); // don't cancel berserk (group 0) + break; + case EVENT_START_PHASE_2_FLY_UP: + { + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(MI_POINT_CENTER_AIR_PH_2, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 32.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); + events.RescheduleEvent(EVENT_START_PHASE_2_MOVE_TO_SIDE, 22s + 500ms, 1); + break; + } + case EVENT_START_PHASE_2_MOVE_TO_SIDE: + Talk(SAY_PHASE_2); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); + me->GetMotionMaster()->MovePoint(MI_POINT_CIRCLE_OUTSIDE_PH_2, Phase2NorthPos); + events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 12s, 15s, 1); + events.RescheduleEvent(EVENT_SPELL_ARCANE_OVERLOAD, 8s, 1); + events.RescheduleEvent(EVENT_MOVE_TO_SURGE_OF_POWER, 55s, 1); + events.RescheduleEvent(EVENT_CHECK_TRASH_DEAD, 3s, 1); + + for (int i = 0; i < MAX_NEXUS_LORDS; i++) + { + float dist = 22.0f; + float angle = M_PI / 2 + ((float)i / MAX_NEXUS_LORDS) * 2 * M_PI; + if (Creature* disk = me->SummonCreature(NPC_HOVER_DISK, CenterPos.GetPositionX() + cos(angle) * dist, CenterPos.GetPositionY() + std::sin(angle) * dist, CenterPos.GetPositionZ() + 30.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + if (Creature* c = me->SummonCreature(NPC_NEXUS_LORD, *disk, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + c->EnterVehicle(disk, 0); + disk->AI()->DoAction(1); // start moving + } + } + for (int i = 0; i < MAX_SCIONS_OF_ETERNITY; i++) + { + float dist = 30.0f; + float angle = 0.0f + ((float)i / MAX_SCIONS_OF_ETERNITY) * 2 * M_PI; + if (Creature* disk = me->SummonCreature(NPC_HOVER_DISK, CenterPos.GetPositionX() + cos(angle) * dist, CenterPos.GetPositionY() + std::sin(angle) * dist, CenterPos.GetPositionZ() + 30.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + if (Creature* c = me->SummonCreature(NPC_SCION_OF_ETERNITY, *disk, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + c->EnterVehicle(disk, 0); + disk->AI()->DoAction(1); // start moving + } + } + + break; + case EVENT_SPELL_ARCANE_OVERLOAD: + { + me->GetMotionMaster()->MoveIdle(); + me->StopMoving(); + float dist = urand(5, 30); + float angle = rand_norm() * 2 * M_PI; + float posx = CenterPos.GetPositionX() + cos(angle) * dist; + float posy = CenterPos.GetPositionY() + std::sin(angle) * dist; + me->SetFacingTo(me->GetAngle(posx, posy)); + me->CastSpell(posx, posy, CenterPos.GetPositionZ() + 1.5f, SPELL_ARCANE_OVERLOAD, true); + events.Repeat(15s); + events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 3s, 1); + } + break; + case EVENT_RESUME_FLYING_CIRCLES_PH_2: + { + float angle = CenterPos.GetAngle(me); + float dist = Phase2NorthPos.GetExactDist2d(&CenterPos); + float newangle = angle + 0.5f; + if (newangle >= 2 * M_PI) newangle -= 2 * M_PI; + me->GetMotionMaster()->MovePoint(MI_POINT_CIRCLE_OUTSIDE_PH_2, CenterPos.GetPositionX() + cos(newangle) * dist, CenterPos.GetPositionY() + std::sin(newangle) * dist, Phase2NorthPos.GetPositionZ()); + } + break; + case EVENT_MOVE_TO_SURGE_OF_POWER: + { + Talk(SAY_DEEP_BREATH); + float angle = CenterPos.GetAngle(me); + me->GetMotionMaster()->MoveIdle(); + me->StopMoving(); + me->GetMotionMaster()->MovePoint(MI_POINT_SURGE_OF_POWER_CENTER, CenterPos.GetPositionX() + cos(angle) * 10.0f, CenterPos.GetPositionY() + std::sin(angle) * 10.0f, Phase2NorthPos.GetPositionZ()); + events.CancelEventGroup(1); // everything beside berserk + } + break; + case EVENT_SURGE_OF_POWER_WARNING: + Talk(EMOTE_SURGE_OF_POWER_WARNING_P2); + events.RescheduleEvent(EVENT_SPELL_SURGE_OF_POWER, 1500ms, 1); + break; + case EVENT_SPELL_SURGE_OF_POWER: + if (Creature* c = me->SummonCreature(NPC_SURGE_OF_POWER, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 10000)) + me->CastSpell(c, SPELL_SURGE_OF_POWER, false); + Talk(SAY_SURGE_OF_POWER); + events.RescheduleEvent(EVENT_CLEAR_TARGET, 10s, 1); + events.RescheduleEvent(EVENT_RESUME_FLYING_CIRCLES_PH_2, 10s, 1); + events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 17s, 25s, 1); + events.RescheduleEvent(EVENT_SPELL_ARCANE_OVERLOAD, 16s, 1); + events.RescheduleEvent(EVENT_MOVE_TO_SURGE_OF_POWER, 65s, 1); + events.RescheduleEvent(EVENT_CHECK_TRASH_DEAD, 3s, 1); + break; + case EVENT_CLEAR_TARGET: + me->SendMeleeAttackStop(); + me->SetTarget(); + break; + case EVENT_CHECK_TRASH_DEAD: + { + if (me->FindNearestCreature(NPC_SCION_OF_ETERNITY, 250.0f, true) || me->FindNearestCreature(NPC_NEXUS_LORD, 250.0f, true)) + events.Repeat(3s); + else + { + me->SendMeleeAttackStop(); + me->SetTarget(); + events.CancelEventGroup(1); + summons.DespawnAll(); + // start phase 3 + Talk(SAY_END_P2); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + me->StopMoving(); + me->GetMotionMaster()->MovePoint(MI_POINT_START_PH_3, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 70.0f); + events.RescheduleEvent(EVENT_LIGHT_DIMENSION_CHANGE, 1s, 1); + events.RescheduleEvent(EVENT_DESTROY_PLATFORM_0, 10s, 1); + } + } + break; + case EVENT_LIGHT_DIMENSION_CHANGE: + me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_CHANGE_DIMENSIONS, 2s); + break; + case EVENT_DESTROY_PLATFORM_0: + if (Creature* c = me->SummonCreature(NPC_WORLD_TRIGGER_LAOI, CenterPos, TEMPSUMMON_TIMED_DESPAWN, 3000)) + { + c->SetFaction(me->GetFaction()); + c->CastSpell(c, SPELL_DESTROY_PLATFORM_VISUAL, true); + c->CastSpell(c, SPELL_DESTROY_PLATFORM_EFFECT, false); + } + me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_OBSCURE_SPACE, 1s); + events.RescheduleEvent(EVENT_MOVE_TO_PHASE_3_POSITION, 2s, 1); + break; + case EVENT_MOVE_TO_PHASE_3_POSITION: + { + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MovePoint(MI_POINT_PH_3_FIGHT_POSITION, CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() - 5.0f, FORCED_MOVEMENT_RUN, 0.f, 0.f, true, true, MOTION_SLOT_ACTIVE, AnimTier::Fly); + + me->GetThreatMgr().ClearAllThreat(); // players on vehicle are unattackable -> leads to EnterEvadeMode() because target is not acceptable! + + // mount players: + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + if (!PlayerList.IsEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (Player* player = i->GetSource()) + { + sScriptMgr->AnticheatSetUnderACKmount(player); + + if (!player->IsAlive() || player->IsGameMaster()) + continue; + + player->CastSpell(player, SPELL_SUMMON_RED_DRAGON_BUDDY, true); + } + + events.RescheduleEvent(EVENT_SAY_PHASE_3_INTRO, 3s, 1); + } + break; + case EVENT_SAY_PHASE_3_INTRO: + Talk(SAY_INTRO_PHASE_3); + break; + case EVENT_START_PHASE_3: + events.SetPhase(PHASE_THREE); + me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_OBSCURE_ARCANE_RUNES, 1s); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetUnitFlag(UNIT_FLAG_PACIFIED | UNIT_FLAG_DISABLE_MOVE); + if (Unit* target = me->GetVictim()) + AttackStart(target); + events.RescheduleEvent(EVENT_SPELL_ARCANE_PULSE, 0ms, 1); + events.RescheduleEvent(EVENT_SPELL_STATIC_FIELD, 1s, 4s, 1); + events.RescheduleEvent(EVENT_SPELL_PH3_SURGE_OF_POWER, 4s, 7s, 1); + events.RescheduleEvent(EVENT_SPELL_ARCANE_STORM, 12s, 15s, 1); + break; + case EVENT_SPELL_ARCANE_PULSE: + me->CastSpell(me, SPELL_ARCANE_PULSE, true); + events.Repeat(3s); + break; + case EVENT_SPELL_STATIC_FIELD: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, false)) + { + me->SetFacingToObject(target); + me->CastSpell(target, SPELL_STATIC_FIELD_MAIN, true); + } + events.Repeat(12s); + break; + case EVENT_SPELL_PH3_SURGE_OF_POWER: + me->CastSpell((Unit*)nullptr, SPELL_PH3_SURGE_OF_POWER, false); + events.Repeat(7s); + break; } - void HandleIntroSpeech(const uint32 diff) - { - if (me->IsInCombat() || me->isDead()) - return; + DoMeleeAttackIfReady(); + } - // speech timer - if (timer1 <= diff) + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + if (pInstance) + { + pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_MALYGOS, 1); + pInstance->SetData(DATA_ENCOUNTER_STATUS, DONE); + } + } + + void KilledUnit(Unit* victim) override + { + if (victim && victim->GetGUID() == me->GetGUID()) + return; + + if (events.IsInPhase(PHASE_ONE)) + Talk(SAY_SLAY_P1); + else if (events.IsInPhase(PHASE_TWO)) + Talk(SAY_SLAY_P2); + else + Talk(SAY_SLAY_P3); + } + + void JustSummoned(Creature* summon) override + { + if (!summon) + return; + summons.Summon(summon); + switch (summon->GetEntry()) + { + case NPC_ARCANE_OVERLOAD: + summon->CastSpell(summon, SPELL_ARCANE_OVERLOAD_DMG, true); + summon->DespawnOrUnsummon(45s); + break; + case NPC_STATIC_FIELD: + summon->DespawnOrUnsummon(20s); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason why) override + { + me->SetDisableGravity(true); + me->GetMap()->SetZoneOverrideLight(AREA_EYE_OF_ETERNITY, LIGHT_GET_DEFAULT_FOR_MAP, 1s); + + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + ScriptedAI::EnterEvadeMode(why); + } + + void HandleIntroSpeech(const uint32 diff) + { + if (me->IsInCombat() || me->isDead()) + return; + + // speech timer + if (timer1 <= diff) + { + Talk(SAY_INTRO); + timer1 = MalygosIntroIntervals[IntroCounter]; + if (++IntroCounter >= 5) + IntroCounter = 0; + } + else + timer1 -= diff; + + // movement timer + if (timer2) + { + if (timer2 <= diff) { - Talk(SAY_INTRO); - timer1 = MalygosIntroIntervals[IntroCounter]; - if (++IntroCounter >= 5) - IntroCounter = 0; + timer2 = 0; + uint32 tmp = urand(0, 3); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_SIDE_0 + tmp, FourSidesPos[tmp]); } else - timer1 -= diff; - - // movement timer - if (timer2) - { - if (timer2 <= diff) - { - timer2 = 0; - uint32 tmp = urand(0, 3); - me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - me->GetMotionMaster()->MovePoint(MI_POINT_INTRO_SIDE_0 + tmp, FourSidesPos[tmp]); - } - else - timer2 -= diff; - } + timer2 -= diff; } - }; + } }; #define VORTEX_DEFAULT_DIFF 250 #define VORTEX_TRAVEL_TIME 3000 //#define VORTEX_RADIUS 25.0f -class npc_vortex_ride : public CreatureScript +struct npc_vortex_ride : public VehicleAI { -public: - npc_vortex_ride() : CreatureScript("npc_vortex_ride") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_vortex_ride(Creature* pCreature) : VehicleAI(pCreature) { - return GetEyeOfEternityAI (pCreature); + VORTEX_RADIUS = urand(22, 28); + float h = urand(15, 30); + float angle = CenterPos.GetAngle(me); + Position pos; + pos.m_positionX = CenterPos.GetPositionX() + VORTEX_RADIUS * cos(angle); + pos.m_positionY = CenterPos.GetPositionY() + VORTEX_RADIUS * std::sin(angle); + pos.m_positionZ = CenterPos.GetPositionZ() + h; + pos.SetOrientation(pos.GetAngle(&CenterPos)); + me->SetPosition(pos); + timer = 0; + despawnTimer = 9500; + bUpdatedFlying = false; } - struct npc_vortex_rideAI : public VehicleAI + uint32 timer; + uint32 despawnTimer; + bool bUpdatedFlying; + float VORTEX_RADIUS; + + void PassengerBoarded(Unit* pass, int8 /*seat*/, bool apply) override { - npc_vortex_rideAI(Creature* pCreature) : VehicleAI(pCreature) + if (pass && !apply && pass->IsPlayer()) + { + Player* plr = pass->ToPlayer(); + float speed = plr->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1.0f * 0.001f); + plr->SetDisableGravity(false); // packet only would lead to issues elsewhere + plr->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed); + plr->RemoveAura(SPELL_FREEZE_ANIM); + plr->SetGuidValue(PLAYER_FARSIGHT, ObjectGuid::Empty); + + sScriptMgr->AnticheatSetCanFlybyServer(plr, false); + sScriptMgr->AnticheatSetUnderACKmount(plr); + } + } + + void UpdateAI(uint32 diff) override + { + /* here: if player has some aura that should make him exit vehicle (eg. ice block) -> exit + or make it another way (dunno how) */ + + if (despawnTimer <= diff) + { + despawnTimer = 0; + me->UpdatePosition(CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 18.0f, 0.0f, true); + me->StopMovingOnCurrentPos(); + if (Vehicle* vehicle = me->GetVehicleKit()) + vehicle->RemoveAllPassengers(); + me->DespawnOrUnsummon(); + return; + } + else + despawnTimer -= diff; + + if (timer <= diff) { - VORTEX_RADIUS = urand(22, 28); - float h = urand(15, 30); float angle = CenterPos.GetAngle(me); - Position pos; - pos.m_positionX = CenterPos.GetPositionX() + VORTEX_RADIUS * cos(angle); - pos.m_positionY = CenterPos.GetPositionY() + VORTEX_RADIUS * std::sin(angle); - pos.m_positionZ = CenterPos.GetPositionZ() + h; - pos.SetOrientation(pos.GetAngle(&CenterPos)); - me->SetPosition(pos); - timer = 0; - despawnTimer = 9500; - bUpdatedFlying = false; - } - - uint32 timer; - uint32 despawnTimer; - bool bUpdatedFlying; - float VORTEX_RADIUS; - - void PassengerBoarded(Unit* pass, int8 /*seat*/, bool apply) override - { - if (pass && !apply && pass->IsPlayer()) + float newangle = angle + 2 * M_PI / ((float)VORTEX_TRAVEL_TIME / VORTEX_DEFAULT_DIFF); + if (newangle >= 2 * M_PI) + newangle -= 2 * M_PI; + float newx = CenterPos.GetPositionX() + VORTEX_RADIUS * cos(newangle); + float newy = CenterPos.GetPositionY() + VORTEX_RADIUS * std::sin(newangle); + float arcangle = me->GetAngle(newx, newy); + float dist = 2 * me->GetDistance2d(newx, newy); + if (me->GetVehicleKit()) if (Unit* pass = me->GetVehicleKit()->GetPassenger(0)) if (Player* plr = pass->ToPlayer()) { - Player* plr = pass->ToPlayer(); - float speed = plr->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1.0f * 0.001f); - plr->SetDisableGravity(false); // packet only would lead to issues elsewhere - plr->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed); - plr->RemoveAura(SPELL_FREEZE_ANIM); - plr->SetGuidValue(PLAYER_FARSIGHT, ObjectGuid::Empty); + if (!bUpdatedFlying && timer) + { + bUpdatedFlying = true; + plr->SetDisableGravity(true); + } - sScriptMgr->AnticheatSetCanFlybyServer(plr, false); - sScriptMgr->AnticheatSetUnderACKmount(plr); + plr->SendMonsterMove(me->GetPositionX() + dist * cos(arcangle), me->GetPositionY() + dist * std::sin(arcangle), me->GetPositionZ(), VORTEX_DEFAULT_DIFF * 2, SPLINEFLAG_FLYING); + me->Relocate(newx, newy); } + + timer = (diff - timer <= VORTEX_DEFAULT_DIFF) ? VORTEX_DEFAULT_DIFF - (diff - timer) : 0; } + else + timer -= diff; + } - void UpdateAI(uint32 diff) override - { - /* here: if player has some aura that should make him exit vehicle (eg. ice block) -> exit - or make it another way (dunno how) */ - - if (despawnTimer <= diff) - { - despawnTimer = 0; - me->UpdatePosition(CenterPos.GetPositionX(), CenterPos.GetPositionY(), CenterPos.GetPositionZ() + 18.0f, 0.0f, true); - me->StopMovingOnCurrentPos(); - if (Vehicle* vehicle = me->GetVehicleKit()) - vehicle->RemoveAllPassengers(); - me->DespawnOrUnsummon(); - return; - } - else - despawnTimer -= diff; - - if (timer <= diff) - { - float angle = CenterPos.GetAngle(me); - float newangle = angle + 2 * M_PI / ((float)VORTEX_TRAVEL_TIME / VORTEX_DEFAULT_DIFF); - if (newangle >= 2 * M_PI) - newangle -= 2 * M_PI; - float newx = CenterPos.GetPositionX() + VORTEX_RADIUS * cos(newangle); - float newy = CenterPos.GetPositionY() + VORTEX_RADIUS * std::sin(newangle); - float arcangle = me->GetAngle(newx, newy); - float dist = 2 * me->GetDistance2d(newx, newy); - if (me->GetVehicleKit()) if (Unit* pass = me->GetVehicleKit()->GetPassenger(0)) if (Player* plr = pass->ToPlayer()) - { - if (!bUpdatedFlying && timer) - { - bUpdatedFlying = true; - plr->SetDisableGravity(true); - } - - plr->SendMonsterMove(me->GetPositionX() + dist * cos(arcangle), me->GetPositionY() + dist * std::sin(arcangle), me->GetPositionZ(), VORTEX_DEFAULT_DIFF * 2, SPLINEFLAG_FLYING); - me->Relocate(newx, newy); - } - - timer = (diff - timer <= VORTEX_DEFAULT_DIFF) ? VORTEX_DEFAULT_DIFF - (diff - timer) : 0; - } - else - timer -= diff; - } - - void AttackStart(Unit* /*who*/) override {} - void MoveInLineOfSight(Unit* /*who*/) override {} - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { damage = 0; } - }; + void AttackStart(Unit* /*who*/) override {} + void MoveInLineOfSight(Unit* /*who*/) override {} + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { damage = 0; } }; -class npc_power_spark : public CreatureScript +struct npc_power_spark : public NullCreatureAI { -public: - npc_power_spark() : CreatureScript("npc_power_spark") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_power_spark(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetEyeOfEternityAI(pCreature); + pInstance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_POWER_SPARK_VISUAL, false); + CheckTimer = 1000; + MoveTimer = 0; } - struct npc_power_sparkAI : public NullCreatureAI + InstanceScript* pInstance; + uint16 CheckTimer; + uint16 MoveTimer; + + void DoAction(int32 param) override { - npc_power_sparkAI(Creature* pCreature) : NullCreatureAI(pCreature) + switch (param) { - pInstance = me->GetInstanceScript(); - me->CastSpell(me, SPELL_POWER_SPARK_VISUAL, false); - CheckTimer = 1000; + case 1: + MoveTimer = 1; + break; + case 2: MoveTimer = 0; + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 0.05f, FORCED_MOVEMENT_NONE, 7.0f); + break; } + } - InstanceScript* pInstance; - uint16 CheckTimer; - uint16 MoveTimer; - - void DoAction(int32 param) override + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth()) { - switch (param) + damage = 0; + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) { - case 1: - MoveTimer = 1; - break; - case 2: - MoveTimer = 0; - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 0.05f, FORCED_MOVEMENT_NONE, 7.0f); - break; + MoveTimer = 0; + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ(), FORCED_MOVEMENT_NONE, 100.0f); + me->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + me->RemoveAura(SPELL_POWER_SPARK_VISUAL); + me->CastSpell(me, SPELL_POWER_SPARK_GROUND_BUFF, true); + me->DespawnOrUnsummon(60s); } } + } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + void UpdateAI(uint32 diff) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + if (CheckTimer <= diff) { - if (damage >= me->GetHealth()) - { - damage = 0; - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - { - MoveTimer = 0; - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), CenterPos.GetPositionZ(), FORCED_MOVEMENT_NONE, 100.0f); - me->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); - me->RemoveAura(SPELL_POWER_SPARK_VISUAL); - me->CastSpell(me, SPELL_POWER_SPARK_GROUND_BUFF, true); - me->DespawnOrUnsummon(60s); - } - } + if (pInstance) + if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_MALYGOS_GUID))) + if (me->IsWithinDist3d(c, 12.0f)) + { + me->CastSpell(c, SPELL_POWER_SPARK_MALYGOS_BUFF, true); + me->DespawnOrUnsummon(); + return; + } + CheckTimer = 1000; } + else + CheckTimer -= diff; - void UpdateAI(uint32 diff) override + if (MoveTimer) { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (CheckTimer <= diff) + if (MoveTimer <= diff) { if (pInstance) if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_MALYGOS_GUID))) - if (me->IsWithinDist3d(c, 12.0f)) - { - me->CastSpell(c, SPELL_POWER_SPARK_MALYGOS_BUFF, true); - me->DespawnOrUnsummon(); - return; - } - CheckTimer = 1000; + me->GetMotionMaster()->MovePoint(0, *c); + MoveTimer = 2000; } else - CheckTimer -= diff; - - if (MoveTimer) - { - if (MoveTimer <= diff) - { - if (pInstance) - if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_MALYGOS_GUID))) - me->GetMotionMaster()->MovePoint(0, *c); - MoveTimer = 2000; - } - else - MoveTimer -= diff; - } + MoveTimer -= diff; } - }; + } }; -class npc_nexus_lord : public CreatureScript +struct npc_nexus_lord : public ScriptedAI { -public: - npc_nexus_lord() : CreatureScript("npc_nexus_lord") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_nexus_lord(Creature* pCreature) : ScriptedAI(pCreature) { - return GetEyeOfEternityAI(pCreature); + me->SetReactState(REACT_PASSIVE); + pInstance = me->GetInstanceScript(); + timer = 0; + events.Reset(); + events.RescheduleEvent(EVENT_TELEPORT_VISUAL, 0ms); } - struct npc_nexus_lordAI : public ScriptedAI + InstanceScript* pInstance; + EventMap events; + uint16 timer; + + void JustEngagedWith(Unit* /*who*/) override { - npc_nexus_lordAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetReactState(REACT_PASSIVE); - pInstance = me->GetInstanceScript(); - timer = 0; - events.Reset(); - events.RescheduleEvent(EVENT_TELEPORT_VISUAL, 0ms); - } + DoZoneInCombat(); + events.Reset(); + events.RescheduleEvent(EVENT_NEXUS_LORD_ARCANE_SHOCK, 3s, 10s); + events.RescheduleEvent(EVENT_NEXUS_LORD_HASTE, 8s, 14s); + } - InstanceScript* pInstance; - EventMap events; - uint16 timer; + void AttackStart(Unit* victim) override + { + if (victim && me->Attack(victim, true)) + me->GetMotionMaster()->MoveIdle(); + } - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); - events.Reset(); - events.RescheduleEvent(EVENT_NEXUS_LORD_ARCANE_SHOCK, 3s, 10s); - events.RescheduleEvent(EVENT_NEXUS_LORD_HASTE, 8s, 14s); - } - - void AttackStart(Unit* victim) override - { - if (victim && me->Attack(victim, true)) - me->GetMotionMaster()->MoveIdle(); - } - - void UpdateAI(uint32 diff) override - { - if (UpdateVictim()) - if (Unit* victim = me->GetVictim()) + void UpdateAI(uint32 diff) override + { + if (UpdateVictim()) + if (Unit* victim = me->GetVictim()) + { + if (timer <= diff) { - if (timer <= diff) + if (!victim->IsWithinMeleeRange(me)) { - if (!victim->IsWithinMeleeRange(me)) + float x, y, z; + victim->GetClosePoint(x, y, z, 0.0f, 1.5f, me->GetAngle(victim)); + if (Unit* v = me->GetVehicleBase()) + v->GetMotionMaster()->MovePoint(0, x, y, z); + } + timer = 1000; + } + else + timer -= diff; + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_TELEPORT_VISUAL: + me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); + break; + case EVENT_NEXUS_LORD_ARCANE_SHOCK: + if (Unit* victim = me->GetVictim()) + me->CastSpell(victim, SPELL_ARCANE_SHOCK); + events.Repeat(10s, 15s); + break; + case EVENT_NEXUS_LORD_HASTE: + me->CastSpell(me, SPELL_HASTE); + events.Repeat(20s, 30s); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + if (Vehicle* v = me->GetVehicle()) + v->RemoveAllPassengers(); + } +}; + +struct npc_scion_of_eternity : public ScriptedAI +{ + npc_scion_of_eternity(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetReactState(REACT_PASSIVE); + pInstance = me->GetInstanceScript(); + events.Reset(); + events.RescheduleEvent(EVENT_TELEPORT_VISUAL, 0ms); + events.RescheduleEvent(EVENT_SCION_OF_ETERNITY_ARCANE_BARRAGE, 20s, 25s); + } + + InstanceScript* pInstance; + EventMap events; + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_TELEPORT_VISUAL: + me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); + break; + case EVENT_SCION_OF_ETERNITY_ARCANE_BARRAGE: + { + GuidVector guids; + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + if (!PlayerList.IsEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + if (Player* pPlayer = i->GetSource()) + { + if (pPlayer->IsAlive()) { - float x, y, z; - victim->GetClosePoint(x, y, z, 0.0f, 1.5f, me->GetAngle(victim)); - if (Unit* v = me->GetVehicleBase()) - v->GetMotionMaster()->MovePoint(0, x, y, z); + if (!pPlayer->GetVehicle()) + { + guids.push_back(pPlayer->GetGUID()); + } } - timer = 1000; } - else - timer -= diff; - } + if (!guids.empty()) + if (Player* plr = ObjectAccessor::GetPlayer(*me, guids.at(urand(0, guids.size() - 1)))) + me->CastSpell(plr, SPELL_SCION_ARCANE_BARRAGE); - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_TELEPORT_VISUAL: - me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); - break; - case EVENT_NEXUS_LORD_ARCANE_SHOCK: - if (Unit* victim = me->GetVictim()) - me->CastSpell(victim, SPELL_ARCANE_SHOCK); - events.Repeat(10s, 15s); - break; - case EVENT_NEXUS_LORD_HASTE: - me->CastSpell(me, SPELL_HASTE); - events.Repeat(20s, 30s); - break; - } - - DoMeleeAttackIfReady(); + events.Repeat(5s, 8s); } - - void JustDied(Unit* /*killer*/) override - { - if (Vehicle* v = me->GetVehicle()) - v->RemoveAllPassengers(); + break; } - }; -}; - -class npc_scion_of_eternity : public CreatureScript -{ -public: - npc_scion_of_eternity() : CreatureScript("npc_scion_of_eternity") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetEyeOfEternityAI(pCreature); } - struct npc_scion_of_eternityAI : public ScriptedAI + void JustDied(Unit* killer) override { - npc_scion_of_eternityAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetReactState(REACT_PASSIVE); - pInstance = me->GetInstanceScript(); - events.Reset(); - events.RescheduleEvent(EVENT_TELEPORT_VISUAL, 0ms); - events.RescheduleEvent(EVENT_SCION_OF_ETERNITY_ARCANE_BARRAGE, 20s, 25s); - } + if (Vehicle* v = me->GetVehicle()) + v->RemoveAllPassengers(); - InstanceScript* pInstance; - EventMap events; - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_TELEPORT_VISUAL: - me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); - break; - case EVENT_SCION_OF_ETERNITY_ARCANE_BARRAGE: - { - GuidVector guids; - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - if (!PlayerList.IsEmpty()) - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (Player* pPlayer = i->GetSource()) - { - if (pPlayer->IsAlive()) - { - if (!pPlayer->GetVehicle()) - { - guids.push_back(pPlayer->GetGUID()); - } - } - } - if (!guids.empty()) - if (Player* plr = ObjectAccessor::GetPlayer(*me, guids.at(urand(0, guids.size() - 1)))) - me->CastSpell(plr, SPELL_SCION_ARCANE_BARRAGE); - - events.Repeat(5s, 8s); - } - break; - } - } - - void JustDied(Unit* killer) override - { - if (Vehicle* v = me->GetVehicle()) - v->RemoveAllPassengers(); - - if (killer) - if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - void AttackStart(Unit* /*who*/) override {} - }; -}; - -class npc_hover_disk : public CreatureScript -{ -public: - npc_hover_disk() : CreatureScript("npc_hover_disk") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetEyeOfEternityAI(pCreature); + if (killer) + if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me); } - struct npc_hover_diskAI : public VehicleAI + void MoveInLineOfSight(Unit* /*who*/) override {} + void AttackStart(Unit* /*who*/) override {} +}; + +struct npc_hover_disk : public VehicleAI +{ + npc_hover_disk(Creature* pCreature) : VehicleAI(pCreature) { - npc_hover_diskAI(Creature* pCreature) : VehicleAI(pCreature) - { - pInstance = me->GetInstanceScript(); - events.Reset(); - } + pInstance = me->GetInstanceScript(); + events.Reset(); + } - InstanceScript* pInstance; - EventMap events; + InstanceScript* pInstance; + EventMap events; - void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override + void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override + { + events.Reset(); + if (!who) + return; + if (apply) { - events.Reset(); - if (!who) - return; - if (apply) + if (who->IsPlayer()) { - if (who->IsPlayer()) - { - who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_OVERLOAD_DMG, true); - who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_SURGE_OF_POWER_DMG, true); - me->SetSpeed(MOVE_RUN, 1.5f); - me->SetSpeed(MOVE_FLIGHT, 1.5f); - } - else if (who->GetEntry() == NPC_NEXUS_LORD) - { - me->SetSpeed(MOVE_RUN, 1.5f); - me->SetSpeed(MOVE_FLIGHT, 1.5f); - } - else - { - me->SetSpeed(MOVE_RUN, 0.6f); - me->SetSpeed(MOVE_FLIGHT, 0.6f); - } - - who->SetFacingTo(me->GetOrientation()); - me->SetCanFly(true); + who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_OVERLOAD_DMG, true); + who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_SURGE_OF_POWER_DMG, true); + me->SetSpeed(MOVE_RUN, 1.5f); + me->SetSpeed(MOVE_FLIGHT, 1.5f); + } + else if (who->GetEntry() == NPC_NEXUS_LORD) + { + me->SetSpeed(MOVE_RUN, 1.5f); + me->SetSpeed(MOVE_FLIGHT, 1.5f); } else { - me->GetMotionMaster()->MoveIdle(); - me->DisableSpline(); - me->SetCanFly(false); - me->GetMotionMaster()->MoveLand(0, me->GetPositionX(), me->GetPositionY(), 267.24f, 10.0f); - - if (who->IsPlayer()) - { - who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_OVERLOAD_DMG, false); - who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_SURGE_OF_POWER_DMG, false); - } + me->SetSpeed(MOVE_RUN, 0.6f); + me->SetSpeed(MOVE_FLIGHT, 0.6f); } - } - void MovementInform(uint32 type, uint32 id) override - { - if (type != POINT_MOTION_TYPE) - return; - - switch (id) - { - case MI_POINT_SCION: - events.RescheduleEvent(EVENT_DISK_MOVE_NEXT_POINT, 0ms); - break; - case MI_POINT_NEXUS_LORD: - if (me->GetPositionZ() > CenterPos.GetPositionZ() + 2.0f) - events.RescheduleEvent(EVENT_DISK_MOVE_NEXT_POINT, 0ms); - else if (Vehicle* v = me->GetVehicleKit()) - if (Unit* pass = v->GetPassenger(0)) - if (Creature* c = pass->ToCreature()) - { - c->SetReactState(REACT_AGGRESSIVE); - if (Player* plr = c->SelectNearestPlayer(100.0f)) - c->AI()->AttackStart(plr); - } - break; - } - } - - void DoAction(int32 param) override - { - switch (param) - { - case 1: // move to next point - if (Vehicle* v = me->GetVehicleKit()) - if (Unit* pass = v->GetPassenger(0)) - switch (pass->GetEntry()) - { - case NPC_NEXUS_LORD: - { - float angle = CenterPos.GetAngle(me); - float newangle = angle - 0.5f; - if (newangle < 0.0f) newangle += 2 * M_PI; - float newz = me->GetPositionZ() - 4.0f; - if (newz < CenterPos.GetPositionZ()) newz = CenterPos.GetPositionZ(); - me->GetMotionMaster()->MovePoint(MI_POINT_NEXUS_LORD, CenterPos.GetPositionX() + cos(newangle) * 22.0f, CenterPos.GetPositionY() + std::sin(newangle) * 22.0f, newz); - } - break; - case NPC_SCION_OF_ETERNITY: - { - float angle = CenterPos.GetAngle(me); - float newangle = angle - 0.3f; - if (newangle < 0.0f) newangle += 2 * M_PI; - float newz = me->GetPositionZ() - 2.0f; - if (newz < CenterPos.GetPositionZ() + 20.0f) newz = CenterPos.GetPositionZ() + 20.0f; - me->GetMotionMaster()->MovePoint(MI_POINT_SCION, CenterPos.GetPositionX() + cos(newangle) * 30.0f, CenterPos.GetPositionY() + std::sin(newangle) * 30.0f, newz); - } - break; - } - break; - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_DISK_MOVE_NEXT_POINT: - DoAction(1); - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - void AttackStart(Unit* /*who*/) override {} - }; -}; - -class npc_alexstrasza : public CreatureScript -{ -public: - npc_alexstrasza() : CreatureScript("npc_alexstrasza") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetEyeOfEternityAI(pCreature); - } - - struct npc_alexstraszaAI : public ScriptedAI - { - npc_alexstraszaAI(Creature* pCreature) : ScriptedAI(pCreature) - { - events.Reset(); - events.ScheduleEvent(1, 9s); + who->SetFacingTo(me->GetOrientation()); me->SetCanFly(true); - me->SetDisableGravity(true); } - - EventMap events; - - void UpdateAI(uint32 diff) override + else { - events.Update(diff); - switch (events.ExecuteEvent()) + me->GetMotionMaster()->MoveIdle(); + me->DisableSpline(); + me->SetCanFly(false); + me->GetMotionMaster()->MoveLand(0, me->GetPositionX(), me->GetPositionY(), 267.24f, 10.0f); + + if (who->IsPlayer()) { - case 0: - break; - case 1: - me->CastSpell(773.98f, 1285.97f, 266.254f, SPELL_ALEXSTRASZA_GIFT, true); - if (GameObject* chest = me->SummonGameObject(ALEXSTRASZA_GIFT, 773.98f, 1285.97f, 266.254f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0)) - { - chest->SetLootRecipient(me->GetMap()); - } - - if (GameObject* heart = me->SummonGameObject(HEART_OF_MAGIC, 773.98f, 1275.97f, 266.254f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0)) - { - heart->SetLootRecipient(me->GetMap()); - } - - Talk(SAY_ALEXSTRASZA_ONE); - events.RescheduleEvent(2, 6s); - break; - case 2: - Talk(SAY_ALEXSTRASZA_TWO); - events.RescheduleEvent(3, 5s); - break; - case 3: - Talk(SAY_ALEXSTRASZA_THREE); - events.RescheduleEvent(4, 22s); - break; - case 4: - Talk(SAY_ALEXSTRASZA_FOUR); - break; + who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_OVERLOAD_DMG, false); + who->ApplySpellImmune(0, IMMUNITY_ID, SPELL_SURGE_OF_POWER_DMG, false); } } - - void MoveInLineOfSight(Unit* /*who*/) override {} - void AttackStart(Unit* /*who*/) override {} - }; -}; - -class npc_eoe_wyrmrest_skytalon : public CreatureScript -{ -public: - npc_eoe_wyrmrest_skytalon() : CreatureScript("npc_eoe_wyrmrest_skytalon") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetEyeOfEternityAI(pCreature); } - struct npc_eoe_wyrmrest_skytalonAI : public VehicleAI + void MovementInform(uint32 type, uint32 id) override { - npc_eoe_wyrmrest_skytalonAI(Creature* pCreature) : VehicleAI(pCreature) { } + if (type != POINT_MOTION_TYPE) + return; - void PassengerBoarded(Unit* pass, int8 /*seat*/, bool apply) override + switch (id) { - if (apply) - { - me->SetDisableGravity(false); - me->SendMovementFlagUpdate(); - } - else if (pass && pass->IsPlayer() && me->IsAlive()) - { - me->SetDisplayId(11686); // prevents nasty falling animation at despawn - me->DespawnOrUnsummon(1ms); - } + case MI_POINT_SCION: + events.RescheduleEvent(EVENT_DISK_MOVE_NEXT_POINT, 0ms); + break; + case MI_POINT_NEXUS_LORD: + if (me->GetPositionZ() > CenterPos.GetPositionZ() + 2.0f) + events.RescheduleEvent(EVENT_DISK_MOVE_NEXT_POINT, 0ms); + else if (Vehicle* v = me->GetVehicleKit()) + if (Unit* pass = v->GetPassenger(0)) + if (Creature* c = pass->ToCreature()) + { + c->SetReactState(REACT_AGGRESSIVE); + if (Player* plr = c->SelectNearestPlayer(100.0f)) + c->AI()->AttackStart(plr); + } + break; } + } - void JustDied(Unit* /*killer*/) override + void DoAction(int32 param) override + { + switch (param) + { + case 1: // move to next point + if (Vehicle* v = me->GetVehicleKit()) + if (Unit* pass = v->GetPassenger(0)) + switch (pass->GetEntry()) + { + case NPC_NEXUS_LORD: + { + float angle = CenterPos.GetAngle(me); + float newangle = angle - 0.5f; + if (newangle < 0.0f) newangle += 2 * M_PI; + float newz = me->GetPositionZ() - 4.0f; + if (newz < CenterPos.GetPositionZ()) newz = CenterPos.GetPositionZ(); + me->GetMotionMaster()->MovePoint(MI_POINT_NEXUS_LORD, CenterPos.GetPositionX() + cos(newangle) * 22.0f, CenterPos.GetPositionY() + std::sin(newangle) * 22.0f, newz); + } + break; + case NPC_SCION_OF_ETERNITY: + { + float angle = CenterPos.GetAngle(me); + float newangle = angle - 0.3f; + if (newangle < 0.0f) newangle += 2 * M_PI; + float newz = me->GetPositionZ() - 2.0f; + if (newz < CenterPos.GetPositionZ() + 20.0f) newz = CenterPos.GetPositionZ() + 20.0f; + me->GetMotionMaster()->MovePoint(MI_POINT_SCION, CenterPos.GetPositionX() + cos(newangle) * 30.0f, CenterPos.GetPositionY() + std::sin(newangle) * 30.0f, newz); + } + break; + } + break; + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_DISK_MOVE_NEXT_POINT: + DoAction(1); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + void AttackStart(Unit* /*who*/) override {} +}; + +struct npc_alexstrasza : public ScriptedAI +{ + npc_alexstrasza(Creature* pCreature) : ScriptedAI(pCreature) + { + events.Reset(); + events.ScheduleEvent(1, 9s); + me->SetCanFly(true); + me->SetDisableGravity(true); + } + + EventMap events; + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + switch (events.ExecuteEvent()) + { + case 0: + break; + case 1: + me->CastSpell(773.98f, 1285.97f, 266.254f, SPELL_ALEXSTRASZA_GIFT, true); + if (GameObject* chest = me->SummonGameObject(ALEXSTRASZA_GIFT, 773.98f, 1285.97f, 266.254f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0)) + { + chest->SetLootRecipient(me->GetMap()); + } + + if (GameObject* heart = me->SummonGameObject(HEART_OF_MAGIC, 773.98f, 1275.97f, 266.254f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0)) + { + heart->SetLootRecipient(me->GetMap()); + } + + Talk(SAY_ALEXSTRASZA_ONE); + events.RescheduleEvent(2, 6s); + break; + case 2: + Talk(SAY_ALEXSTRASZA_TWO); + events.RescheduleEvent(3, 5s); + break; + case 3: + Talk(SAY_ALEXSTRASZA_THREE); + events.RescheduleEvent(4, 22s); + break; + case 4: + Talk(SAY_ALEXSTRASZA_FOUR); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + void AttackStart(Unit* /*who*/) override {} +}; + +struct npc_eoe_wyrmrest_skytalon : public VehicleAI +{ + npc_eoe_wyrmrest_skytalon(Creature* creature) : VehicleAI(creature) { } + + void IsSummonedBy(WorldObject* summoner) override + { + if (summoner && summoner->IsPlayer()) + { + ObjectGuid summonerGUID = summoner->GetGUID(); + me->m_Events.AddEventAtOffset([summonerGUID, this] { + if (Player* rider = ObjectAccessor::GetPlayer(*me, summonerGUID)) + DoCast(rider, SPELL_RIDE_RED_DRAGON, true); + }, 2s); + } + } + + void PassengerBoarded(Unit* pass, int8 /*seat*/, bool apply) override + { + if (apply) + { + me->SetDisableGravity(false); + me->SendMovementFlagUpdate(); + } + else if (pass && pass->IsPlayer() && me->IsAlive()) { me->SetDisplayId(11686); // prevents nasty falling animation at despawn me->DespawnOrUnsummon(1ms); } - }; + } + + void JustDied(Unit* /*killer*/) override + { + me->SetDisplayId(11686); // prevents nasty falling animation at despawn + me->DespawnOrUnsummon(1ms); + } }; class go_the_focusing_iris : public GameObjectScript @@ -1517,17 +1435,60 @@ class spell_eoe_ph3_surge_of_power : public SpellScript } }; +// 56070 - Summon Red Dragon Buddy +class spell_wyrmrest_skytalon_summon_red_dragon_buddy : public SpellScript +{ + PrepareSpellScript(spell_wyrmrest_skytalon_summon_red_dragon_buddy); + + bool Load() override + { + return GetCaster()->IsPlayer(); + } + + void SetDest(SpellDestination& dest) + { + dest.Relocate(GetCaster()->GetPosition()); + // Adjust effect summon position to lower Z + Position const offset = { 0.0f, 0.0f, -80.0f, 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_wyrmrest_skytalon_summon_red_dragon_buddy::SetDest, EFFECT_0, TARGET_DEST_CASTER_RADIUS); + } +}; + +// 56072 - Ride Red Dragon Buddy +class spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger : public SpellScript +{ + PrepareSpellScript(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell(GetCaster(), GetEffectValue(), true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + void AddSC_boss_malygos() { - new boss_malygos(); - new npc_power_spark(); - new npc_vortex_ride(); - new npc_alexstrasza(); + RegisterEoECreatureAI(boss_malygos); + RegisterEoECreatureAI(npc_power_spark); + RegisterEoECreatureAI(npc_vortex_ride); + RegisterEoECreatureAI(npc_alexstrasza); new go_the_focusing_iris(); - new npc_nexus_lord(); - new npc_scion_of_eternity(); - new npc_hover_disk(); - new npc_eoe_wyrmrest_skytalon(); + RegisterEoECreatureAI(npc_nexus_lord); + RegisterEoECreatureAI(npc_scion_of_eternity); + RegisterEoECreatureAI(npc_hover_disk); + RegisterEoECreatureAI(npc_eoe_wyrmrest_skytalon); + RegisterSpellScript(spell_wyrmrest_skytalon_summon_red_dragon_buddy); + RegisterSpellScript(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger); RegisterSpellScript(spell_eoe_ph3_surge_of_power); } diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index 88ad0e920..77a4f7c46 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -46,7 +46,6 @@ enum NPCs NPC_HOVER_DISK = 30248, NPC_ARCANE_OVERLOAD = 30282, NPC_SURGE_OF_POWER = 30334, - NPC_WYRMREST_SKYTALON = 30161, NPC_STATIC_FIELD = 30592, NPC_ALEXSTRASZA = 32295, }; @@ -75,6 +74,8 @@ enum eSpells SPELL_HASTE = 57060, SPELL_ALEXSTRASZA_GIFT = 61028, + SPELL_SUMMON_RED_DRAGON_BUDDY = 56070, + SPELL_RIDE_RED_DRAGON = 56072 }; enum eAchiev @@ -104,20 +105,11 @@ const Position Phase2NorthPos = {837.22f, 1301.676f, 296.10f, M_PI}; const uint32 MalygosIntroIntervals[] = {18000, 19000, 21000, 18000, 15000}; -class EoEDrakeEnterVehicleEvent : public BasicEvent -{ -public: - EoEDrakeEnterVehicleEvent(Creature& owner, ObjectGuid playerGUID) : _owner(owner), _playerGUID(playerGUID) { } - bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override; -private: - Creature& _owner; - ObjectGuid _playerGUID; -}; - template inline AI* GetEyeOfEternityAI(T* obj) { return GetInstanceAI(obj, EyeOfEternityScriptName); } +#define RegisterEoECreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetEyeOfEternityAI) #endif diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index 41a86c063..fea436c4b 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -21,18 +21,6 @@ #include "Vehicle.h" #include "eye_of_eternity.h" -bool EoEDrakeEnterVehicleEvent::Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) -{ - if (Player* p = ObjectAccessor::GetPlayer(_owner, _playerGUID)) - if (p->IsInWorld() && !p->IsDuringRemoveFromWorld() && !p->isBeingLoaded() && p->FindMap() == _owner.FindMap()) - { - p->CastCustomSpell(60683, SPELLVALUE_BASE_POINT0, 1, &_owner, true); - return true; - } - _owner.DespawnOrUnsummon(1ms); - return true; -} - class instance_eye_of_eternity : public InstanceMapScript { public: @@ -68,7 +56,7 @@ public: return EncounterStatus == IN_PROGRESS; } - void OnPlayerEnter(Player* pPlayer) override + void OnPlayerEnter(Player* player) override { if (EncounterStatus == DONE) { @@ -79,18 +67,12 @@ public: go->SetPhaseMask(2, true); // no floor, so put players on drakes - if (pPlayer) + if (player) { - if (!pPlayer->IsAlive()) + if (!player->IsAlive()) return; - if (Creature* c = pPlayer->SummonCreature(NPC_WYRMREST_SKYTALON, pPlayer->GetPositionX(), pPlayer->GetPositionY(), pPlayer->GetPositionZ() - 20.0f, 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) - { - c->SetCanFly(true); - c->SetFaction(pPlayer->GetFaction()); - //pPlayer->CastCustomSpell(60683, SPELLVALUE_BASE_POINT0, 1, c, true); - c->m_Events.AddEventAtOffset(new EoEDrakeEnterVehicleEvent(*c, pPlayer->GetGUID()), 500ms); - } + player->CastSpell(player, SPELL_SUMMON_RED_DRAGON_BUDDY, true); } } } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp index e24adc5ac..7d5f74059 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp @@ -753,7 +753,6 @@ public: if (cr) { cr->AI()->AttackStart(me); - cr->AddThreat(me, 0.0f); cr->SetInCombatWithZone(); } } @@ -911,6 +910,28 @@ void brann_bronzebeard::brann_bronzebeardAI::WaypointReached(uint32 id) } } +// 51774 - Taunt +class spell_taunt_brann : public SpellScript +{ + PrepareSpellScript(spell_taunt_brann); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + if (!caster || !target) + return; + + uint32 spellId = GetEffectValue(); // 51775 + target->CastSpell(caster, spellId, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_taunt_brann::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + class spell_hos_dark_matter : public AuraScript { PrepareAuraScript(spell_hos_dark_matter); @@ -953,4 +974,5 @@ void AddSC_brann_bronzebeard() new brann_bronzebeard(); RegisterSpellScript(spell_hos_dark_matter); RegisterSpellScript(spell_hos_dark_matter_size); + RegisterSpellScript(spell_taunt_brann); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp index 1fa645637..1b4ce7bf5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -558,8 +558,10 @@ public: { uint32 dist = urand(38, 48); float o = rand_norm() * M_PI * 2; - float Zplus = (dist - 38) / 6.5f; - if (Creature* cr = me->SummonCreature(entry, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) + float spawnX = me->GetPositionX() + dist * cos(o); + float spawnY = me->GetPositionY() + dist * std::sin(o); + float spawnZ = me->GetMap()->GetHeight(me->GetPhaseMask(), spawnX, spawnY, 330.0f); + if (Creature* cr = me->SummonCreature(entry, spawnX, spawnY, spawnZ, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) { cr->CastSpell(cr, SPELL_TENTACLE_ERUPT, true); cr->CastSpell(cr, SPELL_VOID_ZONE_SMALL, true); diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index ec6a55f17..960e72b15 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -1472,6 +1472,11 @@ public: me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); _events.ScheduleEvent(EVENT_THASSARIAN_SCRIPT_1, 2s); } + else if (type == POINT_MOTION_TYPE && param == 0) + { + if (Creature* talbot = ObjectAccessor::GetCreature(*me, _talbotGUID)) + me->SetFacingToObject(talbot); + } } void UpdateAI(uint32 diff) override @@ -1804,6 +1809,7 @@ public: { if (action == 0) { + me->setActive(true); _playerGUID = player->GetGUID(); CloseGossipMenuFor(player); me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_porung.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_porung.cpp index aa5856be6..8ce8f9e21 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_porung.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_porung.cpp @@ -291,10 +291,29 @@ class spell_tsh_shoot_flame_arrow : public SpellScript unitList.remove_if([&](WorldObject* target) -> bool { - return !target->SelectNearestPlayer(15.0f); + if (!target) + return true; + + if (!target->SelectNearestPlayer(15.0f)) + return true; + + if (target->FindNearestGameObject(GO_BLAZE, 6.0f)) + return true; + + // Don't stack arrows on the same target + if (InstanceScript* instance = caster->GetInstanceScript()) + if (target->GetGUID() == instance->GetGuidData(DATA_LAST_FLAME_ARROW)) + return true; + + return false; }); Acore::Containers::RandomResize(unitList, 1); + + // Replace last arrow GUID + if (!unitList.empty()) + if (InstanceScript* instance = caster->GetInstanceScript()) + instance->SetGuidData(DATA_LAST_FLAME_ARROW, unitList.front()->GetGUID()); } void HandleScriptEffect(SpellEffIndex effIndex) diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp index a25b4dacd..8198d5f3b 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp @@ -117,11 +117,25 @@ public: return PrisonerGUID[data - DATA_PRISONER_1]; case DATA_EXECUTIONER: return ExecutionerGUID; + case DATA_LAST_FLAME_ARROW: + return LastArrowGUID; } return ObjectGuid::Empty; } + void SetGuidData(uint32 data, ObjectGuid value) override + { + switch (data) + { + case DATA_LAST_FLAME_ARROW: + LastArrowGUID = value; + break; + default: + break; + } + } + void Update(uint32 diff) override { if (RescueTimer && RescueTimer < 100 * MINUTE * IN_MILLISECONDS) @@ -164,6 +178,7 @@ public: } protected: + ObjectGuid LastArrowGUID; ObjectGuid ExecutionerGUID; ObjectGuid PrisonerGUID[3]; uint32 RescueTimer; diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h index 31b10add2..713e399ed 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h @@ -37,7 +37,8 @@ enum DataTypes DATA_EXECUTIONER = 14, DATA_OMROGG_LEFT_HEAD = 15, DATA_OMROGG_RIGHT_HEAD = 16, - DATA_WARCHIEF_PORTAL = 17 + DATA_WARCHIEF_PORTAL = 17, + DATA_LAST_FLAME_ARROW = 18 }; enum CreatureIds @@ -49,6 +50,7 @@ enum CreatureIds NPC_SH_ZEALOT = 17462, NPC_SH_ARCHER = 17427, NPC_SH_SCOUT = 17693, + NPC_SH_FLAME_ARROW = 17687, // Warchief Kargath NPC_WARCHIEF_KARGATH = 16808, @@ -76,7 +78,8 @@ enum CreatureIds enum GameobjectIds { GO_GRAND_WARLOCK_CHAMBER_DOOR_1 = 182539, - GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540 + GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540, + GO_BLAZE = 181915 }; enum SpellIds diff --git a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp index 60e43f0f3..91d41787c 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp @@ -146,25 +146,7 @@ public: } }; -class spell_the_eye_countercharge_aura : public AuraScript -{ - PrepareAuraScript(spell_the_eye_countercharge_aura); - - bool PrepareProc(ProcEventInfo& /*eventInfo*/) - { - // xinef: prevent charge drop - PreventDefaultAction(); - return true; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_the_eye_countercharge_aura::PrepareProc); - } -}; - void AddSC_instance_the_eye() { new instance_the_eye(); - RegisterSpellScript(spell_the_eye_countercharge_aura); }