diff --git a/.github/actions/linux-build/action.yml b/.github/actions/linux-build/action.yml index 3a8fefd77..9a7ca0612 100644 --- a/.github/actions/linux-build/action.yml +++ b/.github/actions/linux-build/action.yml @@ -26,6 +26,7 @@ runs: steps: - name: Cache uses: actions/cache@v3 + if: inputs.pch != 'true' with: path: ${{ github.workspace }}/var/ccache # format @@ -102,7 +103,7 @@ runs: -DBUILD_TESTING="ON" \ -DUSE_SCRIPTPCH=${{ inputs.pch == 'true' && 'ON' || '' }} \ -DUSE_COREPCH=${{ inputs.pch == 'true' && 'ON' || '' }} \ - ${{ !inputs.pch && '-DNOPCH=true' || '' }} + ${{ inputs.pch == 'true' && '' || '-DNOPCH=true' }} - name: build shell: bash diff --git a/data/sql/updates/db_world/2024_03_31_00.sql b/data/sql/updates/db_world/2024_03_31_00.sql new file mode 100644 index 000000000..2ee8bb336 --- /dev/null +++ b/data/sql/updates/db_world/2024_03_31_00.sql @@ -0,0 +1,3 @@ +-- DB update 2024_03_30_01 -> 2024_03_31_00 +-- +UPDATE `reference_loot_template` SET `Item` = 30448, `Reference` = 0, `Chance` = 0, `Comment` = 'Talon of Al\'ar' WHERE `Entry` = 34053 AND `Item` = 1; diff --git a/data/sql/updates/db_world/2024_03_31_01.sql b/data/sql/updates/db_world/2024_03_31_01.sql new file mode 100644 index 000000000..d3fa5d1c3 --- /dev/null +++ b/data/sql/updates/db_world/2024_03_31_01.sql @@ -0,0 +1,11 @@ +-- DB update 2024_03_31_00 -> 2024_03_31_01 +-- +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 17903; + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 17903 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 +(17903, 0, 0, 0, 4, 0, 100, 512, 0, 0, 0, 0, 0, 0, 30, 1, 2, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeleton Mage - On Aggro - Set Event Phase Random'), +(17903, 0, 1, 0, 0, 1, 100, 0, 0, 0, 3000, 3500, 0, 0, 11, 31622, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeleton Mage - In Combat - Cast Frostbolt'), +(17903, 0, 2, 0, 0, 2, 100, 0, 0, 0, 3000, 3500, 0, 0, 11, 31618, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeleton Mage - In Combat - Cast Shadow Bolt'), +(17903, 0, 3, 0, 0, 4, 100, 0, 0, 0, 3000, 3500, 0, 0, 11, 31620, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeleton Mage - In Combat - Cast Fireball'); + diff --git a/data/sql/updates/db_world/2024_04_02_00.sql b/data/sql/updates/db_world/2024_04_02_00.sql new file mode 100644 index 000000000..db6183a16 --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_00.sql @@ -0,0 +1,7 @@ +-- DB update 2024_03_31_01 -> 2024_04_02_00 +-- delete old entries that are unused +DELETE FROM `reference_loot_template` WHERE `Entry` = 34377 AND `Item` IN (30448, 32944); +-- down +DELETE FROM `reference_loot_template` WHERE `Entry` = 34053 AND `Item` = 32944; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34053, 32944, 0, 0, 0, 1, 1, 1, 1, 'Talon of the Phoenix'); diff --git a/data/sql/updates/db_world/2024_04_02_01.sql b/data/sql/updates/db_world/2024_04_02_01.sql new file mode 100644 index 000000000..ad3261bd2 --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_01.sql @@ -0,0 +1,3 @@ +-- DB update 2024_04_02_00 -> 2024_04_02_01 +-- +UPDATE `creature_loot_template` SET `MaxCount` = 2 WHERE `Entry` = 19622 AND `Item` = 90056 AND `Reference` = 34056 AND `GroupId` = 4; diff --git a/data/sql/updates/db_world/2024_04_02_02.sql b/data/sql/updates/db_world/2024_04_02_02.sql new file mode 100644 index 000000000..7b3d43fef --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_02.sql @@ -0,0 +1,4 @@ +-- DB update 2024_04_02_01 -> 2024_04_02_02 +-- +UPDATE `creature_template` SET `speed_walk` = 3.2, `speed_run` = 2.857142 WHERE (`entry` = 19516); +UPDATE `creature_model_info` SET `BoundingRadius` = 12.33326530456542968, `CombatReach` = 18 WHERE `DisplayID` = 18951; diff --git a/data/sql/updates/db_world/2024_04_02_03.sql b/data/sql/updates/db_world/2024_04_02_03.sql new file mode 100644 index 000000000..f31602dbd --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_03.sql @@ -0,0 +1,47 @@ +-- DB update 2024_04_02_02 -> 2024_04_02_03 +-- +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_ashtongue_channeler', `faction` = 1692 WHERE (`entry` = 23421); +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_ashtongue_sorcerer' WHERE (`entry` = 23215); +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 23215) AND (`source_type` = 0); +UPDATE `creature_template_addon` SET `auras` = '39833' WHERE (`entry` = 22841); +UPDATE `creature_template` SET `faction` = 1847 WHERE (`entry` = 23210); +UPDATE `creature_template` SET `faction` = 1813 WHERE (`entry` = 23319); + +DELETE FROM `creature_text` WHERE `CreatureID` = 23191; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23191, 0, 0, 'Broken of the Ashtongue tribe, your leader speaks!', 14, 0, 100, 15, 0, 0, 21342, 0, 'Akama SAY_BROKEN_FREE_0'), +(23191, 1, 0, 'The Betrayer no longer holds sway over us. His dark magic over the Ashtongue soul has been destroyed!', 14, 0, 100, 1, 0, 0, 21343, 0, 'Akama SAY_BROKEN_FREE_1'), +(23191, 2, 0, 'Come out from the shadows! I\'ve returned to lead you against our true enemy! Shed your chains and raise your weapons against your Illidari masters!', 14, 0, 100, 397, 0, 0, 21344, 0, 'Akama SAY_BROKEN_FREE_2'), +(23191, 3, 0, 'I will not last much longer!', 14, 0, 100, 0, 0, 11385, 21784, 0, 'Akama SAY_LOW_HEALTH'), +(23191, 4, 0, 'No! Not yet!', 14, 0, 100, 0, 0, 11386, 21785, 0, 'Akama SAY_DEAD'); + +UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id1` = 23191 AND `map` = 564; + +DELETE FROM `creature_formations` WHERE `leaderGUID` = 148236; +INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES +(148236, 148236, 24), +(148237, 148236, 24), +(148238, 148236, 24), +(148239, 148236, 24), +(148240, 148236, 24), +(148241, 148236, 24), +(148242, 148236, 24); + +-- Delete leftover gobs +DELETE FROM `gameobject` WHERE `guid` IN (20523,20558,20559,20561,20563,20567) AND `map` = 564; + +DELETE FROM `creature_text` WHERE `CreatureID` = 23089 AND `GroupID` IN (9, 10); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(23089, 9, 0, 'Those who\'ve defiled this temple have all been defeated. All but one!', 12, 0, 100, 1, 0, 0, 21518, 0, 'SAY_AKAMA_COUNCIL_1'), +(23089, 10, 0, 'Let us finish what we\'ve started. I will lead you to Illidan\'s abode once you\'ve recovered your strength.', 12, 0, 100, 1, 0, 0, 21520, 0, 'SAY_AKAMA_COUNCIL_2'); + +DELETE FROM `waypoint_data` WHERE `id` = 230891; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `move_type`) VALUES +(230891, 1, 642.5905, 305.6287, 271.6885, 1), +(230891, 2, 660.76465, 305.76627, 271.70413, 1); + +UPDATE `creature` SET `phaseMask` = 3 WHERE `guid` = 148734; +UPDATE `creature` SET `phaseMask` = 5 WHERE `guid` = 148733; + +DELETE FROM `smart_scripts` WHERE `source_type` = 2 AND `entryorguid` = 4665; +INSERT INTO `smart_scripts` VALUES (4665, 2, 0, 0, 46, 0, 100, 1, 0, 0, 0, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 10, 148358, 22871, 0, 0, 0, 0, 0, 0, 'Area Trigger - On Trigger - Teron Gorefiend Talk'); diff --git a/data/sql/updates/db_world/2024_04_02_04.sql b/data/sql/updates/db_world/2024_04_02_04.sql new file mode 100644 index 000000000..f62b89d5d --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_04.sql @@ -0,0 +1,341 @@ +-- DB update 2024_04_02_03 -> 2024_04_02_04 + +DELETE FROM pool_gameobject WHERE guid BETWEEN 75600 AND 75761; +DELETE FROM pool_gameobject WHERE guid BETWEEN 75765 AND 75932; +DELETE FROM pool_gameobject WHERE guid BETWEEN 75936 AND 75938; + +INSERT INTO pool_gameobject (guid, pool_entry, chance, description) VALUES +(75600, 4880, 0, 'Spawn Point 1 - Copper'), +(75601, 4880, 20, 'Spawn Point 1 - Tin'), +(75602, 4880, 20, 'Spawn Point 1 - Silver'), +(75603, 4881, 0, 'Spawn Point 2 - Copper'), +(75604, 4881, 20, 'Spawn Point 2 - Tin'), +(75605, 4881, 20, 'Spawn Point 2 - Silver'), +(75606, 4882, 0, 'Spawn Point 3 - Copper'), +(75607, 4882, 20, 'Spawn Point 3 - Tin'), +(75608, 4882, 20, 'Spawn Point 3 - Silver'), +(75609, 4883, 0, 'Spawn Point 4 - Copper'), +(75610, 4883, 20, 'Spawn Point 4 - Tin'), +(75611, 4883, 20, 'Spawn Point 4 - Silver'), +(75612, 4884, 0, 'Spawn Point 5 - Copper'), +(75613, 4884, 20, 'Spawn Point 5 - Tin'), +(75614, 4884, 20, 'Spawn Point 5 - Silver'), +(75615, 4885, 0, 'Spawn Point 6 - Copper'), +(75616, 4885, 20, 'Spawn Point 6 - Tin'), +(75617, 4885, 20, 'Spawn Point 6 - Silver'), +(75618, 4886, 0, 'Spawn Point 7 - Copper'), +(75619, 4886, 20, 'Spawn Point 7 - Tin'), +(75620, 4886, 20, 'Spawn Point 7 - Silver'), +(75621, 4887, 0, 'Spawn Point 8 - Copper'), +(75622, 4887, 20, 'Spawn Point 8 - Tin'), +(75623, 4887, 20, 'Spawn Point 8 - Silver'), +(75624, 4888, 0, 'Spawn Point 9 - Copper'), +(75625, 4888, 20, 'Spawn Point 9 - Tin'), +(75626, 4888, 20, 'Spawn Point 9 - Silver'), +(75627, 4889, 0, 'Spawn Point 10 - Copper'), +(75628, 4889, 20, 'Spawn Point 10 - Tin'), +(75629, 4889, 20, 'Spawn Point 10 - Silver'), +(75630, 4890, 0, 'Spawn Point 11 - Copper'), +(75631, 4890, 20, 'Spawn Point 11 - Tin'), +(75632, 4890, 20, 'Spawn Point 11 - Silver'), +(75633, 4891, 0, 'Spawn Point 12 - Copper'), +(75634, 4891, 20, 'Spawn Point 12 - Tin'), +(75635, 4891, 20, 'Spawn Point 12 - Silver'), +(75636, 4892, 0, 'Spawn Point 13 - Copper'), +(75637, 4892, 20, 'Spawn Point 13 - Tin'), +(75638, 4892, 20, 'Spawn Point 13 - Silver'), +(75639, 4893, 0, 'Spawn Point 14 - Copper'), +(75640, 4893, 20, 'Spawn Point 14 - Tin'), +(75641, 4893, 20, 'Spawn Point 14 - Silver'), +(75642, 4894, 0, 'Spawn Point 15 - Copper'), +(75643, 4894, 20, 'Spawn Point 15 - Tin'), +(75644, 4894, 20, 'Spawn Point 15 - Silver'), +(75645, 4895, 0, 'Spawn Point 16 - Copper'), +(75646, 4895, 20, 'Spawn Point 16 - Tin'), +(75647, 4895, 20, 'Spawn Point 16 - Silver'), +(75648, 4896, 0, 'Spawn Point 17 - Copper'), +(75649, 4896, 20, 'Spawn Point 17 - Tin'), +(75650, 4896, 20, 'Spawn Point 17 - Silver'), +(75651, 4897, 0, 'Spawn Point 18 - Copper'), +(75652, 4897, 20, 'Spawn Point 18 - Tin'), +(75653, 4897, 20, 'Spawn Point 18 - Silver'), +(75654, 4898, 0, 'Spawn Point 19 - Copper'), +(75655, 4898, 20, 'Spawn Point 19 - Tin'), +(75656, 4898, 20, 'Spawn Point 19 - Silver'), +(75657, 4899, 0, 'Spawn Point 20 - Copper'), +(75658, 4899, 20, 'Spawn Point 20 - Tin'), +(75659, 4899, 20, 'Spawn Point 20 - Silver'), +(75660, 4900, 0, 'Spawn Point 21 - Copper'), +(75661, 4900, 20, 'Spawn Point 21 - Tin'), +(75662, 4900, 20, 'Spawn Point 21 - Silver'), +(75663, 4901, 0, 'Spawn Point 22 - Copper'), +(75664, 4901, 20, 'Spawn Point 22 - Tin'), +(75665, 4901, 20, 'Spawn Point 22 - Silver'), +(75666, 4902, 0, 'Spawn Point 23 - Copper'), +(75667, 4902, 20, 'Spawn Point 23 - Tin'), +(75668, 4902, 20, 'Spawn Point 23 - Silver'), +(75669, 4903, 0, 'Spawn Point 24 - Copper'), +(75670, 4903, 20, 'Spawn Point 24 - Tin'), +(75671, 4903, 20, 'Spawn Point 24 - Silver'), +(75672, 4904, 0, 'Spawn Point 25 - Copper'), +(75673, 4904, 20, 'Spawn Point 25 - Tin'), +(75674, 4904, 20, 'Spawn Point 25 - Silver'), +(75675, 4905, 0, 'Spawn Point 26 - Copper'), +(75676, 4905, 20, 'Spawn Point 26 - Tin'), +(75677, 4905, 20, 'Spawn Point 26 - Silver'), +(75678, 4906, 0, 'Spawn Point 27 - Copper'), +(75679, 4906, 20, 'Spawn Point 27 - Tin'), +(75680, 4906, 20, 'Spawn Point 27 - Silver'), +(75681, 4907, 0, 'Spawn Point 28 - Copper'), +(75682, 4907, 20, 'Spawn Point 28 - Tin'), +(75683, 4907, 20, 'Spawn Point 28 - Silver'), +(75684, 4908, 0, 'Spawn Point 29 - Copper'), +(75685, 4908, 20, 'Spawn Point 29 - Tin'), +(75686, 4908, 20, 'Spawn Point 29 - Silver'), +(75687, 4909, 0, 'Spawn Point 30 - Copper'), +(75688, 4909, 20, 'Spawn Point 30 - Tin'), +(75689, 4909, 20, 'Spawn Point 30 - Silver'), +(75690, 4910, 0, 'Spawn Point 31 - Copper'), +(75691, 4910, 20, 'Spawn Point 31 - Tin'), +(75692, 4910, 20, 'Spawn Point 31 - Silver'), +(75693, 4911, 0, 'Spawn Point 32 - Copper'), +(75694, 4911, 20, 'Spawn Point 32 - Tin'), +(75695, 4911, 20, 'Spawn Point 32 - Silver'), +(75696, 4912, 0, 'Spawn Point 33 - Copper'), +(75697, 4912, 20, 'Spawn Point 33 - Tin'), +(75698, 4912, 20, 'Spawn Point 33 - Silver'), +(75699, 4913, 0, 'Spawn Point 34 - Copper'), +(75700, 4913, 20, 'Spawn Point 34 - Tin'), +(75701, 4913, 20, 'Spawn Point 34 - Silver'), +(75702, 4914, 0, 'Spawn Point 35 - Copper'), +(75703, 4914, 20, 'Spawn Point 35 - Tin'), +(75704, 4914, 20, 'Spawn Point 35 - Silver'), +(75705, 4915, 0, 'Spawn Point 36 - Copper'), +(75706, 4915, 20, 'Spawn Point 36 - Tin'), +(75707, 4915, 20, 'Spawn Point 36 - Silver'), +(75708, 4916, 0, 'Spawn Point 37 - Copper'), +(75709, 4916, 20, 'Spawn Point 37 - Tin'), +(75710, 4916, 20, 'Spawn Point 37 - Silver'), +(75711, 4917, 0, 'Spawn Point 38 - Copper'), +(75712, 4917, 20, 'Spawn Point 38 - Tin'), +(75713, 4917, 20, 'Spawn Point 38 - Silver'), +(75714, 4918, 0, 'Spawn Point 39 - Copper'), +(75715, 4918, 20, 'Spawn Point 39 - Tin'), +(75716, 4918, 20, 'Spawn Point 39 - Silver'), +(75717, 4919, 0, 'Spawn Point 40 - Copper'), +(75718, 4919, 20, 'Spawn Point 40 - Tin'), +(75719, 4919, 20, 'Spawn Point 40 - Silver'), +(75720, 4920, 0, 'Spawn Point 41 - Copper'), +(75721, 4920, 20, 'Spawn Point 41 - Tin'), +(75722, 4920, 20, 'Spawn Point 41 - Silver'), +(75723, 4921, 0, 'Spawn Point 42 - Copper'), +(75724, 4921, 20, 'Spawn Point 42 - Tin'), +(75725, 4921, 20, 'Spawn Point 42 - Silver'), +(75726, 4922, 0, 'Spawn Point 43 - Copper'), +(75727, 4922, 20, 'Spawn Point 43 - Tin'), +(75728, 4922, 20, 'Spawn Point 43 - Silver'), +(75729, 4923, 0, 'Spawn Point 44 - Copper'), +(75730, 4923, 20, 'Spawn Point 44 - Tin'), +(75731, 4923, 20, 'Spawn Point 44 - Silver'), +(75732, 4924, 0, 'Spawn Point 45 - Copper'), +(75733, 4924, 20, 'Spawn Point 45 - Tin'), +(75734, 4924, 20, 'Spawn Point 45 - Silver'), +(75735, 4925, 0, 'Spawn Point 46 - Copper'), +(75736, 4925, 20, 'Spawn Point 46 - Tin'), +(75737, 4925, 20, 'Spawn Point 46 - Silver'), +(75738, 4926, 0, 'Spawn Point 47 - Copper'), +(75739, 4926, 20, 'Spawn Point 47 - Tin'), +(75740, 4926, 20, 'Spawn Point 47 - Silver'), +(75741, 4927, 0, 'Spawn Point 48 - Copper'), +(75742, 4927, 20, 'Spawn Point 48 - Tin'), +(75743, 4927, 20, 'Spawn Point 48 - Silver'), +(75744, 4928, 0, 'Spawn Point 49 - Copper'), +(75745, 4928, 20, 'Spawn Point 49 - Tin'), +(75746, 4928, 20, 'Spawn Point 49 - Silver'), +(75747, 4929, 0, 'Spawn Point 50 - Copper'), +(75748, 4929, 20, 'Spawn Point 50 - Tin'), +(75749, 4929, 20, 'Spawn Point 50 - Silver'), +(75750, 4930, 0, 'Spawn Point 51 - Copper'), +(75751, 4930, 20, 'Spawn Point 51 - Tin'), +(75752, 4930, 20, 'Spawn Point 51 - Silver'), +(75753, 4931, 0, 'Spawn Point 52 - Copper'), +(75754, 4931, 20, 'Spawn Point 52 - Tin'), +(75755, 4931, 20, 'Spawn Point 52 - Silver'), +(75756, 4932, 0, 'Spawn Point 53 - Copper'), +(75757, 4932, 20, 'Spawn Point 53 - Tin'), +(75758, 4932, 20, 'Spawn Point 53 - Silver'), +(75759, 4933, 0, 'Spawn Point 54 - Copper'), +(75760, 4933, 20, 'Spawn Point 54 - Tin'), +(75761, 4933, 20, 'Spawn Point 54 - Silver'), +(75765, 4935, 0, 'Spawn Point 56 - Copper'), +(75766, 4935, 20, 'Spawn Point 56 - Tin'), +(75767, 4935, 20, 'Spawn Point 56 - Silver'), +(75768, 4936, 0, 'Spawn Point 57 - Copper'), +(75769, 4936, 20, 'Spawn Point 57 - Tin'), +(75770, 4936, 20, 'Spawn Point 57 - Silver'), +(75771, 4937, 0, 'Spawn Point 58 - Copper'), +(75772, 4937, 20, 'Spawn Point 58 - Tin'), +(75773, 4937, 20, 'Spawn Point 58 - Silver'), +(75774, 4938, 0, 'Spawn Point 59 - Copper'), +(75775, 4938, 20, 'Spawn Point 59 - Tin'), +(75776, 4938, 20, 'Spawn Point 59 - Silver'), +(75777, 4939, 0, 'Spawn Point 60 - Copper'), +(75778, 4939, 20, 'Spawn Point 60 - Tin'), +(75779, 4939, 20, 'Spawn Point 60 - Silver'), +(75780, 4940, 0, 'Spawn Point 61 - Copper'), +(75781, 4940, 20, 'Spawn Point 61 - Tin'), +(75782, 4940, 20, 'Spawn Point 61 - Silver'), +(75783, 4941, 0, 'Spawn Point 62 - Copper'), +(75784, 4941, 20, 'Spawn Point 62 - Tin'), +(75785, 4941, 20, 'Spawn Point 62 - Silver'), +(75786, 4942, 0, 'Spawn Point 63 - Copper'), +(75787, 4942, 20, 'Spawn Point 63 - Tin'), +(75788, 4942, 20, 'Spawn Point 63 - Silver'), +(75789, 4943, 0, 'Spawn Point 64 - Copper'), +(75790, 4943, 20, 'Spawn Point 64 - Tin'), +(75791, 4943, 20, 'Spawn Point 64 - Silver'), +(75792, 4944, 0, 'Spawn Point 65 - Copper'), +(75793, 4944, 20, 'Spawn Point 65 - Tin'), +(75794, 4944, 20, 'Spawn Point 65 - Silver'), +(75795, 4945, 0, 'Spawn Point 66 - Copper'), +(75796, 4945, 20, 'Spawn Point 66 - Tin'), +(75797, 4945, 20, 'Spawn Point 66 - Silver'), +(75798, 4946, 0, 'Spawn Point 67 - Copper'), +(75799, 4946, 20, 'Spawn Point 67 - Tin'), +(75800, 4946, 20, 'Spawn Point 67 - Silver'), +(75801, 4947, 0, 'Spawn Point 68 - Copper'), +(75802, 4947, 20, 'Spawn Point 68 - Tin'), +(75803, 4947, 20, 'Spawn Point 68 - Silver'), +(75804, 4948, 0, 'Spawn Point 69 - Copper'), +(75805, 4948, 20, 'Spawn Point 69 - Tin'), +(75806, 4948, 20, 'Spawn Point 69 - Silver'), +(75807, 4949, 0, 'Spawn Point 70 - Copper'), +(75808, 4949, 20, 'Spawn Point 70 - Tin'), +(75809, 4949, 20, 'Spawn Point 70 - Silver'), +(75810, 4950, 0, 'Spawn Point 71 - Copper'), +(75811, 4950, 20, 'Spawn Point 71 - Tin'), +(75812, 4950, 20, 'Spawn Point 71 - Silver'), +(75813, 4951, 0, 'Spawn Point 72 - Copper'), +(75814, 4951, 20, 'Spawn Point 72 - Tin'), +(75815, 4951, 20, 'Spawn Point 72 - Silver'), +(75816, 4952, 0, 'Spawn Point 73 - Copper'), +(75817, 4952, 20, 'Spawn Point 73 - Tin'), +(75818, 4952, 20, 'Spawn Point 73 - Silver'), +(75819, 4953, 0, 'Spawn Point 74 - Copper'), +(75820, 4953, 20, 'Spawn Point 74 - Tin'), +(75821, 4953, 20, 'Spawn Point 74 - Silver'), +(75822, 4954, 0, 'Spawn Point 75 - Copper'), +(75823, 4954, 20, 'Spawn Point 75 - Tin'), +(75824, 4954, 20, 'Spawn Point 75 - Silver'), +(75825, 4955, 0, 'Spawn Point 76 - Copper'), +(75826, 4955, 20, 'Spawn Point 76 - Tin'), +(75827, 4955, 20, 'Spawn Point 76 - Silver'), +(75828, 4956, 0, 'Spawn Point 77 - Copper'), +(75829, 4956, 20, 'Spawn Point 77 - Tin'), +(75830, 4956, 20, 'Spawn Point 77 - Silver'), +(75831, 4957, 0, 'Spawn Point 78 - Copper'), +(75832, 4957, 20, 'Spawn Point 78 - Tin'), +(75833, 4957, 20, 'Spawn Point 78 - Silver'), +(75834, 4958, 0, 'Spawn Point 79 - Copper'), +(75835, 4958, 20, 'Spawn Point 79 - Tin'), +(75836, 4958, 20, 'Spawn Point 79 - Silver'), +(75837, 4959, 0, 'Spawn Point 80 - Copper'), +(75838, 4959, 20, 'Spawn Point 80 - Tin'), +(75839, 4959, 20, 'Spawn Point 80 - Silver'), +(75840, 4960, 0, 'Spawn Point 81 - Copper'), +(75841, 4960, 20, 'Spawn Point 81 - Tin'), +(75842, 4960, 20, 'Spawn Point 81 - Silver'), +(75843, 4961, 0, 'Spawn Point 82 - Copper'), +(75844, 4961, 20, 'Spawn Point 82 - Tin'), +(75845, 4961, 20, 'Spawn Point 82 - Silver'), +(75846, 4962, 0, 'Spawn Point 83 - Copper'), +(75847, 4962, 20, 'Spawn Point 83 - Tin'), +(75848, 4962, 20, 'Spawn Point 83 - Silver'), +(75849, 4963, 0, 'Spawn Point 84 - Copper'), +(75850, 4963, 20, 'Spawn Point 84 - Tin'), +(75851, 4963, 20, 'Spawn Point 84 - Silver'), +(75852, 4964, 0, 'Spawn Point 85 - Copper'), +(75853, 4964, 20, 'Spawn Point 85 - Tin'), +(75854, 4964, 20, 'Spawn Point 85 - Silver'), +(75855, 4965, 0, 'Spawn Point 86 - Copper'), +(75856, 4965, 20, 'Spawn Point 86 - Tin'), +(75857, 4965, 20, 'Spawn Point 86 - Silver'), +(75858, 4966, 0, 'Spawn Point 87 - Copper'), +(75859, 4966, 20, 'Spawn Point 87 - Tin'), +(75860, 4966, 20, 'Spawn Point 87 - Silver'), +(75861, 4967, 0, 'Spawn Point 88 - Copper'), +(75862, 4967, 20, 'Spawn Point 88 - Tin'), +(75863, 4967, 20, 'Spawn Point 88 - Silver'), +(75864, 4968, 0, 'Spawn Point 89 - Copper'), +(75865, 4968, 20, 'Spawn Point 89 - Tin'), +(75866, 4968, 20, 'Spawn Point 89 - Silver'), +(75867, 4969, 0, 'Spawn Point 90 - Copper'), +(75868, 4969, 20, 'Spawn Point 90 - Tin'), +(75869, 4969, 20, 'Spawn Point 90 - Silver'), +(75870, 4970, 0, 'Spawn Point 91 - Copper'), +(75871, 4970, 20, 'Spawn Point 91 - Tin'), +(75872, 4970, 20, 'Spawn Point 91 - Silver'), +(75873, 4971, 0, 'Spawn Point 92 - Copper'), +(75874, 4971, 20, 'Spawn Point 92 - Tin'), +(75875, 4971, 20, 'Spawn Point 92 - Silver'), +(75876, 4972, 0, 'Spawn Point 93 - Copper'), +(75877, 4972, 20, 'Spawn Point 93 - Tin'), +(75878, 4972, 20, 'Spawn Point 93 - Silver'), +(75879, 4973, 0, 'Spawn Point 94 - Copper'), +(75880, 4973, 20, 'Spawn Point 94 - Tin'), +(75881, 4973, 20, 'Spawn Point 94 - Silver'), +(75882, 4974, 0, 'Spawn Point 95 - Copper'), +(75883, 4974, 20, 'Spawn Point 95 - Tin'), +(75884, 4974, 20, 'Spawn Point 95 - Silver'), +(75885, 4975, 0, 'Spawn Point 96 - Copper'), +(75886, 4975, 20, 'Spawn Point 96 - Tin'), +(75887, 4975, 20, 'Spawn Point 96 - Silver'), +(75888, 4976, 0, 'Spawn Point 97 - Copper'), +(75889, 4976, 20, 'Spawn Point 97 - Tin'), +(75890, 4976, 20, 'Spawn Point 97 - Silver'), +(75891, 4977, 0, 'Spawn Point 98 - Copper'), +(75892, 4977, 20, 'Spawn Point 98 - Tin'), +(75893, 4977, 20, 'Spawn Point 98 - Silver'), +(75894, 4978, 0, 'Spawn Point 99 - Copper'), +(75895, 4978, 20, 'Spawn Point 99 - Tin'), +(75896, 4978, 20, 'Spawn Point 99 - Silver'), +(75897, 4979, 0, 'Spawn Point 100 - Copper'), +(75898, 4979, 20, 'Spawn Point 100 - Tin'), +(75899, 4979, 20, 'Spawn Point 100 - Silver'), +(75900, 4980, 0, 'Spawn Point 101 - Copper'), +(75901, 4980, 20, 'Spawn Point 101 - Tin'), +(75902, 4980, 20, 'Spawn Point 101 - Silver'), +(75903, 4981, 0, 'Spawn Point 102 - Copper'), +(75904, 4981, 20, 'Spawn Point 102 - Tin'), +(75905, 4981, 20, 'Spawn Point 102 - Silver'), +(75906, 4982, 0, 'Spawn Point 103 - Copper'), +(75907, 4982, 20, 'Spawn Point 103 - Tin'), +(75908, 4982, 20, 'Spawn Point 103 - Silver'), +(75909, 4983, 0, 'Spawn Point 104 - Copper'), +(75910, 4983, 20, 'Spawn Point 104 - Tin'), +(75911, 4983, 20, 'Spawn Point 104 - Silver'), +(75912, 4984, 0, 'Spawn Point 105 - Copper'), +(75913, 4984, 20, 'Spawn Point 105 - Tin'), +(75914, 4984, 20, 'Spawn Point 105 - Silver'), +(75915, 4985, 0, 'Spawn Point 106 - Copper'), +(75916, 4985, 20, 'Spawn Point 106 - Tin'), +(75917, 4985, 20, 'Spawn Point 106 - Silver'), +(75918, 4986, 0, 'Spawn Point 107 - Copper'), +(75919, 4986, 20, 'Spawn Point 107 - Tin'), +(75920, 4986, 20, 'Spawn Point 107 - Silver'), +(75921, 4987, 0, 'Spawn Point 108 - Copper'), +(75922, 4987, 20, 'Spawn Point 108 - Tin'), +(75923, 4987, 20, 'Spawn Point 108 - Silver'), +(75924, 4988, 0, 'Spawn Point 109 - Copper'), +(75925, 4988, 20, 'Spawn Point 109 - Tin'), +(75926, 4988, 20, 'Spawn Point 109 - Silver'), +(75927, 4989, 0, 'Spawn Point 110 - Copper'), +(75928, 4989, 20, 'Spawn Point 110 - Tin'), +(75929, 4989, 20, 'Spawn Point 110 - Silver'), +(75930, 4990, 0, 'Spawn Point 111 - Copper'), +(75931, 4990, 20, 'Spawn Point 111 - Tin'), +(75932, 4990, 20, 'Spawn Point 111 - Silver'), +(75936, 4992, 0, 'Spawn Point 113 - Copper'), +(75937, 4992, 20, 'Spawn Point 113 - Tin'), +(75938, 4992, 20, 'Spawn Point 113 - Silver'); + diff --git a/data/sql/updates/db_world/2024_04_02_05.sql b/data/sql/updates/db_world/2024_04_02_05.sql new file mode 100644 index 000000000..49bbc31bc --- /dev/null +++ b/data/sql/updates/db_world/2024_04_02_05.sql @@ -0,0 +1,176 @@ +-- DB update 2024_04_02_04 -> 2024_04_02_05 +-- Update gameobject 'Forge' with sniffed values +-- updated spawns +DELETE FROM `gameobject` WHERE (`id` IN (194468, 173063, 2575, 19902, 179924, 1749, 21679, 34571, 173095, 173064, 144133, 153459, 20738, 147285, 4090, 56897, 138317, 20986, 23304, 23305, 24745, 24746, 34572, 38491, 202392, 202393, 202391, 202394, 186556, 2728, 2727, 51949, 169969, 2573, 1797, 1896, 141838, 141841, 184617, 182056, 3223, 183818, 181716, 181990, 182117, 182278, 182860, 183121, 183148, 183345, 183347, 183408, 183484, 183757, 183758, 183759, 183760, 183782, 184286, 184922, 184923, 181884, 184146, 187112, 186139, 184687, 17190, 175144, 182270, 186138, 130668, 175851, 186141, 1685, 1743, 52175, 52176, 113754, 148960, 181130, 179886, 176509, 50831, 92490, 179863, 180913, 171716, 171717, 192020, 186654, 190495, 188452, 190765, 190524, 192831, 186433, 192583, 188250, 188257, 191346, 186486, 187256, 194487, 188607, 188354, 188356, 188624, 188651, 188396, 190457, 187388, 192062, 191287, 191288, 192572, 192573, 191508, 186653, 191237, 191505, 179844, 152034, 152042, 152045, 193126, 186231, 186630, 194128, 176895, 142078)) +AND (`guid` IN (100431, 10054, 10118, 10826, 10828, 1091, 11000, 1126, 11324, 11598, 11819, 12642, 12687, 12799, 13139, 13261, 13306, 13360, 13766, 13813, 13814, 13968, 13970, 14273, 14352, 14796, 150251, 150275, 150281, 150283, 151208, 15217, 15396, 15728, 15733, 16626, 17011, 17014, 17141, 17240, 17252, 17426, 18568, 20494, 20562, 20709, 22227, 22401, 22525, 22762, 23671, 24009, 24036, 24217, 24219, 24317, 24377, 24587, 24588, 24589, 24590, 24647, 25118, 25827, 25828, 26791, 27148, 27638, 27811, 28273, 29723, 30166, 30172, 30402, 30816, 32298, 32655, 32779, 34300, 387, 44762, 44871, 44916, 44917, 44949, 45334, 45606, 45689, 46082, 46161, 4623, 467, 47586, 47603, 48632, 49092, 49393, 49803, 5258, 5430, 55964, 56459, 56480, 56654, 56955, 57486, 57539, 57574, 57733, 58133, 58300, 59043, 59092, 59113, 59403, 59623, 59624, 60255, 60307, 60317, 60512, 61116, 61125, 61538, 61660, 62356, 63130, 63131, 63132, 63133, 63185, 65329, 65868, 65884, 66110, 66396, 66401, 6880, 6881, 6927, 6935, 71405, 7561, 7591, 77189, 82, 8821, 95, 9937)); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES +(100431, 194468, 530, 0, 0, 1, 1, -2133.075927734375, 5371.8505859375, 53.80774307250976562, 2.286378860473632812, 0, 0, 0.909960746765136718, 0.414694398641586303, 120, 255, 1, "", 45942, NULL), +(10054, 173063, 1, 0, 0, 1, 1, 2021.614990234375, -4688.12939453125, 25.40483283996582031, 2.426007747650146484, 0, 0, 0.936672210693359375, 0.350207358598709106, 120, 255, 1, "", 45435, NULL), +(10118, 2575, 0, 0, 0, 1, 1, -14378.8134765625, 379.263885498046875, 23.31351470947265625, 4.145159721374511718, 0, 0, -0.87672615051269531, 0.48098987340927124, 120, 255, 1, "", 45572, NULL), +(10826, 19902, 0, 0, 0, 1, 1, -6763.6630859375, -3125.5087890625, 242.098419189453125, 1.343902826309204101, 0.042108535766601562, -0.03894233703613281, 0.621876716613769531, 0.781011998653411865, 120, 255, 1, "", 45613, NULL), +(10828, 179924, 0, 0, 0, 1, 1, -6670.96337890625, -2155.569580078125, 243.8922576904296875, 4.886921405792236328, 0, 0, -0.64278793334960937, 0.766044199466705322, 120, 255, 1, "", 45613, NULL), +(1091, 1749, 0, 0, 0, 1, 1, -5579.0400390625, -428.92535400390625, 397.214263916015625, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 45613, NULL), +(11000, 21679, 0, 0, 0, 1, 1, -14380.5419921875, 371.746826171875, 23.94536018371582031, 1.893682122230529785, 0, 0, 0.811573982238769531, 0.584249675273895263, 120, 255, 1, "", 45572, NULL), +(1126, 34571, 0, 0, 0, 1, 1, -5579.162109375, -435.338470458984375, 397.60888671875, 4.712389945983886718, 0, 0, -0.70710659027099609, 0.707106947898864746, 120, 255, 1, "", 45613, NULL), +(11324, 173095, 1, 0, 0, 1, 1, 2051.62890625, -4838.9736328125, 24.58019256591796875, 3.735006093978881835, 0, 0, -0.95630455017089843, 0.292372345924377441, 120, 255, 1, "", 45435, NULL), +(11598, 173064, 1, 0, 0, 1, 1, 2048.722412109375, -4812.20654296875, 22.65833473205566406, 3.735006093978881835, 0, 0, -0.95630455017089843, 0.292372345924377441, 120, 255, 1, "", 45435, NULL), +(11819, 144133, 0, 0, 0, 1, 1, -5340.11083984375, -2940.55078125, 323.762451171875, 1.823866248130798339, -0.05446863174438476, -0.08452987670898437, 0.786145210266113281, 0.609806180000305175, 120, 255, 1, "", 45613, NULL), +(12642, 153459, 0, 0, 0, 1, 1, -10894.9189453125, -3185.491455078125, 49.57025527954101562, 1.856318235397338867, 0, 0, 0.800518035888671875, 0.599308669567108154, 120, 255, 1, "", 45772, NULL), +(12687, 20738, 1, 0, 0, 1, 1, 787.8443603515625, -1821.4989013671875, 91.5555572509765625, 0.095991745591163635, 0, 0, 0.047977447509765625, 0.998848438262939453, 120, 255, 1, "", 45435, NULL), +(12799, 147285, 0, 0, 0, 1, 1, -10950.888671875, -3456.81640625, 64.95444488525390625, 2.570527553558349609, 0, 0, 0.959511756896972656, 0.28166857361793518, 120, 255, 1, "", 48632, NULL), +(13139, 4090, 530, 0, 0, 1, 1, -2976.90234375, 4027.7607421875, 1.764023303985595703, 5.619962215423583984, 0, 0, -0.32556724548339843, 0.945518851280212402, 120, 255, 1, "", 45704, NULL), +(13261, 56897, 1, 0, 0, 1, 1, -1068.0462646484375, -3534.879638671875, 64.31089019775390625, 1.247910022735595703, 0, 0, 0.584249496459960937, 0.811574101448059082, 120, 255, 1, "", 45435, NULL), +(13306, 138317, 1, 0, 0, 1, 1, -2287.17529296875, -1943.8035888671875, 95.7456817626953125, 6.073746204376220703, 0, 0, -0.10452842712402343, 0.994521915912628173, 120, 255, 1, "", 45435, NULL), +(13360, 147285, 1, 0, 0, 1, 1, -1996.5625, -3608.458984375, 21.75933074951171875, 3.630291461944580078, 0, 0, -0.97029495239257812, 0.241925001144409179, 120, 255, 1, "", 45435, NULL), +(13766, 20986, 0, 0, 0, 1, 1, -3794.984375, -862.1007080078125, 11.59808254241943359, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 46902, NULL), +(13813, 23304, 0, 0, 0, 1, 1, -8421.3154296875, 613.4404296875, 95.18099212646484375, 3.81354522705078125, 0, 0, -0.94408893585205078, 0.329690933227539062, 120, 255, 1, "", 45613, NULL), +(13814, 23305, 0, 0, 0, 1, 1, -8425.16015625, 618.067138671875, 95.38744354248046875, 3.81354522705078125, 0, 0, -0.94408893585205078, 0.329690933227539062, 120, 255, 1, "", 45613, NULL), +(13968, 24745, 0, 0, 0, 1, 1, -8420.0986328125, 633.51885986328125, 95.6527099609375, 3.81354522705078125, 0, 0, -0.94408893585205078, 0.329690933227539062, 120, 255, 1, "", 45613, NULL), +(13970, 24746, 0, 0, 0, 1, 1, -8427.1025390625, 631.1102294921875, 95.631072998046875, 2.234022140502929687, 0, 0, 0.898794174194335937, 0.438370853662490844, 120, 255, 1, "", 45613, NULL), +(14273, 34572, 0, 0, 0, 1, 1, -2603.527099609375, -2284.218017578125, 86.29964447021484375, 4.677483558654785156, 0, 0, -0.71933937072753906, 0.694658815860748291, 120, 255, 1, "", 49822, NULL), +(14352, 4090, 0, 0, 0, 1, 1, -3792.044921875, -865.609375, 9.787861824035644531, 0.741763234138488769, 0, 0, 0.362437248229980468, 0.932008147239685058, 120, 255, 1, "", 46902, NULL), +(14796, 38491, 0, 0, 0, 1, 1, -10594.263671875, -1159.22265625, 28.24942779541015625, 5.724681377410888671, 0, 0, -0.27563667297363281, 0.961261868476867675, 120, 255, 1, "", 45613, NULL), +(150251, 202392, 658, 0, 0, 3, 1, 878.23956298828125, 24.69965362548828125, 498.51959228515625, 1.553341388702392578, 0, 0, 0.700908660888671875, 0.713251054286956787, 7200, 255, 1, "", 51666, NULL), +(150275, 202393, 658, 0, 0, 3, 1, 728, -122.15625, 491.925933837890625, 1.535886883735656738, 0, 0, 0.694657325744628906, 0.719340801239013671, 7200, 255, 1, "", 51666, NULL), +(150281, 202391, 658, 0, 0, 3, 1, 855.27777099609375, 68.93402862548828125, 498.538848876953125, 1.300268411636352539, 0, 0, 0.60529327392578125, 0.796002507209777832, 7200, 255, 1, "", 51666, NULL), +(150283, 202394, 658, 0, 0, 3, 1, 661.19964599609375, -121.932289123535156, 491.615386962890625, 1.535886883735656738, 0, 0, 0.694657325744628906, 0.719340801239013671, 7200, 255, 1, "", 51666, NULL), +(151208, 186556, 571, 0, 0, 1, 1, 2426.829833984375, -5083.95849609375, 272.943023681640625, 0.270525157451629638, 0, 0, 0.134850502014160156, 0.990865945816040039, 120, 255, 1, "", 46158, NULL), +(15217, 2728, 0, 0, 0, 1, 1, -1252.359375, -2548.46875, 21.37276458740234375, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 46902, NULL), +(15396, 2727, 0, 0, 0, 1, 1, -936.98773193359375, -3482.45458984375, 51.4742889404296875, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 45572, NULL), +(15728, 51949, 1, 0, 0, 1, 1, -426.52789306640625, -3162.13427734375, 212.420684814453125, 2.923411369323730468, -0.03230953216552734, 0.025470733642578125, 0.993130683898925781, 0.109538912773132324, 120, 255, 1, "", 45435, NULL), +(15733, 169969, 1, 0, 0, 1, 1, -923.12451171875, -3686.859375, 8.161623954772949218, 4.075345039367675781, 0, 0, -0.89297866821289062, 0.450098991394042968, 120, 255, 1, "", 45435, NULL), +(16626, 147285, 530, 0, 0, 1, 1, -714.12109375, 2603.4951171875, 89.20101165771484375, 1.300268411636352539, 0, 0, 0.60529327392578125, 0.796002507209777832, 120, 255, 1, "", 45854, NULL), +(17011, 2573, 0, 0, 0, 1, 1, -574.515625, 45.43229293823242187, 49.8842926025390625, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 46368, NULL), +(17014, 1797, 0, 0, 0, 1, 1, -550.33856201171875, -1437.0208740234375, 52.44382858276367187, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 45854, NULL), +(17141, 1896, 0, 0, 0, 1, 1, -819.25152587890625, -571.79296875, 15.31679153442382812, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 45942, NULL), +(17240, 141838, 1, 0, 0, 1, 1, -7199.05419921875, -3766.189208984375, 8.659154891967773437, 2.696528911590576171, 0, 0, 0.975341796875, 0.220699742436408996, 120, 255, 1, "", 45572, NULL), +(17252, 141841, 1, 0, 0, 1, 1, -7390.02978515625, -4724.98876953125, 8.988080024719238281, 4.040439605712890625, 0, 0, -0.90069770812988281, 0.434446364641189575, 120, 255, 1, "", 45772, NULL), +(17426, 184617, 0, 0, 0, 1, 1, -160.125, -866.33380126953125, 56.50273513793945312, 2.792520999908447265, -0.03234386444091796, -0.00758171081542968, 0.984333038330078125, 0.173161461949348449, 120, 255, 1, "", 45572, NULL), +(18568, 4090, 0, 0, 0, 1, 1, -571.947265625, 39.94140625, 48.07407760620117187, 5.654868602752685546, 0, 0, -0.30901622772216796, 0.95105677843093872, 120, 255, 1, "", 46368, NULL), +(20494, 182056, 530, 0, 0, 1, 1, -1935.828125, -11912.1845703125, 48.0586395263671875, 5.907940864562988281, 0, 0, -0.1865234375, 0.982450485229492187, 120, 255, 1, "", 46158, NULL), +(20562, 3223, 1, 0, 0, 1, 1, -1886.951416015625, -1093.63720703125, 90.000457763671875, 2.740160465240478515, -0.03085994720458984, -0.02042579650878906, 0.979389190673828125, 0.198563039302825927, 120, 255, 1, "", 46368, NULL), +(20709, 183818, 530, 0, 0, 1, 1, 249.648651123046875, 6030.2138671875, 131.5974884033203125, 2.827429771423339843, 0, 0, 0.987688064575195312, 0.156436234712600708, 120, 255, 1, "", 45704, NULL), +(22227, 181716, 530, 0, 0, 1, 1, -4727.85791015625, -12387.09375, 11.0831146240234375, 3.262326002120971679, 0, 0, -0.99817848205566406, 0.060329910367727279, 120, 255, 1, "", 45942, NULL), +(22401, 181990, 530, 0, 0, 1, 1, 8677.5595703125, -6606.2431640625, 70.25475311279296875, 3.534291028976440429, 0, 0, -0.98078536987304687, 0.195089906454086303, 120, 255, 1, "", 45854, NULL), +(22525, 182117, 530, 0, 0, 1, 1, -2649.286376953125, 4441.5537109375, 36.73196029663085937, 3.351046562194824218, 0, 0, -0.99452114105224609, 0.104535527527332305, 120, 255, 1, "", 45704, NULL), +(22762, 182278, 530, 0, 0, 1, 1, -4186.52099609375, -12440.0107421875, 43.38792800903320312, 3.063024282455444335, 0, 0, 0.999228477478027343, 0.039274025708436965, 120, 255, 1, "", 45435, NULL), +(23671, 182860, 530, 0, 0, 1, 1, 173.7569427490234375, 4296.73193359375, 117.1742477416992187, 4.773476600646972656, 0, 0, -0.68518257141113281, 0.728371381759643554, 120, 255, 1, "", 48632, NULL), +(24009, 183121, 530, 0, 0, 1, 1, 216.3246612548828125, 7859.2802734375, 23.9654388427734375, 1.745326757431030273, 0, 0, 0.766043663024902343, 0.642788589000701904, 120, 255, 1, "", 45942, NULL), +(24036, 183148, 530, 0, 0, 1, 1, -1329.3367919921875, 7198.845703125, 34.24901962280273437, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 45704, NULL), +(24217, 183345, 530, 0, 0, 1, 1, 323.560760498046875, 7838.1708984375, 21.79891395568847656, 4.022988319396972656, 0, 0, -0.90445423126220703, 0.426570683717727661, 120, 255, 1, "", 45942, NULL), +(24219, 183347, 530, 0, 0, 1, 1, 189.00347900390625, 2671.132080078125, 88.7217864990234375, 2.474651098251342773, 0, 0, 0.944911956787109375, 0.327324569225311279, 120, 255, 1, "", 45704, NULL), +(24317, 183408, 530, 0, 0, 1, 1, 2544.48095703125, 6512.921875, 3.469935894012451171, 1.173768043518066406, 0, 0, 0.553769111633300781, 0.832670271396636962, 120, 255, 1, "", 45704, NULL), +(24377, 183484, 530, 0, 0, 1, 1, 2330.126708984375, 6059.69091796875, 142.1997222900390625, 1.308995485305786132, 0, 0, 0.608760833740234375, 0.793353796005249023, 120, 255, 1, "", 45704, NULL), +(24587, 183757, 530, 0, 0, 1, 1, 9846.5849609375, -7361.634765625, 19.392669677734375, 4.450565338134765625, 0, 0, -0.79336071014404296, 0.608751833438873291, 120, 255, 1, "", 45572, NULL), +(24588, 183758, 530, 0, 0, 1, 1, 9840.0341796875, -7358.28759765625, 19.392669677734375, 4.09075021743774414, 0, 0, -0.88948535919189453, 0.456963688135147094, 120, 255, 1, "", 45572, NULL), +(24589, 183759, 530, 0, 0, 1, 1, 9853.9775390625, -7361.6435546875, 19.392669677734375, 4.897896289825439453, 0, 0, -0.63857460021972656, 0.769559919834136962, 120, 255, 1, "", 45572, NULL), +(24590, 183760, 530, 0, 0, 1, 1, 9860.2431640625, -7358.53271484375, 19.392669677734375, 5.33464813232421875, 0, 0, -0.45668792724609375, 0.889626979827880859, 120, 255, 1, "", 45572, NULL), +(24647, 183782, 530, 0, 0, 1, 1, -2248.666748046875, 6225.14306640625, 43.85218429565429687, 3.62458205223083496, 0, 0, -0.97098159790039062, 0.239154160022735595, 120, 255, 1, "", 45704, NULL), +(25118, 184286, 530, 0, 0, 1, 1, -3963.257080078125, 2201.802001953125, 101.7742996215820312, 2.836158275604248046, 0, 0, 0.988361358642578125, 0.152124300599098205, 120, 255, 1, "", 45854, NULL), +(25827, 184922, 530, 0, 0, 1, 1, -4236.08984375, -11717.1201171875, -143.95550537109375, 1.744720935821533203, -0.0032806396484375, -0.00522518157958984, 0.76583099365234375, 0.643012285232543945, 120, 255, 1, "", 45942, NULL), +(25828, 184923, 530, 0, 0, 1, 1, -4242.69384765625, -11713.734375, -144.075897216796875, 0.650804519653320312, -0.00008392333984375, -0.00616931915283203, 0.319672584533691406, 0.947507977485656738, 120, 255, 1, "", 45942, NULL), +(26791, 4090, 0, 0, 0, 1, 1, -9460.033203125, 94.203125, 56.53351593017578125, 4.738570213317871093, 0, 0, -0.69779014587402343, 0.716302275657653808, 120, 255, 1, "", 45435, NULL), +(27148, 181884, 530, 0, 0, 1, 1, 7599.20751953125, -6910.67041015625, 93.76873779296875, 4.555310726165771484, 0, 0, -0.76040554046630859, 0.649448513984680175, 120, 255, 1, "", 45942, NULL), +(27638, 184146, 530, 0, 0, 1, 1, 2318.157958984375, 7256.900390625, 365.553924560546875, 0.488691210746765136, 0, 0, 0.241921424865722656, 0.970295846462249755, 120, 255, 1, "", 45942, NULL), +(27811, 187112, 530, 0, 0, 1, 1, 12667.82421875, -6982.90478515625, 14.57323360443115234, 3.124123096466064453, 0, 0, 0.99996185302734375, 0.008734640665352344, 120, 255, 1, "", 45942, NULL), +(28273, 186139, 530, 0, 0, 1, 1, 4142.79931640625, 3064.890625, 336.458526611328125, 5.742135047912597656, 0, 0, -0.26723766326904296, 0.96363067626953125, 120, 255, 1, "", 45704, NULL), +(29723, 184687, 530, 0, 0, 1, 1, -2395.927001953125, 2890.4228515625, -55.8926277160644531, 4.327290058135986328, -0.00849390029907226, 0.004799842834472656, -0.82933425903320312, 0.558667600154876708, 120, 255, 1, "", 49936, NULL), +(30166, 17190, 1, 0, 0, 1, 1, -1981.136962890625, 442.016998291015625, 133.5895843505859375, 3.150327444076538085, 0, 0, -0.99999046325683593, 0.004367320332676172, 120, 255, 1, "", 46368, NULL), +(30172, 175144, 1, 0, 0, 1, 1, 196.7274017333984375, 1173.1475830078125, 167.8319549560546875, 0.593411982059478759, 0, 0, 0.292371749877929687, 0.956304728984832763, 120, 255, 1, "", 46902, NULL), +(30402, 182270, 530, 0, 0, 1, 1, -198.95660400390625, 5483.064453125, 21.8449859619140625, 5.523968696594238281, 0, 0, -0.37055683135986328, 0.928809821605682373, 120, 255, 1, "", 45704, NULL), +(30816, 186138, 530, 0, 0, 1, 1, 2960.78125, 1799.53125, 139.0110931396484375, 0.654497027397155761, 0, 0, 0.321438789367675781, 0.946930348873138427, 120, 255, 1, "", 45704, NULL), +(32298, 130668, 0, 0, 0, 1, 1, -10651.626953125, 1106.9129638671875, 33.60646820068359375, 2.347463846206665039, 0, 0, 0.922200202941894531, 0.386712819337844848, 120, 255, 1, "", 47966, NULL), +(32655, 175851, 1, 0, 0, 1, 1, -1689.623291015625, 3082.467041015625, 32.05278396606445312, 1.562069892883300781, 0, 0, 0.704014778137207031, 0.71018528938293457, 120, 255, 1, "", 45572, NULL), +(32779, 186141, 530, 0, 0, 1, 1, 3065.7578125, 3677.720458984375, 142.3012237548828125, 4.598945140838623046, 0, 0, -0.74605655670166015, 0.665882587432861328, 120, 255, 1, "", 45704, NULL), +(34300, 38491, 0, 0, 0, 1, 1, -344.818359375, 1502.005859375, 16.99886703491210937, 3.551750659942626953, 0, 0, -0.97904491424560546, 0.203644454479217529, 120, 255, 1, "", 46248, NULL), +(387, 1685, 1, 0, 0, 1, 1, 1523.77783203125, -4368.2412109375, 18.21411514282226562, 0, 0, 0, 0, 1, 120, 255, 1, "", 45327, NULL), +(44762, 1743, 0, 0, 0, 1, 1, 2039.029541015625, 150.2760467529296875, 34.25516128540039062, 3.141669034957885742, 0.00436258316040039, -0.00872516632080078, 0.999952316284179687, 0, 120, 255, 1, "", 45572, NULL), +(44871, 38491, 0, 0, 0, 1, 1, 2230.72265625, 313.740234375, 34.91133499145507812, 5.585053920745849609, 0, 0, -0.34202003479003906, 0.939692676067352294, 120, 255, 1, "", 45435, NULL), +(44916, 52175, 0, 0, 0, 1, 1, 1392.591796875, 147.989959716796875, -62.4183311462402343, 1.928588032722473144, 0, 0, 0.821646690368652343, 0.569997072219848632, 120, 255, 1, "", 45572, NULL), +(44917, 52176, 0, 0, 0, 1, 1, 1684.68798828125, 276.8250732421875, -62.1811408996582031, 1.265363454818725585, 0, 0, 0.591309547424316406, 0.806444704532623291, 120, 255, 1, "", 45435, NULL), +(44949, 113754, 0, 0, 0, 1, 1, 1694.1341552734375, 293.993408203125, -62.1811408996582031, 2.975770950317382812, 0, 0, 0.996564865112304687, 0.082815870642662048, 120, 255, 1, "", 45435, NULL), +(45334, 148960, 0, 0, 0, 1, 1, 2979.0419921875, -1491.28125, 145.2322998046875, 4.747295856475830078, 0, 0, -0.69465827941894531, 0.719339847564697265, 120, 255, 1, "", 50664, NULL), +(45606, 181130, 0, 0, 0, 1, 1, 2261.361083984375, -5322.44970703125, 81.84270477294921875, 5.091957569122314453, 0, 0, -0.56101703643798828, 0.827804267406463623, 120, 255, 1, "", 45942, NULL), +(45689, 148960, 0, 0, 0, 1, 1, 1548.6962890625, -5387.109375, 78.22446441650390625, 5.558874130249023437, 0, 0, -0.35429096221923828, 0.935135245323181152, 120, 255, 1, "", 50664, NULL), +(46082, 179886, 0, 0, 0, 1, 1, -593.06597900390625, -4546.814453125, 8.975338935852050781, 2.111847877502441406, 0, 0, 0.870355606079101562, 0.492423713207244873, 120, 255, 1, "", 45772, NULL), +(46161, 34572, 0, 0, 0, 1, 1, 212.6529541015625, -1966.4642333984375, 140.4819793701171875, 4.703663349151611328, 0, 0, -0.71018505096435546, 0.704015016555786132, 120, 255, 1, "", 46902, NULL), +(4623, 1685, 530, 0, 0, 1, 1, 9479.353515625, -6800.869140625, 16.49356460571289062, 5.70722818374633789, 0, 0, -0.28401470184326171, 0.958819925785064697, 120, 255, 1, "", 45854, NULL), +(467, 194468, 530, 0, 0, 1, 1, -1747.6688232421875, 5648.66162109375, 128.023193359375, 4.049167633056640625, 0, 0, -0.89879322052001953, 0.438372820615768432, 120, 255, 1, "", 45942, NULL), +(47586, 176509, 1, 0, 0, 1, 1, 988.24676513671875, 1005.29302978515625, 104.6084671020507812, 2.748894453048706054, 0, 0, 0.980785369873046875, 0.195089906454086303, 120, 255, 1, "", 45435, NULL), +(47603, 50831, 1, 0, 0, 1, 1, 112.123046875, -591.829345703125, -1.67420196533203125, 4.694936752319335937, 0, 0, -0.71325016021728515, 0.700909554958343505, 120, 255, 1, "", 51943, NULL), +(48632, 92490, 1, 0, 0, 1, 1, 6542.94384765625, 434.2857666015625, 7.549087047576904296, 2.172934770584106445, 0.000201702117919921, 0.009753227233886718, 0.884927749633789062, 0.465626090764999389, 120, 255, 1, "", 46248, NULL), +(49092, 179863, 1, 0, 0, 1, 1, 6696.50341796875, -4645.01416015625, 720.94970703125, 3.359769821166992187, 0, 0, -0.99405574798583984, 0.108872212469577789, 120, 255, 1, "", 45854, NULL), +(49393, 180913, 1, 0, 0, 1, 1, -6865.65576171875, 754.037353515625, 42.65666580200195312, 3.394674062728881835, 0, 0, -0.99200439453125, 0.126203224062919616, 120, 255, 1, "", 45704, NULL), +(49803, 1685, 1, 0, 0, 1, 1, 9916.1142578125, 2308.030517578125, 1330.786376953125, 5.986480236053466796, 0, 0, -0.14780902862548828, 0.989015936851501464, 120, 255, 1, "", 46248, NULL), +(5258, 171716, 0, 0, 0, 1, 1, -4762.9716796875, -1117.1053466796875, 499.334869384765625, 2.260197162628173828, 0, 0, 0.904454231262207031, 0.426570683717727661, 120, 255, 1, "", 45435, NULL), +(5430, 171717, 0, 0, 0, 1, 1, -4807.8603515625, -1130.1844482421875, 499.49908447265625, 2.260197162628173828, 0, 0, 0.904454231262207031, 0.426570683717727661, 120, 255, 1, "", 45435, NULL), +(55964, 192020, 571, 0, 0, 1, 1, 1954.1180419921875, -6190.4912109375, 24.12676429748535156, 1.527163028717041015, 0, 0, 0.6915130615234375, 0.722363948822021484, 120, 255, 1, "", 45772, NULL), +(56459, 186654, 571, 0, 0, 1, 1, 421.713531494140625, -4648.42724609375, 246.7728118896484375, 4.799657344818115234, 0, 0, -0.67558956146240234, 0.737277925014495849, 120, 255, 1, "", 45772, NULL), +(56480, 190495, 571, 0, 0, 1, 1, 7793.19091796875, -2950.447998046875, 1257.730712890625, 0.550021290779113769, -0.00670766830444335, 0.016690254211425781, 0.271546363830566406, 0.962257266044616699, 120, 255, 1, "", 46158, NULL), +(56654, 188452, 571, 0, 0, 1, 1, 3309.210205078125, -2341.568115234375, 110.914093017578125, 4.948008537292480468, 0, 0, -0.61909389495849609, 0.785317003726959228, 120, 255, 1, "", 46158, NULL), +(56955, 190765, 571, 0, 0, 1, 1, 5246.63623046875, 4490.5849609375, -84.3280258178710937, 1.851126790046691894, -0.00239181518554687, 0.026426315307617187, 0.798467636108398437, 0.60145270824432373, 120, 255, 1, "", 45942, NULL), +(57486, 190524, 571, 0, 0, 1, 1, 6642.57666015625, -209.402786254882812, 951.870361328125, 2.932138919830322265, 0, 0, 0.994521141052246093, 0.104535527527332305, 120, 255, 1, "", 46368, NULL), +(57539, 192831, 571, 0, 0, 1, 1, 5622.48291015625, 4572.2587890625, -137.663543701171875, 2.391098499298095703, 0, 0, 0.930417060852050781, 0.366502493619918823, 120, 255, 1, "", 45942, NULL), +(57574, 186433, 571, 0, 0, 1, 1, 1401.9322509765625, -3199.857666015625, 160.9440460205078125, 4.694936752319335937, 0.012232780456542968, -0.01244735717773437, -0.71314144134521484, 0.700802862644195556, 120, 255, 1, "", 46158, NULL), +(57733, 192583, 571, 0, 0, 1, 1, 7985.84716796875, 4.990450859069824218, 961.5565185546875, 2.407231092453002929, -0.00676393508911132, 0.00738525390625, 0.933281898498535156, 0.359004944562911987, 120, 255, 1, "", 47720, NULL), +(58133, 188250, 571, 0, 0, 1, 1, 4542.96728515625, -4246.021484375, 170.49212646484375, 5.75086069107055664, 0, 0, -0.263031005859375, 0.96478736400604248, 120, 255, 1, "", 47720, NULL), +(58300, 188257, 571, 0, 0, 1, 1, 3832.708251953125, -4541.69287109375, 209.2318115234375, 3.612833499908447265, 0.01158761978149414, 0.014916419982910156, -0.97215557098388671, 0.233573809266090393, 120, 255, 1, "", 45942, NULL), +(59043, 191346, 571, 0, 0, 1, 1, 2481.087646484375, -1951.9427490234375, 10.88319873809814453, 5.410521507263183593, 0, 0, -0.42261791229248046, 0.906307935714721679, 120, 255, 1, "", 46779, NULL), +(59092, 186486, 571, 0, 0, 1, 1, 544.4949951171875, -4997.93017578125, 10.47229957580566406, 3.001969099044799804, 0.021456718444824218, -0.00587368011474609, 0.997310638427734375, 0.069832757115364074, 120, 255, 1, "", 48632, NULL), +(59113, 187256, 571, 0, 0, 1, 1, 2334.302001953125, 5269.29931640625, 7.547565937042236328, 1.954769015312194824, 0, 0, 0.829037666320800781, 0.559192776679992675, 120, 255, 1, "", 47720, NULL), +(59403, 194487, 571, 0, 0, 1, 1, 8545.7783203125, 934.6180419921875, 547.29266357421875, 3.115387916564941406, 0, 0, 0.999914169311523437, 0.013101960532367229, 120, 255, 1, "", 50129, NULL), +(59623, 1685, 571, 0, 0, 1, 1, 5924.43994140625, 715.0439453125, 642.43829345703125, 4.660029888153076171, 0, 0, -0.72537422180175781, 0.688354730606079101, 120, 255, 1, "", 45327, NULL), +(59624, 1685, 571, 0, 0, 1, 1, 2478.989990234375, -1954.662353515625, 10.88320159912109375, 4.764749526977539062, 0, 0, -0.6883544921875, 0.725374460220336914, 120, 255, 1, "", 46368, NULL), +(60255, 188607, 571, 0, 0, 1, 1, 2760.4541015625, 853.0382080078125, 6.700050830841064453, 1.649336218833923339, 0, 0, 0.734322547912597656, 0.678800702095031738, 120, 255, 1, "", 45854, NULL), +(60307, 188354, 571, 0, 0, 1, 1, 3813.7353515625, 1571.326416015625, 86.64066314697265625, 3.263772249221801757, 0, 0, -0.99813461303710937, 0.061051756143569946, 120, 255, 1, "", 45854, NULL), +(60317, 188356, 571, 0, 0, 1, 1, 3819.686767578125, 1561.798583984375, 86.58795928955078125, 4.756025314331054687, 0, 0, -0.69151210784912109, 0.722364842891693115, 120, 255, 1, "", 45854, NULL), +(60512, 188624, 571, 0, 0, 1, 1, 3417.529541015625, -2759.072998046875, 199.2813720703125, 0.968657433986663818, 0.002991676330566406, 0.003175735473632812, 0.465604782104492187, 0.884981989860534667, 120, 255, 1, "", 46158, NULL), +(61116, 188651, 571, 0, 0, 1, 1, 4131.76416015625, 5282.38818359375, 25.10947418212890625, 5.724681377410888671, 0, 0, -0.27563667297363281, 0.961261868476867675, 120, 255, 1, "", 45854, NULL), +(61125, 188396, 571, 0, 0, 1, 1, 3210.1171875, -635.60418701171875, 160.1486663818359375, 4.180065631866455078, 0, 0, -0.86819839477539062, 0.496217250823974609, 120, 255, 1, "", 45942, NULL), +(61538, 190457, 571, 0, 0, 1, 1, 5409.99462890625, -2662.455078125, 303.933135986328125, 6.025707721710205078, 0, 0, -0.12838363647460937, 0.991724610328674316, 120, 255, 1, "", 45942, NULL), +(61660, 187388, 571, 0, 0, 1, 1, 3071.33935546875, 4826.24755859375, 1.220486998558044433, 5.279621601104736328, 0, 0, -0.4809885025024414, 0.876726925373077392, 120, 255, 1, "", 45854, NULL), +(62356, 192062, 571, 0, 0, 1, 195, 6204.640625, -3.63715291023254394, 410.169921875, 2.164208889007568359, 0.002507686614990234, -0.01356697082519531, 0.88282012939453125, 0.469508498907089233, 120, 255, 1, "", 45942, NULL), +(63130, 191287, 571, 0, 0, 1, 1, 2760.498291015625, 6177.1982421875, 83.32198333740234375, 3.883358240127563476, 0, 0, -0.9320077896118164, 0.36243826150894165, 120, 255, 1, "", 45772, NULL), +(63131, 191288, 571, 0, 0, 1, 1, 2826.31787109375, 6108.43017578125, 83.32198333740234375, 4.694071292877197265, 0, 0, -0.71355342864990234, 0.700600802898406982, 120, 255, 1, "", 45772, NULL), +(63132, 192572, 571, 0, 0, 1, 1, 2757.91162109375, 6203.10693359375, 83.32198333740234375, 3.883358240127563476, 0, 0, -0.9320077896118164, 0.36243826150894165, 120, 255, 1, "", 45772, NULL), +(63133, 192573, 571, 0, 0, 1, 1, 2851.6044921875, 6105.693359375, 83.32198333740234375, 5.082666873931884765, 0, 0, -0.56485652923583984, 0.825189113616943359, 120, 255, 1, "", 45772, NULL), +(63185, 191508, 0, 0, 0, 1, 449, 2438.341064453125, -5655.60595703125, 420.542938232421875, 4.609313011169433593, 0, 0, -0.74259471893310546, 0.669741034507751464, 120, 255, 1, "", 45942, NULL), +(65329, 186653, 571, 0, 0, 1, 1, 413.211822509765625, -4655.423828125, 246.5844268798828125, 2.574358940124511718, 0, 0, 0.960049629211425781, 0.279829770326614379, 120, 255, 1, "", 45772, NULL), +(65868, 191237, 609, 0, 0, 1, 1, 2261.635498046875, -5322.5556640625, 81.92261505126953125, 5.131268978118896484, 0, 0, -0.54463863372802734, 0.838670849800109863, 120, 255, 1, "", 48632, NULL), +(65884, 191505, 609, 0, 0, 1, 231, 2453.395751953125, -5659.1181640625, 420.566162109375, 4.609313011169433593, 0, 0, -0.74259471893310546, 0.669741034507751464, 120, 255, 1, "", 48632, NULL), +(66110, 148960, 609, 0, 0, 1, 1, 1811.8017578125, -6001.63671875, 115.8481292724609375, 4.738570213317871093, 0, 0, -0.69779014587402343, 0.716302275657653808, 120, 255, 1, "", 48632, NULL), +(66396, 191505, 0, 0, 0, 1, 449, 2453.395751953125, -5659.1181640625, 420.56658935546875, 4.609313011169433593, 0, 0, -0.74259471893310546, 0.669741034507751464, 120, 255, 1, "", 45942, NULL), +(66401, 191508, 609, 0, 0, 1, 231, 2438.341064453125, -5655.60595703125, 420.54248046875, 4.609313011169433593, 0, 0, -0.74259471893310546, 0.669741034507751464, 120, 255, 1, "", 48632, NULL), +(6880, 179844, 0, 0, 0, 1, 1, -6525.9970703125, -1188.3726806640625, 309.2177734375, 2.312241077423095703, 0, 0, 0.915246963500976562, 0.402893275022506713, 120, 255, 1, "", 45772, NULL), +(6881, 152034, 0, 0, 0, 1, 1, -6831.6884765625, -1222.37109375, 240.0138702392578125, 1.780233979225158691, 0, 0, 0.7771453857421875, 0.629321098327636718, 120, 255, 1, "", 45772, NULL), +(6927, 152042, 0, 0, 0, 1, 1, -6745.45703125, -1248.993896484375, 246.7498931884765625, 1.780233979225158691, 0, 0, 0.7771453857421875, 0.629321098327636718, 120, 255, 1, "", 45772, NULL), +(6935, 152045, 0, 0, 0, 1, 1, -6686.6318359375, -1428.4888916015625, 241.3292694091796875, 0.47996494174003601, 0.030863761901855468, 0.038967132568359375, 0.236227035522460937, 0.970425546169281005, 120, 255, 1, "", 45772, NULL), +(71405, 193126, 571, 0, 0, 1, 1, 5292.3046875, 2930.510498046875, 409.157135009765625, 3.220161199569702148, 0, 0, -0.99922847747802734, 0.039274025708436965, 120, 255, 1, "", 46248, NULL), +(7561, 186231, 1, 0, 0, 1, 1, -4606.11474609375, -3212.513916015625, 34.81392288208007812, 4.022988319396972656, 0, 0, -0.90445423126220703, 0.426570683717727661, 120, 255, 1, "", 45613, NULL), +(7591, 186630, 1, 0, 0, 1, 1, -3150.38916015625, -2857.26904296875, 34.00139236450195312, 2.085667610168457031, 0, 0, 0.863835334777832031, 0.503774285316467285, 120, 255, 1, "", 45572, NULL), +(77189, 194128, 571, 0, 0, 1, 1, 6096.16845703125, -1074.0052490234375, 404.558258056640625, 0.514872133731842041, -0.0191049575805664, 0.084914207458496093, 0.253370285034179687, 0.963445961475372314, 120, 255, 1, "", 46158, NULL), +(82, 176895, 0, 0, 0, 1, 1, -8100.392578125, -1507.236083984375, 132.9344024658203125, 4.188792228698730468, 0, 0, -0.86602497100830078, 0.50000077486038208, 120, 255, 1, "", 45772, NULL), +(8821, 4090, 1, 0, 0, 1, 1, -3792.841796875, -4369.90234375, 14.97791671752929687, 6.178466320037841796, 0, 0, -0.05233573913574218, 0.998629570007324218, 120, 255, 1, "", 46902, NULL), +(95, 1685, 0, 0, 0, 1, 1, -4816.33935546875, -1250.142333984375, 501.904693603515625, 1.954769015312194824, 0, 0, 0.829037666320800781, 0.559192776679992675, 120, 255, 1, "", 45435, NULL), +(9937, 142078, 0, 0, 0, 1, 1, -12040.26953125, -1005.96307373046875, 49.4103546142578125, 2.417279243469238281, 0, 0, 0.9351348876953125, 0.354291886091232299, 120, 255, 1, "", 45572, NULL); + +-- remaining spawns (no sniffed values available) +-- (`guid` IN (66383, 66616, 31085, 42510, 76879, 44720)) + +-- two remaining spawns actually show in sniffs but with non-existend gameobject IDs +-- guid 31085, id 1745: +-- (, 405870, 0, 40, 20, 1, 1, -11042.3994140625, 1452.140625, 45.19609832763671875, 4.860743999481201171, 0.002847671508789062, 0.003304481506347656, -0.65275287628173828, 0.757558345794677734, 120, 255, 1, 53622), -- 405870 (Area: 20 - Difficulty: 0) CreateObject1 +-- guid 42510, id 2015: +-- (, 405880, 0, 44, 68, 1, 1, -9261.330078125, -2228.619873046875, 63.7667999267578125, 3.141592741012573242, 0, 0.008726119995117187, 0.99996185302734375, 0, 120, 255, 1, 53622), -- 405880 (Area: 68 - Difficulty: 0) CreateObject1 + +-- new spawns +DELETE FROM `gameobject` WHERE (`id` IN (161487, 1685, 178684, 194468, 34571, 38491)) +AND (`guid` BETWEEN 12362 AND 12368); +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES +(12362, 161487, 30, 0, 0, 3, 1, 361.09722900390625, -531.69268798828125, 71.1897735595703125, 4.127707481384277343, 0, 0, -0.880889892578125, 0.473321229219436645, 7200, 255, 1, "", 46248, NULL), +(12363, 1685, 631, 0, 0, 3, 1, -514.44793701171875, 2245.038330078125, 539.29119873046875, 0, 0, 0, 0, 1, 7200, 255, 1, "", 51666, NULL), +(12364, 178684, 30, 0, 0, 3, 1, 649.263916015625, -59.1111106872558593, 41.54756927490234375, 3.595378875732421875, 0, 0, -0.97437000274658203, 0.224951311945915222, 7200, 255, 1, "", 46248, NULL), +(12365, 194468, 530, 0, 0, 1, 1, -1892.86328125, 5669.203125, 127.458251953125, 0.785396754741668701, 0, 0, 0.38268280029296875, 0.923879802227020263, 120, 255, 1, "", 45942, NULL), +(12366, 194468, 530, 0, 0, 1, 1, -2045.0133056640625, 5568.71826171875, 53.38373565673828125, 5.096362113952636718, 0, 0, -0.55919265747070312, 0.829037725925445556, 120, 255, 1, "", 45942, NULL), +(12367, 34571, 30, 0, 0, 3, 1, -105.423355102539062, -584.35174560546875, 42.01491928100585937, 2.364918231964111328, 0, 0, 0.925539970397949218, 0.378649920225143432, 7200, 255, 1, "", 46248, NULL), +(12368, 38491, 33, 0, 0, 1, 1, -344.818359375, 2035.33984375, 16.99887275695800781, 3.551750659942626953, 0, 0, -0.97904491424560546, 0.203644454479217529, 7200, 255, 1, "", 52237, NULL); diff --git a/data/sql/updates/db_world/2024_04_03_00.sql b/data/sql/updates/db_world/2024_04_03_00.sql new file mode 100644 index 000000000..6da6147b7 --- /dev/null +++ b/data/sql/updates/db_world/2024_04_03_00.sql @@ -0,0 +1,3 @@ +-- DB update 2024_04_02_05 -> 2024_04_03_00 +-- remove duplicate 'Door' spawns from Black Temple +DELETE from `gameobject` WHERE (`id` IN (185482, 185892, 185479, 185478, 185481, 185480)) AND (`guid` IN (20567, 20523, 20559, 20558, 20563, 20561)); diff --git a/data/sql/updates/db_world/2024_04_03_01.sql b/data/sql/updates/db_world/2024_04_03_01.sql new file mode 100644 index 000000000..81a4e0ea9 --- /dev/null +++ b/data/sql/updates/db_world/2024_04_03_01.sql @@ -0,0 +1,3 @@ +-- DB update 2024_04_03_00 -> 2024_04_03_01 +-- +UPDATE `creature` SET `spawntimesecs` = 60 WHERE `guid` = 148735 AND `id1` = 23089; diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index dc9b3e24d..8b46604a2 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -364,11 +364,11 @@ Network.OutKBuff = -1 # # Network.OutUBuff -# Description: Amount of memory (in bytes) reserved in the user space per connection for -# output buffering. -# Default: 65536 +# Description: Amount of memory (in bytes) reserved initially in the user space per +# connection for output buffering. +# Default: 4096 -Network.OutUBuff = 65536 +Network.OutUBuff = 4096 # # Network.TcpNoDelay: diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 1b3fe32c8..226bcf709 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -113,6 +113,8 @@ void BattlegroundEY::AddPoints(TeamId teamId, uint32 points) { uint8 honorRewards = uint8(m_TeamScores[teamId] / _honorTics); m_TeamScores[teamId] += points; + if (m_TeamScores[teamId] > BG_EY_MAX_TEAM_SCORE) + m_TeamScores[teamId] = BG_EY_MAX_TEAM_SCORE; for (; honorRewards < uint8(m_TeamScores[teamId] / _honorTics); ++honorRewards) RewardHonorToTeam(GetBonusHonorFromKill(1), teamId); diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 94e7b481e..98389c5c2 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -149,6 +149,7 @@ DBCStorage sScalingStatValuesStore(ScalingStatValuesfmt DBCStorage sSkillLineStore(SkillLinefmt); DBCStorage sSkillLineAbilityStore(SkillLineAbilityfmt); +SkillLineAbilityIndexBySkillLine sSkillLineAbilityIndexBySkillLine; DBCStorage sSkillRaceClassInfoStore(SkillRaceClassInfofmt); SkillRaceClassInfoMap SkillRaceClassInfoBySkill; DBCStorage sSkillTiersStore(SkillTiersfmt); @@ -473,6 +474,9 @@ void LoadDBCStores(const std::string& dataPath) } } + for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore) + sSkillLineAbilityIndexBySkillLine[skillLine->SkillLine].push_back(skillLine); + // Create Spelldifficulty searcher for (SpellDifficultyEntry const* spellDiff : sSpellDifficultyStore) { @@ -945,3 +949,14 @@ EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uin auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender)); return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr; } + +const std::vector& GetSkillLineAbilitiesBySkillLine(uint32 skillLine) +{ + auto it = sSkillLineAbilityIndexBySkillLine.find(skillLine); + if (it == sSkillLineAbilityIndexBySkillLine.end()) + { + static const std::vector emptyVector; + return emptyVector; + } + return it->second; +} diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 3b72e06ed..20b9b0e29 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -75,6 +75,8 @@ typedef std::pair > SkillLineAbilityIndexBySkillLine; +const std::vector& GetSkillLineAbilitiesBySkillLine(uint32 skillLine); extern DBCStorage sAchievementStore; extern DBCStorage sAchievementCriteriaStore; @@ -157,6 +159,7 @@ extern DBCStorage sScalingStatDistributionStore; extern DBCStorage sScalingStatValuesStore; extern DBCStorage sSkillLineStore; extern DBCStorage sSkillLineAbilityStore; +extern SkillLineAbilityIndexBySkillLine sSkillLineAbilityIndexBySkillLine; extern DBCStorage sSkillTiersStore; extern DBCStorage sSoundEntriesStore; extern DBCStorage sSpellCastTimesStore; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index b2304cb18..ab0b84dca 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -198,7 +198,7 @@ void Corpse::ResetGhostTime() m_time = GameTime::GetGameTime().count(); } -void Corpse::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const +void Corpse::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) { if (!target) return; diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 6d1dedcf0..e74f2c943 100644 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -54,7 +54,7 @@ public: void AddToWorld() override; void RemoveFromWorld() override; - void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const override; + void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override; bool Create(ObjectGuid::LowType guidlow); bool Create(ObjectGuid::LowType guidlow, Player* owner); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 7f9886aa4..83f21ac4c 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2738,7 +2738,7 @@ GameObject* GameObject::GetLinkedTrap() return ObjectAccessor::GetGameObject(*this, m_linkedTrap); } -void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const +void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) { if (!target) return; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index a2e352ea8..ed47aa084 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -124,7 +124,7 @@ public: explicit GameObject(); ~GameObject() override; - void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override; + void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override; void AddToWorld() override; void RemoveFromWorld() override; diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp index ad7164c56..100df4604 100644 --- a/src/server/game/Entities/Item/Container/Bag.cpp +++ b/src/server/game/Entities/Item/Container/Bag.cpp @@ -166,7 +166,7 @@ void Bag::StoreItem(uint8 slot, Item* pItem, bool /*update*/) } } -void Bag::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const +void Bag::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) { Item::BuildCreateUpdateBlockForPlayer(data, target); diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h index dfe7654f8..071f4d902 100644 --- a/src/server/game/Entities/Item/Container/Bag.h +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -55,7 +55,7 @@ public: // overwrite virtual Item::DeleteFromDB void DeleteFromDB(CharacterDatabaseTransaction trans) override; - void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; + void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) override; std::string GetDebugInfo() const override; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a831a0804..5f505655d 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -186,7 +186,7 @@ void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const data->AddUpdateBlock(buf); } -void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const +void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) { if (!target) return; @@ -254,7 +254,7 @@ void Object::SendUpdateToPlayer(Player* player) player->GetSession()->SendPacket(&packet); } -void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const +void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) { ByteBuffer buf(500); @@ -494,7 +494,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const } } -void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const +void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) { if (!target) return; @@ -542,7 +542,7 @@ void Object::ClearUpdateMask(bool remove) } } -void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const +void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) { UpdateDataMapType::iterator iter = data_map.find(player); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3547b36ce..f9a9ac69c 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -121,10 +121,10 @@ public: [[nodiscard]] TypeID GetTypeId() const { return m_objectTypeId; } [[nodiscard]] bool isType(uint16 mask) const { return (mask & m_objectType); } - virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const; + virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target); void SendUpdateToPlayer(Player* player); - void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const; + void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target); void BuildOutOfRangeUpdateBlock(UpdateData* data) const; void BuildMovementUpdateBlock(UpdateData* data, uint32 flags = 0) const; @@ -183,7 +183,7 @@ public: [[nodiscard]] virtual bool hasQuest(uint32 /* quest_id */) const { return false; } [[nodiscard]] virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; } virtual void BuildUpdate(UpdateDataMapType&, UpdatePlayerSet&) {} - void BuildFieldsUpdate(Player*, UpdateDataMapType&) const; + void BuildFieldsUpdate(Player*, UpdateDataMapType&); void SetFieldNotifyFlag(uint16 flag) { _fieldNotifyFlags |= flag; } void RemoveFieldNotifyFlag(uint16 flag) { _fieldNotifyFlags &= ~flag; } @@ -223,7 +223,7 @@ protected: uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const; void BuildMovementUpdate(ByteBuffer* data, uint16 flags) const; - virtual void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const; + virtual void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target); uint16 m_objectType; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 47c762efc..7cb8b4146 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -444,6 +444,7 @@ Player::~Player() delete m_runes; delete m_achievementMgr; delete m_reputationMgr; + delete _cinematicMgr; sWorld->DecreasePlayerCount(); @@ -3793,7 +3794,7 @@ Mail* Player::GetMail(uint32 id) return nullptr; } -void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const +void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) { if (target == this) { @@ -5315,10 +5316,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) mSkillStatus.erase(itr); // remove all spells that related to this skill - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) - if (SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j)) - if (pAbility->SkillLine == id) - removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->Spell), SPEC_MASK_ALL, false); + for (SkillLineAbilityEntry const* pAbility : GetSkillLineAbilitiesBySkillLine(id)) + removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->Spell), SPEC_MASK_ALL, false); } } else if (newVal) //add @@ -11937,14 +11936,8 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value) { uint32 raceMask = getRaceMask(); uint32 classMask = getClassMask(); - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + for (SkillLineAbilityEntry const* pAbility : GetSkillLineAbilitiesBySkillLine(skill_id)) { - SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j); - if (!pAbility || pAbility->SkillLine != skill_id) - { - continue; - } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pAbility->Spell); if (!spellInfo) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index fa9251c43..b8e053924 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1974,7 +1974,7 @@ public: [[nodiscard]] WorldSession* GetSession() const { return m_session; } void SetSession(WorldSession* sess) { m_session = sess; } - void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; + void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) override; void DestroyForPlayer(Player* target, bool onDeath = false) const override; void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend = false, float group_rate = 1.0f); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 1639f277e..b274b0799 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -534,6 +534,8 @@ void Unit::Update(uint32 p_time) UpdateSplineMovement(p_time); GetMotionMaster()->UpdateMotion(p_time); + + InvalidateValuesUpdateCache(); } bool Unit::haveOffhandWeapon() const @@ -21065,16 +21067,11 @@ void Unit::SendMovementHover(Player* sendTo) sendTo->SendDirectMessage(&data); } -void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const +void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) { if (!target) return; - ByteBuffer fieldBuffer; - - UpdateMask updateMask; - updateMask.SetCount(m_valuesCount); - uint32* flags = UnitUpdateFieldFlags; uint32 visibleFlag = UF_FLAG_PUBLIC; @@ -21092,7 +21089,30 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (plr && plr->IsInSameRaidWith(target)) visibleFlag |= UF_FLAG_PARTY_MEMBER; - Creature const* creature = ToCreature(); + uint64 cacheKey = static_cast(visibleFlag) << 8 | updateType; + + auto cacheIt = _valuesUpdateCache.find(cacheKey); + if (cacheIt != _valuesUpdateCache.end()) + { + int32 cachePos = static_cast(data->wpos()); + data->append(cacheIt->second.buffer); + + BuildValuesCachePosPointers dataAdjustedPos = cacheIt->second.posPointers; + if (cachePos) + dataAdjustedPos.ApplyOffset(cachePos); + + PatchValuesUpdate(*data, dataAdjustedPos, target); + + return; + } + + BuildValuesCachedBuffer cacheValue(500); + + ByteBuffer fieldBuffer(400); + + UpdateMask updateMask; + updateMask.SetCount(m_valuesCount); + for (uint16 index = 0; index < m_valuesCount; ++index) { if (_fieldNotifyFlags & flags[index] || @@ -21104,37 +21124,13 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (index == UNIT_NPC_FLAGS) { - uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS]; - - if (creature) - { - if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && appendValue & UNIT_NPC_FLAG_FLIGHTMASTER) - { - appendValue |= UNIT_NPC_FLAG_GOSSIP; // flight masters need NPC gossip flag to show instant flight toggle option - } - - if (!target->CanSeeSpellClickOn(creature)) - { - appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK; - } - - if (!target->CanSeeVendor(creature)) - { - appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK; - } - - if (!creature->IsValidTrainerForPlayer(target, &appendValue)) - { - appendValue &= ~UNIT_NPC_FLAG_TRAINER; - } - } - - fieldBuffer << uint32(appendValue); + cacheValue.posPointers.UnitNPCFlagsPos = int32(fieldBuffer.wpos()); + fieldBuffer << m_uint32Values[UNIT_NPC_FLAGS]; } else if (index == UNIT_FIELD_AURASTATE) { - // Check per caster aura states to not enable using a spell in client if specified aura is not by target - fieldBuffer << BuildAuraStateUpdateForTarget(target); + cacheValue.posPointers.UnitFieldAuraStatePos = int32(fieldBuffer.wpos()); + fieldBuffer << uint32(0); // Fill in later. } // FIXME: Some values at server stored in float format but must be sent to client in uint32 format else if (index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME) @@ -21153,115 +21149,35 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) // Gamemasters should be always able to select units - remove not selectable flag else if (index == UNIT_FIELD_FLAGS) { - uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS]; - if (target->IsGameMaster() && target->GetSession()->IsGMAccount()) - appendValue &= ~UNIT_FLAG_NOT_SELECTABLE; - - fieldBuffer << uint32(appendValue); + cacheValue.posPointers.UnitFieldFlagsPos = int32(fieldBuffer.wpos()); + fieldBuffer << m_uint32Values[UNIT_FIELD_FLAGS]; } // use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures else if (index == UNIT_FIELD_DISPLAYID) { - uint32 displayId = m_uint32Values[UNIT_FIELD_DISPLAYID]; - if (creature) - { - CreatureTemplate const* cinfo = creature->GetCreatureTemplate(); - - // this also applies for transform auras - if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(getTransForm())) - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (transform->Effects[i].IsAura(SPELL_AURA_TRANSFORM)) - if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(transform->Effects[i].MiscValue)) - { - cinfo = transformInfo; - break; - } - - if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) - { - if (target->IsGameMaster() && target->GetSession()->IsGMAccount()) - { - if (cinfo->Modelid1) - displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms - else - displayId = 17519; // world visible trigger's model - } - else - { - if (cinfo->Modelid2) - displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players - else - displayId = 11686; // world invisible trigger's model - } - } - } - - fieldBuffer << uint32(displayId); + cacheValue.posPointers.UnitFieldDisplayPos = int32(fieldBuffer.wpos()); + fieldBuffer << m_uint32Values[UNIT_FIELD_DISPLAYID]; } - // hide lootable animation for unallowed players else if (index == UNIT_DYNAMIC_FLAGS) { + cacheValue.posPointers.UnitDynamicFlagsPos = int32(fieldBuffer.wpos()); uint32 dynamicFlags = m_uint32Values[UNIT_DYNAMIC_FLAGS] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER); - - if (creature) - { - if (creature->hasLootRecipient()) - { - dynamicFlags |= UNIT_DYNFLAG_TAPPED; - if (creature->isTappedBy(target)) - dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER; - } - - if (!target->isAllowedToLoot(creature)) - dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE; - } - - // unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras - if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT) - if (!HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID())) - dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT; - fieldBuffer << dynamicFlags; } - // FG: pretend that OTHER players in own group are friendly ("blue") - else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE) + else if (index == UNIT_FIELD_BYTES_2) { - if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target)) - { - FactionTemplateEntry const* ft1 = GetFactionTemplateEntry(); - FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry(); - if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2)) - { - if (index == UNIT_FIELD_BYTES_2) - // Allow targetting opposite faction in party when enabled in config - fieldBuffer << (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8)); // this flag is at uint8 offset 1 !! - else - // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work) - fieldBuffer << uint32(target->GetFaction()); - } - else - fieldBuffer << m_uint32Values[index]; - }// pussywizard / Callmephil - else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() && - (this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT)) - { - if (index == UNIT_FIELD_BYTES_2) - fieldBuffer << (m_uint32Values[index] & 0xFFFFF2FF); // clear UNIT_BYTE2_FLAG_PVP, UNIT_BYTE2_FLAG_FFA_PVP, UNIT_BYTE2_FLAG_SANCTUARY - else - fieldBuffer << (uint32)target->GetFaction(); - } - else - if (!sScriptMgr->IsCustomBuildValuesUpdate(this, updateType, fieldBuffer, target, index)) - { - fieldBuffer << m_uint32Values[index]; - } + cacheValue.posPointers.UnitFieldBytes2Pos = int32(fieldBuffer.wpos()); + fieldBuffer << m_uint32Values[index]; + } + else if (index == UNIT_FIELD_FACTIONTEMPLATE) + { + cacheValue.posPointers.UnitFieldFactionTemplatePos = int32(fieldBuffer.wpos()); + fieldBuffer << m_uint32Values[index]; } else { - if (sScriptMgr->OnBuildValuesUpdate(this, updateType, fieldBuffer, target, index)) - { - continue; - } + if (sScriptMgr->ShouldTrackValuesUpdatePosByIndex(this, updateType, index)) + cacheValue.posPointers.other[index] = static_cast(fieldBuffer.wpos()); // send in current format (float as float, uint32 as uint32) fieldBuffer << m_uint32Values[index]; @@ -21269,9 +21185,167 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + cacheValue.buffer << uint8(updateMask.GetBlockCount()); + updateMask.AppendToPacket(&cacheValue.buffer); + int32 fieldBufferPos = static_cast(cacheValue.buffer.wpos()); + cacheValue.buffer.append(fieldBuffer); + cacheValue.posPointers.ApplyOffset(fieldBufferPos); + + int32 cachePos = static_cast(data->wpos()); + data->append(cacheValue.buffer); + + BuildValuesCachePosPointers dataAdjustedPos = cacheValue.posPointers; + if (cachePos) + dataAdjustedPos.ApplyOffset(cachePos); + + PatchValuesUpdate(*data, dataAdjustedPos, target); + + _valuesUpdateCache.insert(std::pair(cacheKey, std::move(cacheValue))); +} + +void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target) +{ + Creature const* creature = ToCreature(); + + // UNIT_NPC_FLAGS + if (creature && posPointers.UnitNPCFlagsPos >= 0) + { + uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS]; + + if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && appendValue & UNIT_NPC_FLAG_FLIGHTMASTER) + appendValue |= UNIT_NPC_FLAG_GOSSIP; // flight masters need NPC gossip flag to show instant flight toggle option + + if (!target->CanSeeSpellClickOn(creature)) + appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK; + + if (!target->CanSeeVendor(creature)) + appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK; + + if (!creature->IsValidTrainerForPlayer(target, &appendValue)) + appendValue &= ~UNIT_NPC_FLAG_TRAINER; + + valuesUpdateBuf.put(posPointers.UnitNPCFlagsPos, appendValue); + } + + // UNIT_FIELD_AURASTATE + if (posPointers.UnitFieldAuraStatePos >= 0) + valuesUpdateBuf.put(posPointers.UnitFieldAuraStatePos, uint32(BuildAuraStateUpdateForTarget(target))); + + // UNIT_FIELD_FLAGS + if (posPointers.UnitFieldFlagsPos >= 0) + { + uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS]; + if (target->IsGameMaster() && target->GetSession()->IsGMAccount()) + appendValue &= ~UNIT_FLAG_NOT_SELECTABLE; + + valuesUpdateBuf.put(posPointers.UnitFieldFlagsPos, appendValue); + } + + // UNIT_FIELD_DISPLAYID + // Use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures. + if (posPointers.UnitFieldDisplayPos >= 0) + { + uint32 displayId = m_uint32Values[UNIT_FIELD_DISPLAYID]; + if (creature) + { + CreatureTemplate const* cinfo = creature->GetCreatureTemplate(); + + // this also applies for transform auras + if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(getTransForm())) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (transform->Effects[i].IsAura(SPELL_AURA_TRANSFORM)) + if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(transform->Effects[i].MiscValue)) + { + cinfo = transformInfo; + break; + } + + if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) + { + if (target->IsGameMaster() && target->GetSession()->IsGMAccount()) + { + if (cinfo->Modelid1) + displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms + else + displayId = 17519; // world visible trigger's model + } + else + { + if (cinfo->Modelid2) + displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players + else + displayId = 11686; // world invisible trigger's model + } + } + } + + valuesUpdateBuf.put(posPointers.UnitFieldDisplayPos, uint32(displayId)); + } + + // UNIT_DYNAMIC_FLAGS + // Hide lootable animation for unallowed players. + if (posPointers.UnitDynamicFlagsPos >= 0) + { + uint32 dynamicFlags = m_uint32Values[UNIT_DYNAMIC_FLAGS] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER); + + if (creature) + { + if (creature->hasLootRecipient()) + { + dynamicFlags |= UNIT_DYNFLAG_TAPPED; + if (creature->isTappedBy(target)) + dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER; + } + + if (!target->isAllowedToLoot(creature)) + dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE; + } + + // unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras + if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT) + if (!HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID())) + dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT; + + valuesUpdateBuf.put(posPointers.UnitDynamicFlagsPos, dynamicFlags); + } + + // UNIT_FIELD_BYTES_2 + if (posPointers.UnitFieldBytes2Pos >= 0) + { + if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target)) + { + FactionTemplateEntry const* ft1 = GetFactionTemplateEntry(); + FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry(); + if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2)) + // Allow targetting opposite faction in party when enabled in config + valuesUpdateBuf.put(posPointers.UnitFieldBytes2Pos, (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8))); // this flag is at uint8 offset 1 !! + }// pussywizard / Callmephil + else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() && + (this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT)) + { + valuesUpdateBuf.put(posPointers.UnitFieldBytes2Pos, (m_uint32Values[UNIT_FIELD_BYTES_2] & 0xFFFFF2FF)); // clear UNIT_BYTE2_FLAG_PVP, UNIT_BYTE2_FLAG_FFA_PVP, UNIT_BYTE2_FLAG_SANCTUARY + } + } + + // UNIT_FIELD_FACTIONTEMPLATE + if (posPointers.UnitFieldFactionTemplatePos >= 0) + { + if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target)) + { + FactionTemplateEntry const* ft1 = GetFactionTemplateEntry(); + FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry(); + if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2)) + // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work) + valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction())); + }// pussywizard / Callmephil + else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() && + (this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT)) + { + valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction())); + } + } + + sScriptMgr->OnPatchValuesUpdate(this, valuesUpdateBuf, posPointers, target); } void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index a424ae465..fd32ac6ea 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1321,6 +1321,62 @@ private: Unit* defaultValue; }; +// BuildValuesCachePosPointers is marks of the position of some data inside of BuildValue cache. +struct BuildValuesCachePosPointers +{ + BuildValuesCachePosPointers() : + UnitNPCFlagsPos(-1), UnitFieldAuraStatePos(-1), UnitFieldFlagsPos(-1), UnitFieldDisplayPos(-1), + UnitDynamicFlagsPos(-1), UnitFieldBytes2Pos(-1), UnitFieldFactionTemplatePos(-1) {} + + void ApplyOffset(uint32 offset) + { + if (UnitNPCFlagsPos >= 0) + UnitNPCFlagsPos += offset; + + if (UnitFieldAuraStatePos >= 0) + UnitFieldAuraStatePos += offset; + + if (UnitFieldFlagsPos >= 0) + UnitFieldFlagsPos += offset; + + if (UnitFieldDisplayPos >= 0) + UnitFieldDisplayPos += offset; + + if (UnitDynamicFlagsPos >= 0) + UnitDynamicFlagsPos += offset; + + if (UnitFieldBytes2Pos >= 0) + UnitFieldBytes2Pos += offset; + + if (UnitFieldFactionTemplatePos >= 0) + UnitFieldFactionTemplatePos += offset; + + for (auto it = other.begin(); it != other.end(); ++it) + it->second += offset; + } + + int32 UnitNPCFlagsPos; + int32 UnitFieldAuraStatePos; + int32 UnitFieldFlagsPos; + int32 UnitFieldDisplayPos; + int32 UnitDynamicFlagsPos; + int32 UnitFieldBytes2Pos; + int32 UnitFieldFactionTemplatePos; + + std::unordered_map other; +}; + +// BuildValuesCachedBuffer cache for calculated BuildValue. +struct BuildValuesCachedBuffer +{ + BuildValuesCachedBuffer(uint32 bufferSize) : + buffer(bufferSize), posPointers() {} + + ByteBuffer buffer; + + BuildValuesCachePosPointers posPointers; +}; + class Unit : public WorldObject { public: @@ -2511,7 +2567,7 @@ public: protected: explicit Unit (bool isWorldObject); - void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override; + void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override; UnitAI* i_AI, *i_disabledAI; @@ -2604,6 +2660,9 @@ private: [[nodiscard]] float GetCombatRatingReduction(CombatRating cr) const; [[nodiscard]] uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const; + void PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target); + void InvalidateValuesUpdateCache() { _valuesUpdateCache.clear(); } + protected: void SetFeared(bool apply, Unit* fearedBy = nullptr, bool isFear = false); void SetConfused(bool apply); @@ -2641,6 +2700,9 @@ private: uint32 _lastExtraAttackSpell; std::unordered_map extraAttacksTargets; ObjectGuid _lastDamagedTargetGuid; + + typedef std::unordered_map ValuesUpdateCache; + ValuesUpdateCache _valuesUpdateCache; }; namespace Acore diff --git a/src/server/game/Scripting/ScriptDefines/UnitScript.cpp b/src/server/game/Scripting/ScriptDefines/UnitScript.cpp index eb070a6cf..f493b5166 100644 --- a/src/server/game/Scripting/ScriptDefines/UnitScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/UnitScript.cpp @@ -192,18 +192,24 @@ bool ScriptMgr::IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, By return false; } -bool ScriptMgr::OnBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player* target, uint16 index) +bool ScriptMgr::ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index) { - auto ret = IsValidBoolScript([&](UnitScript* script) { return script->OnBuildValuesUpdate(unit, updateType, fieldBuffer, target, index); }); + auto ret = IsValidBoolScript([&](UnitScript* script) { return script->ShouldTrackValuesUpdatePosByIndex(unit, updateType, index); }); if (ret && *ret) - { return true; - } return false; } +void ScriptMgr::OnPatchValuesUpdate(Unit const* unit, ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target) +{ + ExecuteScript([&](UnitScript* script) + { + script->OnPatchValuesUpdate(unit, valuesUpdateBuf, posPointers, target); + }); +} + void ScriptMgr::OnUnitUpdate(Unit* unit, uint32 diff) { ExecuteScript([&](UnitScript* script) diff --git a/src/server/game/Scripting/ScriptDefines/UnitScript.h b/src/server/game/Scripting/ScriptDefines/UnitScript.h index 3b44ca03d..f0341909c 100644 --- a/src/server/game/Scripting/ScriptDefines/UnitScript.h +++ b/src/server/game/Scripting/ScriptDefines/UnitScript.h @@ -22,6 +22,7 @@ enum ReputationRank : uint8; class ByteBuffer; +struct BuildValuesCachePosPointers; class UnitScript : public ScriptObject { @@ -69,7 +70,9 @@ public: [[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; } - [[nodiscard]] virtual bool OnBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player* /*target*/, uint16 /*index*/) { return false; } + [[nodiscard]] virtual bool ShouldTrackValuesUpdatePosByIndex(Unit const* /*unit*/, uint8 /*updateType*/, uint16 /*index*/) { return false; } + + virtual void OnPatchValuesUpdate(Unit const* /*unit*/, ByteBuffer& /*valuesUpdateBuf*/, BuildValuesCachePosPointers& /*posPointers*/, Player* /*target*/) { } /** * @brief This hook runs in Unit::Update diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 7b91cffcc..e4a9cff57 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -581,7 +581,8 @@ public: /* UnitScript */ bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto); bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update); bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index); - bool OnBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player* target, uint16 index); + bool ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index); + void OnPatchValuesUpdate(Unit const* unit, ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target); void OnUnitUpdate(Unit* unit, uint32 diff); void OnDisplayIdChange(Unit* unit, uint32 displayId); void OnUnitEnterEvadeMode(Unit* unit, uint8 why); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 05235bc6f..a2e8e5dcd 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -161,43 +161,53 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result) bool WorldSocket::Update() { EncryptableAndCompressiblePacket* queued; - MessageBuffer buffer(_sendBufferSize); - while (_bufferQueue.Dequeue(queued)) + if (_bufferQueue.Dequeue(queued)) { - queued->CompressIfNeeded(); - - ServerPktHeader header(queued->size() + 2, queued->GetOpcode()); - if (queued->NeedsEncryption()) - _authCrypt.EncryptSend(header.header, header.getHeaderLength()); - - if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength()) + // Allocate buffer only when it's needed but not on every Update() call. + MessageBuffer buffer(_sendBufferSize); + std::size_t currentPacketSize; + do { + queued->CompressIfNeeded(); + ServerPktHeader header(queued->size() + 2, queued->GetOpcode()); + if (queued->NeedsEncryption()) + _authCrypt.EncryptSend(header.header, header.getHeaderLength()); + + currentPacketSize = queued->size() + header.getHeaderLength(); + + if (buffer.GetRemainingSpace() < currentPacketSize) + { + QueuePacket(std::move(buffer)); + buffer.Resize(_sendBufferSize); + } + + if (buffer.GetRemainingSpace() >= currentPacketSize) + { + buffer.Write(header.header, header.getHeaderLength()); + if (!queued->empty()) + buffer.Write(queued->contents(), queued->size()); + } + else // Single packet larger than current buffer size + { + // Resize buffer to fit current packet + buffer.Resize(currentPacketSize); + + // Grow future buffers to current packet size if still below limit + if (currentPacketSize <= 65536) + _sendBufferSize = currentPacketSize; + + buffer.Write(header.header, header.getHeaderLength()); + if (!queued->empty()) + buffer.Write(queued->contents(), queued->size()); + } + + delete queued; + } while (_bufferQueue.Dequeue(queued)); + + if (buffer.GetActiveSize() > 0) QueuePacket(std::move(buffer)); - buffer.Resize(_sendBufferSize); - } - - if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength()) - { - buffer.Write(header.header, header.getHeaderLength()); - if (!queued->empty()) - buffer.Write(queued->contents(), queued->size()); - } - else // single packet larger than 4096 bytes - { - MessageBuffer packetBuffer(queued->size() + header.getHeaderLength()); - packetBuffer.Write(header.header, header.getHeaderLength()); - if (!queued->empty()) - packetBuffer.Write(queued->contents(), queued->size()); - - QueuePacket(std::move(packetBuffer)); - } - - delete queued; } - if (buffer.GetActiveSize() > 0) - QueuePacket(std::move(buffer)); - if (!BaseSocket::Update()) return false; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0e29e95d8..1bd906594 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2323,19 +2323,8 @@ void SpellMgr::LoadPetLevelupSpellMap() if (!creatureFamily->skillLine[j]) continue; - for (uint32 k = 0; k < sSkillLineAbilityStore.GetNumRows(); ++k) + for (SkillLineAbilityEntry const* skillLine : GetSkillLineAbilitiesBySkillLine(creatureFamily->skillLine[j])) { - SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(k); - if (!skillLine) - continue; - - //if (skillLine->skillId != creatureFamily->skillLine[0] && - // (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1])) - // continue; - - if (skillLine->SkillLine != creatureFamily->skillLine[j]) - continue; - if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN) continue; diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 6780b042c..4169428fe 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -352,7 +352,7 @@ public: float x = locationValues[0]; float y = locationValues[1]; - if (!sMapStore.LookupEntry(mapId)) + if (!sMapStore.LookupEntry(mapId) || !MapMgr::IsValidMapCoord(mapId, x, y)) { handler->SendErrorMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); return false; diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index efe99283f..6664a294d 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -390,16 +390,8 @@ public: { uint32 classmask = player->getClassMask(); - for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j) + for (SkillLineAbilityEntry const* skillLine : GetSkillLineAbilitiesBySkillLine(skillId)) { - SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(j); - if (!skillLine) - continue; - - // wrong skill - if (skillLine->SkillLine != skillId) - continue; - // not high rank if (skillLine->SupercededBySpell) continue; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp index d46a0fb33..9768ba034 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp @@ -55,6 +55,7 @@ enum Spells SPELL_RAISE_DEAD_1 = 31617, SPELL_RAISE_DEAD_2 = 31624, SPELL_RAISE_DEAD_3 = 31625, + SPELL_UNHOLY_FRENZY = 31626, SPELL_SHADOW_BOLT = 31627, // Banshee (Ranged) @@ -84,6 +85,8 @@ enum Talk SAY_TELEPORT = 7 }; +const float UNHOLY_FRENZY_RANGE = 30.0f; + class npc_hyjal_jaina : public CreatureScript { public: @@ -411,6 +414,13 @@ struct npc_hyjal_ground_trash : public ScriptedAI break; } context.Repeat(10s, 20s); + }).Schedule(15s, 20s, [this](TaskContext context) + { + if (Creature* target = GetNearbyFriendlyTrashCreature(UNHOLY_FRENZY_RANGE)) + { + DoCast(target, SPELL_UNHOLY_FRENZY); + } + context.Repeat(15s, 20s); }); break; } @@ -501,6 +511,27 @@ struct npc_hyjal_ground_trash : public ScriptedAI } } + Creature* GetNearbyFriendlyTrashCreature(float radius) + { + //need accurate timer + Creature* creatureToReturn = nullptr; + std::list creatureList; + GetCreatureListWithEntryInGrid(creatureList, me, NPC_ABOMI, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_BANSH, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_STALK, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_NECRO, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_CRYPT, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_GHOUL, radius); + GetCreatureListWithEntryInGrid(creatureList, me, NPC_SKELETON_INVADER, radius); + Acore::Containers::RandomResize(creatureList, 1); + if (creatureList.size() > 0) + { + creatureToReturn = creatureList.front(); + } + creatureList.clear(); + return creatureToReturn; + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h index 954d2a838..b0c127f49 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h @@ -78,6 +78,10 @@ enum HyjalCreaturesIds NPC_STALK = 17916, NPC_BUILD = 18304, // Serverside creature? Not found in CreateObject packets, but seen as targets + // Summoned necromancer mobs + NPC_SKELETON_INVADER = 17902, + NPC_SKELETON_MAGE = 17903, + // Alliance Base NPC_JAINA = 17772, NPC_ALLIANCE_PEASANT = 17931, diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp index 323d4af42..d4b5e39ec 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp @@ -390,6 +390,14 @@ struct boss_vem : public boss_bug_trio { DoCastVictim(SPELL_KNOCKDOWN); context.Repeat(); + }) + .Schedule(1s, [this](TaskContext context) + { + if (instance->GetData(DATA_BUG_TRIO_DEATH) == 2 && !me->HasAura(SPELL_VENGEANCE)) // Vem is the only one left. + { + DoCastSelf(SPELL_VENGEANCE, true); + } + context.Repeat(1s); }); } }; diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.h b/src/server/scripts/Outland/BlackTemple/black_temple.h index 4944e0b7e..491125714 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.h +++ b/src/server/scripts/Outland/BlackTemple/black_temple.h @@ -40,17 +40,27 @@ enum DataTypes DATA_RELIQUARY_OF_SOULS = 5, DATA_MOTHER_SHAHRAZ = 6, DATA_ILLIDARI_COUNCIL = 7, - DATA_AKAMA_FINISHED = 8, + DATA_AKAMA_ILLIDAN = 8, DATA_ILLIDAN_STORMRAGE = 9, - MAX_ENCOUNTERS = 10 + MAX_ENCOUNTERS = 10, + + DATA_AKAMA_SHADE = 11, + DATA_GATHIOS_THE_SHATTERER = 12, + DATA_HIGH_NETHERMANCER_ZEREVOR = 13, + DATA_LADY_MALANDE = 14, + DATA_VERAS_DARKSHADOW = 15 }; enum CreatureIds { + NPC_HIGH_WARLORD_NAJENTUS = 22887, + NPC_SUPREMUS = 22898, NPC_SHADE_OF_AKAMA = 22841, NPC_AKAMA_SHADE = 23191, - NPC_STORM_FURY = 22848, + NPC_ASHTONGUE_CHANNELER = 23421, + NPC_CREATURE_GENERATOR_AKAMA = 23210, NPC_TERON_GOREFIEND = 22871, + NPC_GURTOGG_BLOODBOIL = 22948, NPC_VENGEFUL_SPIRIT = 23109, NPC_SHADOWY_CONSTRUCT = 23111, NPC_ANGERED_SOUL_FRAGMENT = 23398, @@ -58,17 +68,26 @@ enum CreatureIds NPC_SUFFERING_SOUL_FRAGMENT = 23399, NPC_RELIQUARY_OF_THE_LOST = 22856, NPC_ENSLAVED_SOUL = 23469, + NPC_MOTHER_SHAHRAZ = 22947, NPC_GATHIOS_THE_SHATTERER = 22949, NPC_HIGH_NETHERMANCER_ZEREVOR = 22950, NPC_LADY_MALANDE = 22951, NPC_VERAS_DARKSHADOW = 22952, NPC_ILLIDARI_COUNCIL = 23426, - NPC_AKAMA = 23089, + NPC_AKAMA_ILLIDAN = 23089, NPC_ILLIDAN_STORMRAGE = 22917, NPC_PARASITIC_SHADOWFIEND = 23498, NPC_BLADE_OF_AZZINOTH = 22996, NPC_FLAME_OF_AZZINOTH = 22997, + NPC_ASHTONGUE_BATTLELORD = 22844, + NPC_ASHTONGUE_MYSTIC = 22845, + NPC_ASHTONGUE_STORMCALLER = 22846, + NPC_ASHTONGUE_PRIMALIST = 22847, + NPC_ASHTONGUE_FERAL_SPIRIT = 22849, + NPC_ASHTONGUE_STALKER = 23374, + NPC_STORM_FURY = 22848, + NPC_DRAGON_TURTLE = 22885 }; diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index c860ef94d..ebc2d0589 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -48,6 +48,8 @@ enum Says SAY_AKAMA_ILLIDAN1 = 4, SAY_AKAMA_ILLIDAN2 = 5, SAY_AKAMA_ILLIDAN3 = 6, + SAY_AKAMA_COUNCIL_1 = 9, + SAY_AKAMA_COUNCIL_2 = 10, SAY_MAIEV_SHADOWSONG_TAUNT = 0, SAY_MAIEV_SHADOWSONG_ILLIDAN1 = 1, @@ -117,6 +119,7 @@ enum Spells enum Misc { + ACTION_ILLIDARI_COUNCIL_DONE = 0, ACTION_FIGHT_MINIONS = 1, ACTION_RETURN_BLADE = 2, ACTION_ILLIDAN_CAGED = 3, @@ -133,7 +136,9 @@ enum Misc NPC_ILLIDAN_DB_TARGET = 23070, NPC_MAIEV_SHADOWSONG = 23197, - GO_CAGE_TRAP = 185916 + GO_CAGE_TRAP = 185916, + + PATH_AKAMA_ILLIDARI_COUNCIL_1 = 230891 }; enum Events @@ -235,15 +240,15 @@ public: void EnterEvadeMode(EvadeReason why) override { - BossAI::EnterEvadeMode(why); + if (Creature* akama = instance->GetCreature(DATA_AKAMA_ILLIDAN)) + akama->DespawnOrUnsummon(); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) - akama->AI()->EnterEvadeMode(why); + BossAI::EnterEvadeMode(why); } bool CanAIAttack(Unit const* target) const override { - return target->GetEntry() != NPC_AKAMA && target->GetEntry() != NPC_MAIEV_SHADOWSONG; + return target->GetEntry() != NPC_AKAMA_ILLIDAN && target->GetEntry() != NPC_MAIEV_SHADOWSONG; } void DoAction(int32 param) override @@ -408,7 +413,7 @@ public: switch (events2.ExecuteEvent()) { case EVENT_SUMMON_MINIONS2: - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) + if (Creature* akama = instance->GetCreature(DATA_AKAMA_ILLIDAN)) akama->AI()->DoAction(ACTION_FIGHT_MINIONS); break; case EVENT_PHASE_2_EYE_BEAM_START: @@ -445,7 +450,7 @@ public: maiev->AI()->Talk(SAY_MAIEV_SHADOWSONG_ILLIDAN3); } - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA))) + if (Creature* akama = instance->GetCreature(DATA_AKAMA_ILLIDAN)) { akama->AI()->DoAction(ACTION_ILLIDAN_DEAD); akama->SetTarget(me->GetGUID()); @@ -754,6 +759,8 @@ enum Akama EVENT_AKAMA_HEALTH = 102 }; +Position AkamaTeleport = { 609.772f, 308.456f, 271.826f, 6.1972566f }; + class npc_akama_illidan : public CreatureScript { public: @@ -764,7 +771,7 @@ public: npc_akama_illidanAI(Creature* creature) : npc_escortAI(creature), summons(me) { instance = creature->GetInstanceScript(); - if (instance->GetBossState(DATA_AKAMA_FINISHED) == DONE) + if (instance->GetBossState(DATA_AKAMA_ILLIDAN) == DONE) { me->GetMap()->LoadGrid(751.664f, 238.933f); me->SetHomePosition(751.664f, 238.933f, 353.106f, 2.18f); @@ -789,6 +796,12 @@ public: summons.DespawnAll(); me->CombatStop(true); } + else if (param == ACTION_ILLIDARI_COUNCIL_DONE) + { + me->NearTeleportTo(AkamaTeleport); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->GetMotionMaster()->MovePath(PATH_AKAMA_ILLIDARI_COUNCIL_1, false); + } } void Reset() override @@ -796,7 +809,6 @@ public: me->SetReactState(REACT_AGGRESSIVE); me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); me->setActive(false); - me->SetVisible(instance->GetBossState(DATA_ILLIDARI_COUNCIL) == DONE && instance->GetBossState(DATA_ILLIDAN_STORMRAGE) != DONE); events.Reset(); summons.DespawnAll(); } @@ -807,7 +819,7 @@ public: me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); me->setActive(true); - if (instance->GetBossState(DATA_AKAMA_FINISHED) != DONE) + if (instance->GetBossState(DATA_AKAMA_ILLIDAN) != DONE) { me->SetReactState(REACT_PASSIVE); Start(false, true); @@ -830,6 +842,22 @@ public: } } + void PathEndReached(uint32 pathId) override + { + if (pathId == PATH_AKAMA_ILLIDARI_COUNCIL_1) + { + ScheduleUniqueTimedEvent(200ms, [&] + { + Talk(SAY_AKAMA_COUNCIL_1); + }, 1); + ScheduleUniqueTimedEvent(7800ms, [&] + { + Talk(SAY_AKAMA_COUNCIL_2); + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + }, 2); + } + } + void JustSummoned(Creature* summon) override { summons.Summon(summon); @@ -878,6 +906,7 @@ public: void UpdateEscortAI(uint32 diff) override { + scheduler.Update(diff); events.Update(diff); switch (events.ExecuteEvent()) { @@ -913,8 +942,8 @@ public: udalo->CastSpell(udalo, SPELL_AKAMA_DOOR_OPEN, false); break; case EVENT_AKAMA_SCENE_9: - instance->SetBossState(DATA_AKAMA_FINISHED, NOT_STARTED); - instance->SetBossState(DATA_AKAMA_FINISHED, DONE); + instance->SetBossState(DATA_AKAMA_ILLIDAN, NOT_STARTED); + instance->SetBossState(DATA_AKAMA_ILLIDAN, DONE); break; case EVENT_AKAMA_SCENE_10: Talk(SAY_AKAMA_BEWARE); @@ -923,40 +952,40 @@ public: SetEscortPaused(false); break; case EVENT_AKAMA_SCENE_20: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->SetStandState(UNIT_STAND_STATE_STAND); break; case EVENT_AKAMA_SCENE_21: me->SetFacingTo(M_PI); break; case EVENT_AKAMA_SCENE_22: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA1); break; case EVENT_AKAMA_SCENE_23: Talk(SAY_AKAMA_ILLIDAN1); break; case EVENT_AKAMA_SCENE_24: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA2); break; case EVENT_AKAMA_SCENE_25: Talk(SAY_AKAMA_ILLIDAN2); break; case EVENT_AKAMA_SCENE_26: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->Talk(SAY_ILLIDAN_AKAMA3); break; case EVENT_AKAMA_SCENE_27: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->LoadEquipment(1, true); break; case EVENT_AKAMA_SCENE_28: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NO_SHEATHE); break; case EVENT_AKAMA_SCENE_29: - if (Creature* illidan = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDAN_STORMRAGE))) + if (Creature* illidan = instance->GetCreature(DATA_ILLIDAN_STORMRAGE)) { illidan->SetImmuneToAll(false); illidan->SetInCombatWithZone(); diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index 691c345e0..d55c9169f 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -25,30 +25,43 @@ enum Says SAY_BROKEN_FREE_0 = 0, SAY_BROKEN_FREE_1 = 1, SAY_BROKEN_FREE_2 = 2, + SAY_LOW_HEALTH = 3, + SAY_DEATH = 4, + SAY_BROKEN_S1 = 0, SAY_BROKEN_S2 = 1 }; enum Spells { + // Akama SPELL_STEALTH = 34189, - SPELL_AKAMA_SOUL_CHANNEL = 40447, - SPELL_SHADE_SOUL_CHANNEL = 40401, - SPELL_CHAIN_LIGHTNING = 39945, SPELL_DESTRUCTIVE_POISON = 40874, - SPELL_SHADE_OF_AKAMA_TRIGGER = 40955, - SPELL_AKAMA_SOUL_RETRIEVE = 40902, + SPELL_CHAIN_LIGHTNING = 39945, + SPELL_AKAMA_SOUL_CHANNEL = 40447, + SPELL_FIXATE = 40607, + SPELL_AKAMA_SOUL_RETRIEVE = 40902, // epilogue + SPELL_AKAMA_SOUL_EXPEL_CHANNEL = 40927, // epilogue - SPELL_ASHTONGUE_WAVE_B = 42035, - SPELL_SUMMON_ASHTONGUE_SORCERER = 40476, - SPELL_SUMMON_ASHTONGUE_DEFENDER = 40474 + // Shade & Channelers + SPELL_SHADE_SOUL_CHANNEL = 40401, + SPELL_THREAT = 41602, + SPELL_SHADE_OF_AKAMA_TRIGGER = 40955, + + // Summons + SPELL_ASHTONGUE_WAVE_A = 42073, // unused + SPELL_ASHTONGUE_WAVE_B = 42035, + SPELL_SUMMON_ASHTONGUE_SORCERER = 40476, + SPELL_SUMMON_ASHTONGUE_DEFENDER = 40474 }; enum Creatures { - NPC_ASHTONGUE_CHANNELER = 23421, - NPC_CREATURE_GENERATOR_AKAMA = 23210, NPC_ASHTONGUE_SORCERER = 23215, + NPC_ASHTONGUE_DEFENDER = 23216, + NPC_ASHTONGUE_ELEMENTAL = 23523, + NPC_ASHTONGUE_ROGUE = 23318, + NPC_ASHTONGUE_SPIRITBIND = 23524, NPC_ASHTONGUE_BROKEN = 23319 }; @@ -56,220 +69,137 @@ enum Misc { SUMMON_GROUP_BROKENS = 1, - POINT_START = 0, - POINT_CHANNEL_SOUL = 1, + POINT_ENGAGE = 0, + POINT_OUTRO = 1, - ACTION_AKAMA_DIED = 1, - ACTION_START_ENCOUNTER = 2, - ACTION_STOP_SPAWNING = 3, - ACTION_DESPAWN_ALL = 4, - ACTION_CHANNELERS_START_CHANNEL = 5, - ACTION_KILL_CHANNELERS = 6, - ACTION_NO_SORCERERS = 7, - ACTION_SHADE_DIED = 8, + ACTION_GENERATOR_START = 1, + ACTION_GENERATOR_STOP = 2, + ACTION_GENERATOR_DESPAWN_ALL = 3, - EVENT_AKAMA_START_ENCOUNTER = 1, - EVENT_AKAMA_START_CHANNEL = 2, - EVENT_SPELL_CHAIN_LIGHTNING = 4, - EVENT_SPELL_DESTRUCTIVE_POISON = 5, + COUNTER_SPAWNS_MAX = 20, // Max number of spawns for each generator, number chosen at random - EVENT_SHADE_CHECK_DISTANCE = 10, - EVENT_SHADE_RESET_ENCOUNTER = 11, - EVENT_SHADE_GATHER_NPCS = 12, + ACTION_AKAMA_START_OUTRO = 1, - EVENT_SUMMON_WAVE_B = 20, - EVENT_SUMMON_ASHTONGUE_SORCERER = 21, - EVENT_SUMMON_ASHTONGUE_DEFENDER = 22, - - EVENT_AKAMA_SCENE0 = 29, - EVENT_AKAMA_SCENE1 = 30, - EVENT_AKAMA_SCENE2 = 31, - EVENT_AKAMA_SCENE3 = 32, - EVENT_AKAMA_SCENE4 = 33, - EVENT_AKAMA_SCENE5 = 34, - EVENT_AKAMA_SCENE6 = 35, - EVENT_AKAMA_SCENE7 = 36 + FACTION_DEFAULT = 1820, + FACTION_ENGAGE = 1868 }; +Position AkamaEngage = { 517.4877f, 400.79926f, 112.77704f }; +Position AkamaOutro = { 469.0867f, 401.0793f, 118.52704f, 0.087266460061073303f }; +Position ShadeEngage = { 512.48773f, 400.8283f, 112.77704f }; + struct boss_shade_of_akama : public BossAI { - boss_shade_of_akama(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA), summonsChanneler(me), summonsGenerator(me) - { - events2.ScheduleEvent(EVENT_SHADE_GATHER_NPCS, 1000); - } + boss_shade_of_akama(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA) { } - SummonList summonsChanneler; - SummonList summonsGenerator; - EventMap events2; - - void ChannelersAction(int32 action) - { - for (SummonList::const_iterator i = summonsChanneler.begin(); i != summonsChanneler.end(); ++i) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - { - if (action == ACTION_CHANNELERS_START_CHANNEL) - { - summon->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); - summon->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - else if (action == ACTION_START_ENCOUNTER) - { - summon->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - else if (action == ACTION_KILL_CHANNELERS) - { - Unit::Kill(me, summon); - } - } - } + std::list channelers; + std::list generators; void Reset() override { - BossAI::Reset(); - me->SetReactState(REACT_PASSIVE); + channelers.clear(); + generators.clear(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(true); me->SetWalk(true); + me->SetReactState(REACT_DEFENSIVE); + BossAI::Reset(); } void EnterEvadeMode(EvadeReason why) override { + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_DESPAWN_ALL); + + for (Creature* channeler : channelers) + channeler->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + BossAI::EnterEvadeMode(why); - summonsGenerator.DoAction(ACTION_DESPAWN_ALL); - events2.ScheduleEvent(EVENT_SHADE_RESET_ENCOUNTER, 20000); - me->SetVisible(false); - ChannelersAction(ACTION_KILL_CHANNELERS); } void JustDied(Unit* killer) override { BossAI::JustDied(killer); - summonsGenerator.DoAction(ACTION_DESPAWN_ALL); - summonsChanneler.DespawnAll(); me->CastSpell(me, SPELL_SHADE_OF_AKAMA_TRIGGER, true); - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_DESPAWN_ALL); + + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + akama->AI()->DoAction(ACTION_AKAMA_START_OUTRO); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_AKAMA_SOUL_CHANNEL) { - akama->SetHomePosition(*akama); - akama->AI()->DoAction(ACTION_SHADE_DIED); + instance->SetBossState(DATA_SHADE_OF_AKAMA, IN_PROGRESS); + + me->GetCreatureListWithEntryInGrid(channelers, NPC_ASHTONGUE_CHANNELER, 40.0f); + me->GetCreatureListWithEntryInGrid(generators, NPC_CREATURE_GENERATOR_AKAMA, 100.0f); + + for (Creature* channeler : channelers) + channeler->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_START); + + ScheduleTimedEvent(1200ms, [&] + { + if (me->GetSpeed(MOVE_WALK) > 0.01f) + { + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(POINT_ENGAGE, ShadeEngage); + } + }, 1200ms); } } - void DoAction(int32 param) override + void MovementInform(uint32 type, uint32 point) override { - if (param == ACTION_START_ENCOUNTER) + if (type == POINT_MOTION_TYPE && point == POINT_ENGAGE) { - summonsGenerator.DoAction(ACTION_START_ENCOUNTER); - ChannelersAction(ACTION_START_ENCOUNTER); - events.ScheduleEvent(EVENT_SHADE_CHECK_DISTANCE, 1000); - } - else if (param == ACTION_AKAMA_DIED) - { - EnterEvadeMode(EVADE_REASON_OTHER); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL); + scheduler.CancelAll(); + + for (Creature* generator : generators) + generator->AI()->DoAction(ACTION_GENERATOR_STOP); + + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + { + akama->SetReactState(REACT_AGGRESSIVE); + akama->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoCast(akama, SPELL_THREAT, true); + me->AddThreat(akama, 900000.0f); + akama->AI()->DoCast(me, SPELL_FIXATE, true); + AttackStart(akama); + } + + ScheduleTimedEvent(3500ms, [&] + { + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + me->AddThreat(akama, 900000.0f); + }, 3500ms); } } void UpdateAI(uint32 diff) override { - events2.Update(diff); - switch (events2.ExecuteEvent()) - { - case EVENT_SHADE_GATHER_NPCS: - { - std::list ChannelerList; - me->GetCreaturesWithEntryInRange(ChannelerList, 100.0f, NPC_ASHTONGUE_CHANNELER); - for (std::list::const_iterator itr = ChannelerList.begin(); itr != ChannelerList.end(); ++itr) - summonsChanneler.Summon(*itr); - - std::list SpawnerList; - me->GetCreaturesWithEntryInRange(SpawnerList, 100.0f, NPC_CREATURE_GENERATOR_AKAMA); - for (std::list::const_iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr) - summonsGenerator.Summon(*itr); - - summonsChanneler.Respawn(); - summonsGenerator.Respawn(); - ChannelersAction(ACTION_CHANNELERS_START_CHANNEL); - - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - akama->Respawn(true); - break; - } - case EVENT_SHADE_RESET_ENCOUNTER: - me->SetVisible(true); - summonsGenerator.Respawn(); - summonsChanneler.Respawn(); - ChannelersAction(ACTION_CHANNELERS_START_CHANNEL); - - if (Creature* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - akama->Respawn(true); - break; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SHADE_CHECK_DISTANCE: - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - int32 slow = me->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow > -100) - { - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_START, 510.0f, 400.7993f, 112.7837f); - } - } - else - { - int32 slow = me->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); - if (slow < -100) - me->GetMotionMaster()->Clear(); - else if (slow == 0) - { - summonsGenerator.DoAction(ACTION_NO_SORCERERS); - me->SetWalk(false); - } - } - - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->SetReactState(REACT_AGGRESSIVE); - DoResetThreatList(); - me->GetVictim()->InterruptNonMeleeSpells(false); - me->AddThreat(me->GetVictim(), 1000000.0f); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - summonsGenerator.DoAction(ACTION_STOP_SPAWNING); - break; - } - events.ScheduleEvent(EVENT_SHADE_CHECK_DISTANCE, 1000); - break; - } + scheduler.Update(diff); DoMeleeAttackIfReady(); } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return !SelectTargetFromPlayerList(120.0f); - } }; struct npc_akama_shade : public ScriptedAI { - npc_akama_shade(Creature* creature) : ScriptedAI(creature), summons(me) + npc_akama_shade(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); } InstanceScript* instance; - EventMap events; - EventMap events2; - SummonList summons; void Reset() override { @@ -279,244 +209,262 @@ struct npc_akama_shade : public ScriptedAI return; } + me->SetFaction(FACTION_DEFAULT); me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->CastSpell(me, SPELL_STEALTH, true); - events.Reset(); - events2.Reset(); + DoCastSelf(SPELL_STEALTH, true); + me->SetWalk(true); + scheduler.CancelAll(); } void MovementInform(uint32 type, uint32 point) override { - if (type != POINT_MOTION_TYPE || point != POINT_CHANNEL_SOUL) - return; + if (type == POINT_MOTION_TYPE) + { + switch (point) + { + case POINT_ENGAGE: + me->SetHomePosition(me->GetPosition()); + me->SetFaction(FACTION_ENGAGE); + DoCast(me, SPELL_AKAMA_SOUL_CHANNEL, true); + break; + case POINT_OUTRO: + DoCastSelf(SPELL_AKAMA_SOUL_RETRIEVE, true); + ScheduleUniqueTimedEvent(15600ms, [&] + { + Talk(SAY_BROKEN_FREE_0); + me->SummonCreatureGroup(SUMMON_GROUP_BROKENS); + }, 1); + ScheduleUniqueTimedEvent(26550ms, [&] + { + Talk(SAY_BROKEN_FREE_1); + }, 2); + ScheduleUniqueTimedEvent(37500ms, [&] + { + Talk(SAY_BROKEN_FREE_2); + }, 3); + ScheduleUniqueTimedEvent(52000ms, [&] + { + std::list brokens; + me->GetCreatureListWithEntryInGrid(brokens, NPC_ASHTONGUE_BROKEN, 40.0f); + if (Creature* broken = GetClosestCreatureWithEntry(me, NPC_ASHTONGUE_BROKEN, 40.0f)) + broken->AI()->Talk(SAY_BROKEN_S1); - me->SetFacingTo(0.0f); - events2.ScheduleEvent(EVENT_AKAMA_SCENE1, 1000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE2, 16500); - events2.ScheduleEvent(EVENT_AKAMA_SCENE3, 17500); - events2.ScheduleEvent(EVENT_AKAMA_SCENE4, 27000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE5, 37000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE6, 51000); - events2.ScheduleEvent(EVENT_AKAMA_SCENE7, 56000); + for (Creature* broken : brokens) + { + broken->SetStandState(UNIT_STAND_STATE_KNEEL); + broken->SetFaction(FACTION_DEFAULT); + broken->AI()->Talk(SAY_BROKEN_S2, 4800ms); + } + }, 4); + break; + } + } } void DoAction(int32 param) override { - if (param == ACTION_SHADE_DIED) - events2.ScheduleEvent(EVENT_AKAMA_SCENE0, 1000); + if (param == ACTION_AKAMA_START_OUTRO) + { + me->SetWalk(false); + me->GetMotionMaster()->MovePoint(POINT_OUTRO, AkamaOutro); + } } + void JustSummoned(Creature* summon) override + { + // In Retail they seem to me like they should move in formations of 3 to set points, this is simpler for now + ScriptedAI::JustSummoned(summon); + float x, y, z; + me->GetNearPoint(summon, x, y, z, 25.f, 0, me->GetAngle(summon)); + summon->SetWalk(true); + summon->GetMotionMaster()->MovePoint(POINT_OUTRO, x, y, z); + } + + void EnterEvadeMode(EvadeReason /*why*/) override { } + void JustDied(Unit* /*killer*/) override { - if (Creature* shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SHADE_OF_AKAMA))) - shade->AI()->DoAction(ACTION_AKAMA_DIED); + if (Creature* shade = instance->GetCreature(DATA_SHADE_OF_AKAMA)) + { + shade->SetHomePosition(shade->GetHomePosition()); + shade->AI()->EnterEvadeMode(); + } + + me->DespawnOrUnsummon(); } void JustEngagedWith(Unit* /*who*/) override { - events.ScheduleEvent(EVENT_SPELL_CHAIN_LIGHTNING, 2000); - events.ScheduleEvent(EVENT_SPELL_DESTRUCTIVE_POISON, 5000); + ScheduleTimedEvent(2s, [&] + { + DoCastVictim(SPELL_CHAIN_LIGHTNING); + }, 10s, 15s); + ScheduleTimedEvent(5s, [&] + { + DoCastVictim(SPELL_DESTRUCTIVE_POISON); + }, 4s, 15s); } - void JustSummoned(Creature* summon) override + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override { - float dist = frand(30.0f, 32.0f); - summon->SetWalk(true); - summon->GetMotionMaster()->MovePoint(POINT_START, summon->GetPositionX() + dist * cos(summon->GetOrientation()), summon->GetPositionY() + dist * std::sin(summon->GetOrientation()), summon->GetPositionZ(), false); - summons.Summon(summon); + CloseGossipMenuFor(player); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->RemoveAurasDueToSpell(SPELL_STEALTH); + me->GetMotionMaster()->MovePoint(POINT_ENGAGE, AkamaEngage); } void UpdateAI(uint32 diff) override { - events2.Update(diff); - switch (events2.ExecuteEvent()) - { - case EVENT_AKAMA_START_ENCOUNTER: - me->RemoveAura(SPELL_STEALTH); - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_START, 517.4877f, 400.7993f, 112.7837f, false); - events2.ScheduleEvent(EVENT_AKAMA_START_CHANNEL, 11000); - break; - case EVENT_AKAMA_START_CHANNEL: - me->CastSpell(me, SPELL_AKAMA_SOUL_CHANNEL, false); - if (Creature* shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_SHADE_OF_AKAMA))) - { - shade->AI()->AttackStart(me); - shade->GetMotionMaster()->Clear(); - shade->AI()->DoAction(ACTION_START_ENCOUNTER); - } - break; - case EVENT_AKAMA_SCENE0: - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_CHANNEL_SOUL, 467.0f, 400.7993f, 118.537f); - break; - case EVENT_AKAMA_SCENE1: - me->CastSpell(me, SPELL_AKAMA_SOUL_RETRIEVE, true); - break; - case EVENT_AKAMA_SCENE2: - Talk(SAY_BROKEN_FREE_0); - break; - case EVENT_AKAMA_SCENE3: - me->SummonCreatureGroup(SUMMON_GROUP_BROKENS); - break; - case EVENT_AKAMA_SCENE4: - Talk(SAY_BROKEN_FREE_1); - break; - case EVENT_AKAMA_SCENE5: - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* broken = ObjectAccessor::GetCreature(*me, *itr)) - broken->SetStandState(UNIT_STAND_STATE_KNEEL); - Talk(SAY_BROKEN_FREE_2); - break; - case EVENT_AKAMA_SCENE6: - if (Creature* broken = summons.GetCreatureWithEntry(NPC_ASHTONGUE_BROKEN)) - broken->AI()->Talk(SAY_BROKEN_S1); - break; - case EVENT_AKAMA_SCENE7: - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* broken = ObjectAccessor::GetCreature(*me, *itr)) - broken->AI()->Talk(SAY_BROKEN_S2); - break; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_CHAIN_LIGHTNING: - me->CastSpell(me->GetVictim(), SPELL_CHAIN_LIGHTNING, false); - events.ScheduleEvent(EVENT_SPELL_CHAIN_LIGHTNING, urand(10000, 15000)); - break; - case EVENT_SPELL_DESTRUCTIVE_POISON: - me->CastSpell(me, SPELL_DESTRUCTIVE_POISON, false); - events.ScheduleEvent(EVENT_SPELL_DESTRUCTIVE_POISON, urand(4000, 5000)); - break; - } - + scheduler.Update(diff); DoMeleeAttackIfReady(); } - - void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override - { - if (action == 0) - { - CloseGossipMenuFor(player); - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - events2.ScheduleEvent(EVENT_AKAMA_START_ENCOUNTER, 0); - } - } }; -struct npc_creature_generator_akama : public NullCreatureAI +struct npc_creature_generator_akama : public ScriptedAI { - npc_creature_generator_akama(Creature* creature) : NullCreatureAI(creature), summons(me) + npc_creature_generator_akama(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); } + uint8 spawnCounter = 0; + void Reset() override { - events.Reset(); summons.DespawnAll(); + scheduler.CancelAll(); } void JustSummoned(Creature* summon) override { - summons.Summon(summon); - if (summon->GetEntry() == NPC_ASHTONGUE_SORCERER) + spawnCounter++; + ScriptedAI::JustSummoned(summon); + + switch (summon->GetEntry()) { - std::list channelerList; - me->GetCreaturesWithEntryInRange(channelerList, 120.0f, NPC_ASHTONGUE_CHANNELER); - for (std::list::const_iterator itr = channelerList.begin(); itr != channelerList.end(); ++itr) + case NPC_ASHTONGUE_SORCERER: + if (Creature* shade = instance->GetCreature(DATA_SHADE_OF_AKAMA)) { - if ((*itr)->IsAlive() || (*itr)->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - continue; - - summon->SetInCombatWithZone(); - summon->SetReactState(REACT_PASSIVE); - summon->GetMotionMaster()->MovePoint(POINT_START, **itr); - (*itr)->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - return; + float x, y, z; + shade->GetNearPoint(shade, x, y, z, 20.f, 0, shade->GetAngle(summon)); + summon->GetMotionMaster()->MovePoint(POINT_ENGAGE, x, y, z); } - } - - summon->SetInCombatWithZone(); - if (Unit* akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_AKAMA_SHADE))) - { - summon->AddThreat(akama, 500.0f); - summon->AI()->AttackStart(akama); + break; + default: + summon->SetInCombatWithZone(); + if (Creature* akama = instance->GetCreature(DATA_AKAMA_SHADE)) + summon->AI()->AttackStart(akama); + break; } } void SummonedCreatureDies(Creature* summon, Unit*) override { + spawnCounter--; summon->DespawnOrUnsummon(10000); summons.Despawn(summon); } void DoAction(int32 param) override { - if (param == ACTION_STOP_SPAWNING || param == ACTION_DESPAWN_ALL) + switch (param) { - events.Reset(); - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) + case ACTION_GENERATOR_STOP: + scheduler.CancelAll(); + break; + case ACTION_GENERATOR_START: + if (me->GetPositionY() > 400.0f) // Right Side { - if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr)) + ScheduleTimedEvent(10s, [&] { - if (summon->GetEntry() != NPC_ASHTONGUE_SORCERER) - continue; - summon->InterruptNonMeleeSpells(false); - summon->GetMotionMaster()->Clear(); - summon->SetInCombatWithZone(); - } + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_ASHTONGUE_WAVE_B); + }, 50s, 60s); + + ScheduleTimedEvent(2s, 5s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER); + }, 30s, 40s); } - } - if (param == ACTION_DESPAWN_ALL) + + if (me->GetPositionY() < 400.0f) // Left Side + { + ScheduleTimedEvent(3s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_ASHTONGUE_WAVE_B); + }, 50s, 60s); + + ScheduleTimedEvent(2s, 5s, [&] + { + if (spawnCounter <= COUNTER_SPAWNS_MAX) + DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER); + }, 30s, 35s); + } + break; + case ACTION_GENERATOR_DESPAWN_ALL: summons.DespawnAll(); - else if (param == ACTION_NO_SORCERERS) - events.CancelEvent(EVENT_SUMMON_ASHTONGUE_SORCERER); - else if (param == ACTION_START_ENCOUNTER) - { - events.ScheduleEvent(EVENT_SUMMON_WAVE_B, 5000); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, 20000); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, 35000); + scheduler.CancelAll(); + break; } } void UpdateAI(uint32 diff) override { - events.Update(diff); - - switch (events.ExecuteEvent()) - { - case EVENT_SUMMON_WAVE_B: - me->CastSpell(me, SPELL_ASHTONGUE_WAVE_B, true); - events.ScheduleEvent(EVENT_SUMMON_WAVE_B, 45000); - break; - case EVENT_SUMMON_ASHTONGUE_SORCERER: // left - me->CastSpell(me, SPELL_SUMMON_ASHTONGUE_SORCERER, true); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, 45000); - break; - case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right - me->CastSpell(me, SPELL_SUMMON_ASHTONGUE_DEFENDER, true); - events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, 45000); - break; - default: - break; - } + scheduler.Update(diff); } private: - EventMap events; SummonList summons; InstanceScript* instance; }; +struct npc_ashtongue_sorcerer : public NullCreatureAI +{ + npc_ashtongue_sorcerer(Creature* creature) : NullCreatureAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type == POINT_MOTION_TYPE && point == POINT_ENGAGE) + me->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); + } + +private: + InstanceScript* instance; +}; + +struct npc_ashtongue_channeler : public NullCreatureAI +{ + npc_ashtongue_channeler(Creature* creature) : NullCreatureAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() override + { + scheduler.Schedule(3600ms, [this](TaskContext context) + { + if (!me->HasUnitState(UNIT_STATE_CASTING)) + me->CastSpell(me, SPELL_SHADE_SOUL_CHANNEL, true); + + context.Repeat(); + }); + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + } + +private: + InstanceScript* instance; + TaskScheduler scheduler; +}; + class spell_shade_of_akama_shade_soul_channel : public AuraScript { PrepareAuraScript(spell_shade_of_akama_shade_soul_channel); @@ -562,6 +510,8 @@ void AddSC_boss_shade_of_akama() RegisterBlackTempleCreatureAI(boss_shade_of_akama); RegisterBlackTempleCreatureAI(npc_akama_shade); RegisterBlackTempleCreatureAI(npc_creature_generator_akama); + RegisterBlackTempleCreatureAI(npc_ashtongue_channeler); + RegisterBlackTempleCreatureAI(npc_ashtongue_sorcerer); RegisterSpellScript(spell_shade_of_akama_shade_soul_channel); RegisterSpellScript(spell_shade_of_akama_akama_soul_expel); } diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp index 247b61311..44d4cae96 100644 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp @@ -148,19 +148,15 @@ public: struct boss_illidari_councilAI : public BossAI { - boss_illidari_councilAI(Creature* creature) : BossAI(creature, DATA_ILLIDARI_COUNCIL) - { - } + boss_illidari_councilAI(Creature* creature) : BossAI(creature, DATA_ILLIDARI_COUNCIL) { } - ObjectGuid councilGUIDs[4]; - - void Reset() override + void EnterEvadeMode(EvadeReason why) override { - BossAI::Reset(); - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) member->AI()->EnterEvadeMode(); + + BossAI::EnterEvadeMode(why); } void AttackStart(Unit*) override { } @@ -171,15 +167,11 @@ public: if (!me->isActiveObject() && param == ACTION_START_ENCOUNTER) { me->setActive(true); - councilGUIDs[0] = instance->GetGuidData(NPC_GATHIOS_THE_SHATTERER); - councilGUIDs[1] = instance->GetGuidData(NPC_HIGH_NETHERMANCER_ZEREVOR); - councilGUIDs[2] = instance->GetGuidData(NPC_LADY_MALANDE); - councilGUIDs[3] = instance->GetGuidData(NPC_VERAS_DARKSHADOW); bool spoken = false; - for (uint8 i = 0; i < 4; ++i) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) { - if (Creature* member = ObjectAccessor::GetCreature(*me, councilGUIDs[i])) + if (Creature* member = instance->GetCreature(i)) { if (!spoken && (roll_chance_i(33) || i == 3)) { @@ -193,17 +185,15 @@ public: } else if (param == ACTION_ENRAGE) { - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) member->AI()->DoAction(ACTION_ENRAGE); } else if (param == ACTION_END_ENCOUNTER) { me->setActive(false); - Creature* member = nullptr; - for (uint8 i = 0; i < 4; ++i) - if ((member = ObjectAccessor::GetCreature(*me, councilGUIDs[i]))) + for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i) + if (Creature* member = instance->GetCreature(i)) if (member->IsAlive()) Unit::Kill(me, member); me->KillSelf(); @@ -217,7 +207,7 @@ public: if (!SelectTargetFromPlayerList(115.0f)) { - EnterEvadeMode(); + EnterEvadeMode(EVADE_REASON_NO_HOSTILES); return; } @@ -268,13 +258,13 @@ struct boss_illidari_council_memberAI : public ScriptedAI void JustDied(Unit*) override { Talk(SAY_COUNCIL_DEATH); - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_END_ENCOUNTER); } void JustEngagedWith(Unit* /*who*/) override { - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_START_ENCOUNTER); } }; @@ -296,14 +286,14 @@ public: Creature* SelectCouncilMember() { if (roll_chance_i(50)) - return ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_LADY_MALANDE)); + return instance->GetCreature(DATA_LADY_MALANDE); if (roll_chance_i(20)) - if (Creature* veras = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_VERAS_DARKSHADOW))) + if (Creature* veras = instance->GetCreature(DATA_VERAS_DARKSHADOW)) if (!veras->HasAura(SPELL_VANISH)) return veras; - return ObjectAccessor::GetCreature(*me, instance->GetGuidData(RAND(NPC_GATHIOS_THE_SHATTERER, NPC_HIGH_NETHERMANCER_ZEREVOR))); + return instance->GetCreature(RAND(DATA_GATHIOS_THE_SHATTERER, DATA_HIGH_NETHERMANCER_ZEREVOR)); } void JustEngagedWith(Unit* who) override @@ -555,7 +545,7 @@ public: break; case EVENT_SPELL_ENRAGE: DoResetThreatList(); - if (Creature* council = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ILLIDARI_COUNCIL))) + if (Creature* council = instance->GetCreature(DATA_ILLIDARI_COUNCIL)) council->GetAI()->DoAction(ACTION_ENRAGE); break; } diff --git a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp index ab447cdcb..175437358 100644 --- a/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/instance_black_temple.cpp @@ -36,12 +36,37 @@ DoorData const doorData[] = { GO_MOTHER_SHAHRAZ_DOOR, DATA_MOTHER_SHAHRAZ, DOOR_TYPE_PASSAGE }, { GO_COUNCIL_DOOR_1, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, { GO_COUNCIL_DOOR_2, DATA_ILLIDARI_COUNCIL, DOOR_TYPE_ROOM }, - { GO_ILLIDAN_GATE, DATA_AKAMA_FINISHED, DOOR_TYPE_PASSAGE }, + { GO_ILLIDAN_GATE, DATA_AKAMA_ILLIDAN, DOOR_TYPE_PASSAGE }, { GO_ILLIDAN_DOOR_L, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, { GO_ILLIDAN_DOOR_R, DATA_ILLIDAN_STORMRAGE, DOOR_TYPE_ROOM }, { 0, 0, DOOR_TYPE_ROOM } }; +ObjectData const creatureData[] = +{ + { NPC_HIGH_WARLORD_NAJENTUS, DATA_HIGH_WARLORD_NAJENTUS }, + { NPC_SUPREMUS, DATA_SUPREMUS }, + { NPC_SHADE_OF_AKAMA, DATA_SHADE_OF_AKAMA }, + { NPC_AKAMA_SHADE, DATA_AKAMA_SHADE }, + { NPC_TERON_GOREFIEND, DATA_TERON_GOREFIEND }, + { NPC_GURTOGG_BLOODBOIL, DATA_GURTOGG_BLOODBOIL }, + { NPC_RELIQUARY_OF_THE_LOST, DATA_RELIQUARY_OF_SOULS }, + { NPC_MOTHER_SHAHRAZ, DATA_MOTHER_SHAHRAZ }, + { NPC_ILLIDARI_COUNCIL, DATA_ILLIDARI_COUNCIL }, + { NPC_GATHIOS_THE_SHATTERER, DATA_GATHIOS_THE_SHATTERER }, + { NPC_HIGH_NETHERMANCER_ZEREVOR, DATA_HIGH_NETHERMANCER_ZEREVOR }, + { NPC_LADY_MALANDE, DATA_LADY_MALANDE }, + { NPC_VERAS_DARKSHADOW, DATA_VERAS_DARKSHADOW }, + { NPC_AKAMA_ILLIDAN, DATA_AKAMA_ILLIDAN }, + { NPC_ILLIDAN_STORMRAGE, DATA_ILLIDAN_STORMRAGE }, + { 0, 0 } +}; + +ObjectData const objectData[] = +{ + { 0, 0 } +}; + BossBoundaryData const boundaries = { { DATA_HIGH_WARLORD_NAJENTUS, new RectangleBoundary(394.0f, 479.4f, 707.8f, 859.1f) }, @@ -70,6 +95,7 @@ public: SetBossNumber(MAX_ENCOUNTERS); LoadDoorData(doorData); LoadBossBoundaries(boundaries); + LoadObjectData(creatureData, objectData); ashtongueGUIDs.clear(); } @@ -78,52 +104,19 @@ public: { switch (creature->GetEntry()) { - case NPC_SHADE_OF_AKAMA: - ShadeOfAkamaGUID = creature->GetGUID(); - break; - case NPC_AKAMA_SHADE: - AkamaShadeGUID = creature->GetGUID(); - break; - case NPC_TERON_GOREFIEND: - TeronGorefiendGUID = creature->GetGUID(); - break; - case NPC_RELIQUARY_OF_THE_LOST: - ReliquaryGUID = creature->GetGUID(); - break; - case NPC_GATHIOS_THE_SHATTERER: - GathiosTheShattererGUID = creature->GetGUID(); - break; - case NPC_HIGH_NETHERMANCER_ZEREVOR: - HighNethermancerZerevorGUID = creature->GetGUID(); - break; - case NPC_LADY_MALANDE: - LadyMalandeGUID = creature->GetGUID(); - break; - case NPC_VERAS_DARKSHADOW: - VerasDarkshadowGUID = creature->GetGUID(); - break; - case NPC_ILLIDARI_COUNCIL: - IllidariCouncilGUID = creature->GetGUID(); - break; - case NPC_AKAMA: - AkamaGUID = creature->GetGUID(); - break; - case NPC_ILLIDAN_STORMRAGE: - IllidanStormrageGUID = creature->GetGUID(); - break; case NPC_VENGEFUL_SPIRIT: case NPC_SHADOWY_CONSTRUCT: - if (Creature* teron = instance->GetCreature(TeronGorefiendGUID)) + if (Creature* teron = GetCreature(DATA_TERON_GOREFIEND)) teron->AI()->JustSummoned(creature); break; case NPC_ENSLAVED_SOUL: - if (Creature* reliquary = instance->GetCreature(ReliquaryGUID)) + if (Creature* reliquary = GetCreature(DATA_RELIQUARY_OF_SOULS)) reliquary->AI()->JustSummoned(creature); break; case NPC_PARASITIC_SHADOWFIEND: case NPC_BLADE_OF_AZZINOTH: case NPC_FLAME_OF_AZZINOTH: - if (Creature* illidan = instance->GetCreature(IllidanStormrageGUID)) + if (Creature* illidan = GetCreature(DATA_ILLIDAN_STORMRAGE)) illidan->AI()->JustSummoned(creature); break; case NPC_ANGERED_SOUL_FRAGMENT: @@ -131,85 +124,38 @@ public: case NPC_SUFFERING_SOUL_FRAGMENT: creature->SetCorpseDelay(5); break; + case NPC_ASHTONGUE_BATTLELORD: + case NPC_ASHTONGUE_MYSTIC: + case NPC_ASHTONGUE_STORMCALLER: + case NPC_ASHTONGUE_PRIMALIST: + case NPC_ASHTONGUE_FERAL_SPIRIT: + case NPC_ASHTONGUE_STALKER: + case NPC_STORM_FURY: + if (GetBossState(DATA_SHADE_OF_AKAMA) == DONE) + creature->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); + else + ashtongueGUIDs.insert(creature->GetGUID()); + break; + default: + break; } - if (creature->GetName().find("Ashtongue") != std::string::npos || creature->GetEntry() == NPC_STORM_FURY) - { - ashtongueGUIDs.push_back(creature->GetGUID()); - if (GetBossState(DATA_SHADE_OF_AKAMA) == DONE) - creature->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); - } + InstanceScript::OnCreatureCreate(creature); } void OnGameObjectCreate(GameObject* go) override { - switch (go->GetEntry()) + // If created after Illidari Council is done, then skip Akama's event. Used for crashes/reset + if (go->GetEntry() == GO_ILLIDAN_GATE) { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - case GO_ILLIDAN_GATE: - case GO_ILLIDAN_DOOR_R: - case GO_ILLIDAN_DOOR_L: - AddDoor(go); - break; - } - } - - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_NAJENTUS_GATE: - case GO_SUPREMUS_GATE: - case GO_SHADE_OF_AKAMA_DOOR: - case GO_TERON_DOOR_1: - case GO_TERON_DOOR_2: - case GO_GURTOGG_DOOR: - case GO_TEMPLE_DOOR: - case GO_MOTHER_SHAHRAZ_DOOR: - case GO_COUNCIL_DOOR_1: - case GO_COUNCIL_DOOR_2: - case GO_ILLIDAN_GATE: - case GO_ILLIDAN_DOOR_R: - case GO_ILLIDAN_DOOR_L: - RemoveDoor(go); - break; - } - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case NPC_SHADE_OF_AKAMA: - return ShadeOfAkamaGUID; - case NPC_AKAMA_SHADE: - return AkamaShadeGUID; - case NPC_GATHIOS_THE_SHATTERER: - return GathiosTheShattererGUID; - case NPC_HIGH_NETHERMANCER_ZEREVOR: - return HighNethermancerZerevorGUID; - case NPC_LADY_MALANDE: - return LadyMalandeGUID; - case NPC_VERAS_DARKSHADOW: - return VerasDarkshadowGUID; - case NPC_ILLIDARI_COUNCIL: - return IllidariCouncilGUID; - case NPC_AKAMA: - return AkamaGUID; - case NPC_ILLIDAN_STORMRAGE: - return IllidanStormrageGUID; + if (GetBossState(DATA_ILLIDARI_COUNCIL) == DONE) + { + SetBossState(DATA_AKAMA_ILLIDAN, DONE); + HandleGameObject(ObjectGuid::Empty, true, go); + } } - return ObjectGuid::Empty; + InstanceScript::OnGameObjectCreate(go); } bool SetBossState(uint32 type, EncounterState state) override @@ -225,26 +171,15 @@ public: } else if (type == DATA_ILLIDARI_COUNCIL && state == DONE) { - if (Creature* akama = instance->GetCreature(AkamaGUID)) - akama->SetVisible(true); + if (Creature* akama = GetCreature(DATA_AKAMA_ILLIDAN)) + akama->AI()->DoAction(0); } return true; } protected: - ObjectGuid ShadeOfAkamaGUID; - ObjectGuid AkamaShadeGUID; - ObjectGuid TeronGorefiendGUID; - ObjectGuid ReliquaryGUID; - GuidList ashtongueGUIDs; - ObjectGuid GathiosTheShattererGUID; - ObjectGuid HighNethermancerZerevorGUID; - ObjectGuid LadyMalandeGUID; - ObjectGuid VerasDarkshadowGUID; - ObjectGuid IllidariCouncilGUID; - ObjectGuid AkamaGUID; - ObjectGuid IllidanStormrageGUID; + GuidSet ashtongueGUIDs; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index 21594b256..198abc879 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -102,15 +102,6 @@ struct boss_alar : public BossAI }); } - void JustReachedHome() override - { - BossAI::JustReachedHome(); - if (me->IsEngaged()) - { - ConstructWaypointsAndMove(); - } - } - void Reset() override { BossAI::Reset(); @@ -129,6 +120,15 @@ struct boss_alar : public BossAI ConstructWaypointsAndMove(); } + void JustReachedHome() override + { + BossAI::JustReachedHome(); + if (me->IsEngaged()) + { + ConstructWaypointsAndMove(); + } + } + void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); @@ -158,6 +158,29 @@ struct boss_alar : public BossAI ScheduleMainSpellAttack(0s); } + bool CanAIAttack(Unit const* victim) const override + { + if (me->isMoving()) + return true; + + return me->IsWithinMeleeRange(victim); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (why == EVADE_REASON_BOUNDARY) + { + BossAI::EnterEvadeMode(why); + } + else + { + if (me->GetThreatMgr().GetThreatList().empty()) + { + BossAI::EnterEvadeMode(why); + } + } + } + void JustDied(Unit* killer) override { BossAI::JustDied(killer); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 77aad57b1..a9ba7d96e 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -498,8 +498,12 @@ struct boss_kaelthas : public BossAI { summons.DespawnEntry(NPC_NETHER_VAPOR); scheduler.CancelGroup(GROUP_NETHER_BEAM); - me->SetTarget(me->GetVictim()->GetGUID()); - me->GetMotionMaster()->MoveChase(me->GetVictim()); + + if (Unit* victim = me->GetVictim()) + { + me->SetTarget(victim->GetGUID()); + me->GetMotionMaster()->MoveChase(victim); + } }); me->SetTarget(); me->GetMotionMaster()->Clear(); @@ -803,9 +807,9 @@ struct npc_lord_sanguinar : public ScriptedAI { Talk(SAY_SANGUINAR_AGGRO); } - ScheduleTimedEvent(0s, [&]{ + ScheduleTimedEvent(6s, 20s, [&]{ DoCastSelf(SPELL_BELLOWING_ROAR); - }, 15s); + }, 30s, 40s); } void JustDied(Unit* /*killer*/) override diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp index 19c7feb76..a1d94f89f 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp @@ -95,7 +95,7 @@ struct boss_void_reaver : public BossAI context.Repeat(12100ms, 15800ms); }).Schedule(3450ms, GROUP_ARCANE_ORB, [this](TaskContext context) { - if (!DoCastRandomTarget(SPELL_ARCANE_ORB, 0, -18.0f)) + if (DoCastRandomTarget(SPELL_ARCANE_ORB, 0, -20.0f) != SPELL_CAST_OK) { DoCastRandomTarget(SPELL_ARCANE_ORB, 0, 18.0f); }