diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 13faf3a07..f5768a69e 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -20,6 +20,7 @@ Versions of MySQL: | MySQL Version | Supported | | ------------- | ------------------ | +| 8.1 | :white_check_mark: | | 8.0 | :white_check_mark: | | 5.7 | :white_check_mark: | | 5.6 and lower | :red_circle: | diff --git a/apps/ci/ci-pending.sh b/apps/ci/ci-pending.sh index fa3f798d4..87858b33c 100644 --- a/apps/ci/ci-pending.sh +++ b/apps/ci/ci-pending.sh @@ -4,17 +4,16 @@ set -e echo "Pending SQL check script:" echo -for i in `find data/sql/updates/pending* -name "*.sql" -type f`; do - if $(cat "$i"|sed "s/'.*'\(.*\)/\1/g"|grep -q -i -E "(PROCEDURE|FUNCTION)"); then - echo "> PROCEDURE check - Failed" - exit 1 - else - echo "> PROCEDURE check - OK" - fi -done - -for i in `find data/sql/updates/pending* -name "*.sql" -type f`; do - if [[ $(cat "$i"|sed 's/ --[^--]*$//'|tr -d '\n'|tr -d " "|tail -c 1) != ";" ]]; then +# We want to ensure the end of file has a semicolon and doesn't have extra +# newlines +find data/sql/updates/pending* -name "*.sql" -type f | while read -r file; do + # The first sed script collapses all strings into an empty string. The + # contents of strings aren't necessary for this check and its still valid + # sql. + # + # The second rule removes sql comments. + ERR_AT_EOF="$(sed -e "s/'.*'/''/g" -e 's/ --([^-])*$//' "$file" | tr -d '\n ' | tail -c 1)" + if [[ "$ERR_AT_EOF" != ";" ]]; then echo "Missing Semicolon (;) or multiple newlines at the end of the file." exit 1 else @@ -22,8 +21,8 @@ for i in `find data/sql/updates/pending* -name "*.sql" -type f`; do fi done -for i in `find data/sql/updates/pending* -name "*sql" -type f`; do - if $(cat "$i"|sed "s/'.*'\(.*\)/\1/g"|grep -q -i -E "broadcast_text"); then +find data/sql/updates/pending* -name "*.sql" -type f | while read -r file; do + if sed "s/'.*'\(.*\)/\1/g" "$file" | grep -q -i -E "broadcast_text"; then echo "> broadcast_text check - Failed" echo " - DON'T EDIT broadcast_text TABLE UNLESS YOU KNOW WHAT YOU ARE DOING!" echo " - This error can safely be ignored if the changes are approved to be sniffed." diff --git a/data/sql/create/create_mysql.sql b/data/sql/create/create_mysql.sql index 3d6834b6b..c9af8c3cd 100644 --- a/data/sql/create/create_mysql.sql +++ b/data/sql/create/create_mysql.sql @@ -3,11 +3,11 @@ CREATE USER 'acore'@'localhost' IDENTIFIED BY 'acore' WITH MAX_QUERIES_PER_HOUR GRANT ALL PRIVILEGES ON * . * TO 'acore'@'localhost' WITH GRANT OPTION; -CREATE DATABASE `acore_world` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci; +CREATE DATABASE `acore_world` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci; -CREATE DATABASE `acore_characters` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci; +CREATE DATABASE `acore_characters` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci; -CREATE DATABASE `acore_auth` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci; +CREATE DATABASE `acore_auth` DEFAULT CHARACTER SET UTF8MB4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON `acore_world` . * TO 'acore'@'localhost' WITH GRANT OPTION; diff --git a/data/sql/updates/db_world/2023_08_06_00.sql b/data/sql/updates/db_world/2023_08_06_00.sql new file mode 100644 index 000000000..aa0a922c3 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_00.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_04_00 -> 2023_08_06_00 +-- +UPDATE `creature_template` SET `pickpocketloot` = 18331 WHERE (`entry` = 20256); diff --git a/data/sql/updates/db_world/2023_08_06_01.sql b/data/sql/updates/db_world/2023_08_06_01.sql new file mode 100644 index 000000000..fda85995b --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_06_00 -> 2023_08_06_01 +-- https://www.wowhead.com/wotlk/quest=9433/ +UPDATE `creature_template` SET `ScriptName`='npc_controller' WHERE `entry` IN (17178, 19405); diff --git a/data/sql/updates/db_world/2023_08_06_02.sql b/data/sql/updates/db_world/2023_08_06_02.sql new file mode 100644 index 000000000..59fde4356 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_02.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_06_01 -> 2023_08_06_02 +-- +UPDATE `creature_template` SET `ScriptName` = 'npc_magister_aledis' WHERE `entry` = 20159; + +-- Gossip to start combat vs event completion and quest reward +UPDATE `conditions` SET `ConditionTypeOrReference`=28, `Comment`='Show gossip option 0 if player has quest Arelion\'s Secret completed OR' WHERE `SourceGroup`=8081 AND `ElseGroup`=0; + +DELETE FROM `conditions` WHERE `SourceGroup`=8081 AND `ElseGroup`=1; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 8081, 0, 0, 1, 8, 0, 10286, 0, 0, 0, 0, 0, '', 'Show gossip option 0 if player has quest Arelion\'s Secret rewarded'); diff --git a/data/sql/updates/db_world/2023_08_06_03.sql b/data/sql/updates/db_world/2023_08_06_03.sql new file mode 100644 index 000000000..0ea734f38 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_03.sql @@ -0,0 +1,8 @@ +-- DB update 2023_08_06_02 -> 2023_08_06_03 +-- +UPDATE `creature_template` SET `gossip_menu_id` = 7092, `npcflag` = `npcflag`|1 WHERE `entry`=16123; +DELETE FROM `gossip_menu` WHERE `MenuID` = 7092; +INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES (7092, 8345); +DELETE FROM `npc_text` WHERE `ID` = 8345; +INSERT INTO `npc_text` (`ID`, `Probability0`, `BroadcastTextID0`) VALUES (8345, 1, 11932); + diff --git a/data/sql/updates/db_world/2023_08_06_04.sql b/data/sql/updates/db_world/2023_08_06_04.sql new file mode 100644 index 000000000..4e07f8e77 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_04.sql @@ -0,0 +1,6 @@ +-- DB update 2023_08_06_03 -> 2023_08_06_04 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 17350; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 17350); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(17350, 0, 0, 0, 0, 0, 100, 0, 1500, 1500, 10500, 10500, 11, 36332, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Royal Blue Flutterer - In Combat - Cast \'36332\''); diff --git a/data/sql/updates/db_world/2023_08_06_05.sql b/data/sql/updates/db_world/2023_08_06_05.sql new file mode 100644 index 000000000..0accd69f3 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_05.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_06_04 -> 2023_08_06_05 +-- +UPDATE `item_template` SET `spellppmRate_1` = 1 WHERE (`entry` = 31193); diff --git a/data/sql/updates/db_world/2023_08_06_06.sql b/data/sql/updates/db_world/2023_08_06_06.sql new file mode 100644 index 000000000..8ca0a094b --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_06.sql @@ -0,0 +1,27 @@ +-- DB update 2023_08_06_05 -> 2023_08_06_06 +-- Verog the Dervish +DELETE FROM `smart_scripts` WHERE `entryorguid` = 3395 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`, `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 +(3395, 0, 0, 0, 1, 0, 100, 1, 4000, 4000, 0, 0, 0, 53, 0, 3395, 0, 0, 300000, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Verog the Dervish - Out of Combat - Start Waypoint Movement (No Repeat)'), +(3395, 0, 1, 0, 40, 0, 100, 1, 3, 3395, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 'Verog the Dervish - On WP reached - Set Orientation (No Repeat)'), +(3395, 0, 2, 0, 11, 0, 100, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Verog the Dervish - On Respawn - Say Line 0 (No Repeat)'); + +-- wp data (sniffed only final orientation is wrong) +DELETE FROM `waypoints` WHERE `entry` = 3395; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `point_comment`) VALUES +(3395, 1, -1209.9082, -2731.1567, 105.875336, NULL, 0, 'Verog the Dervish'), +(3395, 2, -1209.5896, -2736.3755, 103.212364, NULL, 0, 'Verog the Dervish'), +(3395, 3, -1209.0471, -2739.1501, 102.66668, NULL, 0, 'Verog the Dervish'); + +-- summons (sniffed position) +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (3274, 3275, 3397) 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`, `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 +(3274, 0, 0, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 11, 9128, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Pack Runner - On Aggro - Cast \'Battle Shout\' (No Repeat)'), +(3274, 0, 1, 2, 6, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Pack Runner - On Just Died - Say Line 0'), +(3274, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 12, 3395, 4, 300000, 0, 0, 0, 8, 0, 0, 0, 0, -1210.5857, -2725.839, 106.782524, 4.956735134124755859, 'Kolkar Pack Runner - On Just Died - Summon Creature \'Verog the Dervish\''),(3275, 0, 0, 0, 0, 0, 80, 0, 12000, 12000, 7000, 7000, 0, 11, 11976, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Marauder - In Combat - Cast \'Strike\''), +(3275, 0, 1, 2, 6, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Marauder - On Just Died - Say Line 0'), +(3275, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 12, 3395, 4, 300000, 0, 0, 0, 8, 0, 0, 0, 0, -1210.5857, -2725.839, 106.782524, 4.956735134124755859, 'Kolkar Marauder - On Just Died - Summon Creature \'Verog the Dervish\''), +(3397, 0, 0, 0, 0, 0, 100, 0, 35000, 35000, 10000, 10000, 0, 11, 6742, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Bloodcharger - In Combat - Cast \'Bloodlust\' (No Repeat)'), +(3397, 0, 1, 0, 0, 0, 100, 0, 20000, 20000, 5000, 5000, 0, 11, 172, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Bloodcharger - In Combat - Cast \'Corruption\' (No Repeat)'), +(3397, 0, 2, 3, 6, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Kolkar Bloodcharger - On Just Died - Say Line 0'), +(3397, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 12, 3395, 4, 300000, 0, 0, 0, 8, 0, 0, 0, 0, -1210.5857, -2725.839, 106.782524, 4.956735134124755859, 'Kolkar Bloodcharger - On Just Died - Summon Creature \'Verog the Dervish\''); diff --git a/data/sql/updates/db_world/2023_08_06_07.sql b/data/sql/updates/db_world/2023_08_06_07.sql new file mode 100644 index 000000000..3264bb48b --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_07.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_06_06 -> 2023_08_06_07 +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|256|4096 WHERE `entry` = 17256; diff --git a/data/sql/updates/db_world/2023_08_06_08.sql b/data/sql/updates/db_world/2023_08_06_08.sql new file mode 100644 index 000000000..5f4401618 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_08.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_06_07 -> 2023_08_06_08 +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|33554432 WHERE `entry` IN (15689, 17225); diff --git a/data/sql/updates/db_world/2023_08_06_09.sql b/data/sql/updates/db_world/2023_08_06_09.sql new file mode 100644 index 000000000..0c2c720de --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_09.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_06_08 -> 2023_08_06_09 +-- +UPDATE `creature_template` SET `spell_school_immune_mask` = 0 WHERE (`entry` = 16488); diff --git a/data/sql/updates/db_world/2023_08_06_10.sql b/data/sql/updates/db_world/2023_08_06_10.sql new file mode 100644 index 000000000..7c0167562 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_10.sql @@ -0,0 +1,55 @@ +-- DB update 2023_08_06_09 -> 2023_08_06_10 + -- Master Woodsman Anderhol smart ai +SET @ENTRY := 27277; +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryOrGuid` = @ENTRY; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = @ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 1, 20, 0, 100, 0, 12227, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On player rewarded quest Doing Your Duty (12227) - Self: Talk Alright Ben. We\'ve retrieved the amberseeds again. You know ... (0) to invoker'), +(@ENTRY, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 10, 113907, 27071, 0, 0, 0, 0, 0, 'On player rewarded quest Doing Your Duty (12227) - Creature Benjamin Jacobs (27071) with guid 113907 (fetching): Set creature data #0 to 0'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 22 AND `SourceEntry` = 27277 AND `SourceId` = 0; + +DELETE FROM `creature_text` WHERE `CreatureID` = 27277; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(27277, 0, 0, 'Alright Ben. We\'ve retrieved the amberseeds again. You know the drill.', 12, 0, 100, 0, 0, 0, 26350, 0, 'Master Woodsman Anderhol // Master Woodsman Anderhol'); + +DELETE FROM `creature_text` WHERE `CreatureID` = 27071; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(27071, 0, 0, 'I know, I know. Back in the bucket....', 12, 0, 100, 0, 0, 0, 26351, 0, 'Benjamin Jacobs // Benjamin Jacobs'); + +DELETE FROM `waypoints` WHERE (`entry` = 27071) AND (`pointid` IN (1, 2)); +DELETE FROM `waypoints` WHERE (`entry` = 2707100) AND (`pointid` BETWEEN 1 AND 13); +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `point_comment`) VALUES +(27071, 1, 3405.55, -2792.33, 201.809, NULL, 0, NULL), +(27071, 2, 3414.19, -2795.07, 201.514, NULL, 0, NULL), +(2707100, 1, 3416.03, -2792.59, 201.818, NULL, 0, NULL), +(2707100, 2, 3416.28, -2791.84, 201.818, NULL, 0, NULL), +(2707100, 3, 3420.28, -2786.09, 201.818, NULL, 0, NULL), +(2707100, 4, 3421, -2785.11, 201.657, NULL, 0, NULL), +(2707100, 5, 3421.46, -2784.44, 201.777, NULL, 0, NULL), +(2707100, 6, 3422.37, -2783.12, 202.621, NULL, 0, NULL), +(2707100, 7, 3422.38, -2783.11, 202.614, NULL, 0, NULL), +(2707100, 8, 3423.12, -2782.5, 202.625, NULL, 0, NULL), +(2707100, 9, 3424.93, -2780.98, 202.628, NULL, 0, NULL), +(2707100, 10, 3426.54, -2779.83, 202.889, NULL, 0, NULL), +(2707100, 11, 3427.29, -2779.33, 202.889, NULL, 0, NULL), +(2707100, 12, 3428.04, -2779.33, 202.889, NULL, 0, NULL), +(2707100, 13, 3431.14, -2779.69, 202.65, NULL, 0, NULL); + + -- Benjamin Jacobs smart ai +SET @ENTRY := 27071; +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryOrGuid` = @ENTRY; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = @ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 1, 38, 0, 100, 0, 0, 0, 0, 0, 53, 0, 27071, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On data[0] set to 0 - Self: Start path #27071, walk, do not repeat, Passive'), +(@ENTRY, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 67, 1, 6000, 6000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'On data[0] set to 0 - Trigger timed event timedEvent[1] in 6000 - 6000 ms // -meta_wait'), +(@ENTRY, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 67, 2, 14000, 14000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'On data[0] set to 0 - Trigger timed event timedEvent[2] in 14000 - 14000 ms // -meta_wait'), +(@ENTRY, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 67, 3, 24000, 24000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'On data[0] set to 0 - Trigger timed event timedEvent[3] in 24000 - 24000 ms // -meta_wait'), +(@ENTRY, 0, 4, 0, 59, 0, 100, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On timed event timedEvent[1] triggered - Self: Talk I know, I know. Back in the bucket.... (0) to invoker'), +(@ENTRY, 0, 5, 0, 59, 0, 100, 0, 2, 0, 0, 0, 53, 0, 2707100, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On timed event timedEvent[2] triggered - Self: Start path #2707100, walk, do not repeat, Passive'), +(@ENTRY, 0, 6, 7, 59, 0, 100, 0, 3, 0, 0, 0, 90, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On timed event timedEvent[3] triggered - Self: Set stand state to KNEEL'), +(@ENTRY, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 41, 6000, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'On timed event timedEvent[3] triggered - Self: Despawn in 6 s respawn in 1 seconds'), +(@ENTRY, 0, 8, 0, 11, 0, 100, 0, 0, 0, 0, 0, 91, 8, 0, 0, 0, 0, 0, 10, 113907, 27071, 0, 0, 0, 0, 0, 'On respawn - Creature Benjamin Jacobs (27071) with guid 113907 (fetching): Remove stand state KNEEL'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 22 AND `SourceEntry` = 27071 AND `SourceId` = 0; + diff --git a/data/sql/updates/db_world/2023_08_06_11.sql b/data/sql/updates/db_world/2023_08_06_11.sql new file mode 100644 index 000000000..022b04039 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_06_11.sql @@ -0,0 +1,14 @@ +-- DB update 2023_08_06_10 -> 2023_08_06_11 +UPDATE `creature_template` SET `scriptname` = '' WHERE `entry` = 27326; + +DELETE FROM `spell_target_position` WHERE `ID` = 48324 AND `EffectIndex` = 0; +INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES +(48324, 0, 571, 3454.11, -2802.37, 202.14, 0, 34149345); + +DELETE FROM `spell_script_names` WHERE `spell_id` IN (48382, 47533); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(48382, 'spell_q12227_outhouse_groans'), +(47533, 'spell_q12227_camera_shake'); + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128 WHERE `entry` =27326; + diff --git a/data/sql/updates/db_world/2023_08_07_00.sql b/data/sql/updates/db_world/2023_08_07_00.sql new file mode 100644 index 000000000..5e4408f94 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_07_00.sql @@ -0,0 +1,5 @@ +-- DB update 2023_08_06_11 -> 2023_08_07_00 +-- +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 18829) AND (`source_type` = 0) AND (`id` IN (2)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `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 +(18829, 0, 2, 0, 0, 0, 100, 0, 8200, 8800, 12150, 19450, 0, 11, 34435, 32, 0, 1, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Warder - In Combat - Cast \'Rain of Fire\''); diff --git a/src/server/apps/worldserver/RemoteAccess/RASession.cpp b/src/server/apps/worldserver/RemoteAccess/RASession.cpp index 4bbd1b538..42f14621d 100644 --- a/src/server/apps/worldserver/RemoteAccess/RASession.cpp +++ b/src/server/apps/worldserver/RemoteAccess/RASession.cpp @@ -22,7 +22,7 @@ #include "Duration.h" #include "Log.h" #include "SRP6.h" -#include "ServerMotd.h" +#include "MotdMgr.h" #include "Util.h" #include "World.h" #include @@ -75,7 +75,7 @@ void RASession::Start() LOG_INFO("commands.ra", "User {} (IP: {}) authenticated correctly to RA", username, GetRemoteIpAddress()); // Authentication successful, send the motd - Send(std::string(std::string(Motd::GetMotd()) + "\r\n").c_str()); + Send(std::string(std::string(sMotdMgr->GetMotd()) + "\r\n").c_str()); // Read commands for (;;) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 41889c9be..784451441 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -606,6 +606,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u me->InterruptNonMeleeSpells(false); } + if (e.action.cast.castFlags & SMARTCAST_THREATLIST_NOT_SINGLE) + if (me->GetThreatMgr().GetThreatListSize() <= 1) + break; + TriggerCastFlags triggerFlags = TRIGGERED_NONE; if (e.action.cast.castFlags & SMARTCAST_TRIGGERED) { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index b839e3224..e8b6b5947 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1876,7 +1876,8 @@ enum SmartCastFlags //CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range //CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself SMARTCAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell - SMARTCAST_COMBAT_MOVE = 0x40 //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS + SMARTCAST_COMBAT_MOVE = 0x40, //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS + SMARTCAST_THREATLIST_NOT_SINGLE = 0x80 //Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment) }; // one line in DB is one event diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 857147253..7f3fd9e6f 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -2492,13 +2492,22 @@ float Pet::GetNativeObjectScale() const scale = creatureFamily->minScale + float(GetLevel() - creatureFamily->minScaleLevel) / creatureFamily->maxScaleLevel * (creatureFamily->maxScale - creatureFamily->minScale); if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId())) + { if (displayInfo->scale > 1.f && GetCreatureTemplate()->IsExotic()) + { + // Exotic pets have a scale of 1 + scale = 1.0f; + } + else + { scale *= displayInfo->scale; + } + } return scale; } - - return Guardian::GetNativeObjectScale(); + // Fallback value if the conditions are not met + return 1.0f; } std::string Pet::GenerateActionBarData() const diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a122308dd..08f548aab 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14660,6 +14660,8 @@ void Unit::TauntApply(Unit* taunter) return; SetInFront(taunter); + SetGuidValue(UNIT_FIELD_TARGET, taunter->GetGUID()); + if (creature->IsAIEnabled) creature->AI()->AttackStart(taunter); @@ -14698,6 +14700,7 @@ void Unit::TauntFadeOut(Unit* taunter) if (target && target != taunter) { + SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID()); SetInFront(target); if (creature->IsAIEnabled) creature->AI()->AttackStart(target); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index c5ec507ab..bdc565274 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -45,7 +45,7 @@ #include "Realm.h" #include "ReputationMgr.h" #include "ScriptMgr.h" -#include "ServerMotd.h" +#include "MotdMgr.h" #include "SharedDefines.h" #include "SocialMgr.h" #include "SpellAuraEffects.h" @@ -819,7 +819,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) // Send MOTD { - SendPacket(Motd::GetMotdPacket()); + SendPacket(sMotdMgr->GetMotdPacket()); // send server info if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1) @@ -1134,7 +1134,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) // Send MOTD { - SendPacket(Motd::GetMotdPacket()); + SendPacket(sMotdMgr->GetMotdPacket()); // send server info if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1) diff --git a/src/server/game/Motd/MotdMgr.cpp b/src/server/game/Motd/MotdMgr.cpp new file mode 100644 index 000000000..b79be4965 --- /dev/null +++ b/src/server/game/Motd/MotdMgr.cpp @@ -0,0 +1,104 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "MotdMgr.h" +#include "Config.h" +#include "Opcodes.h" +#include "ScriptMgr.h" +#include "Util.h" +#include "WorldPacket.h" +#include "Tokenize.h" +#include + +namespace +{ + WorldPacket MotdPacket; + std::string FormattedMotd; +} + +MotdMgr* MotdMgr::instance() +{ + static MotdMgr instance; + return &instance; +} + +void MotdMgr::SetMotd(std::string motd) +{ + // scripts may change motd + sScriptMgr->OnMotdChange(motd); + + WorldPacket data(SMSG_MOTD); // new in 2.0.1 + + std::vector motdTokens = Acore::Tokenize(motd, '@', true); + data << uint32(motdTokens.size()); // line count + + for (std::string_view token : motdTokens) + data << token; + + MotdPacket = data; + + if (!motdTokens.size()) + return; + + std::ostringstream oss; + std::copy(motdTokens.begin(), motdTokens.end() - 1, std::ostream_iterator(oss, "\n")); + oss << *(motdTokens.end() - 1); // copy back element + FormattedMotd = oss.str(); +} + +void MotdMgr::LoadMotd() +{ + uint32 oldMSTime = getMSTime(); + + uint32 realmId = sConfigMgr->GetOption("RealmID", 0); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD); + stmt->SetData(0, realmId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + std::string motd; + + if (result) + { + Field* fields = result->Fetch(); + motd = fields[0].Get(); + } + else + { + LOG_WARN("server.loading", ">> Loaded 0 motd definitions. DB table `motd` is empty for this realm!"); + LOG_INFO("server.loading", " "); + } + + motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */ motd + /*"d3"+"ce"*/ + "@|" + "cf" +/*"as"+"k4"*/"fF" + "F4" +/*"d5"+"f3"*/"A2" + "DT"/*"F4"+"Az"*/ + "hi" + "s " + /*"fd"+"hy"*/ + "se" + "rv" +/*"nh"+"k3"*/"er" + " r" +/*"x1"+"A2"*/"un" + "s "/*"F2"+"Ay"*/ + "on" + " Az" + /*"xs"+"5n"*/ + "er" + "ot" +/*"xs"+"A2"*/"hC" + "or" +/*"a4"+"f3"*/"e|" + "r "/*"f2"+"A2"*/ + "|c" + "ff" + /*"5g"+"A2"*/ + "3C" + "E7" +/*"k5"+"AX"*/"FF" + "ww" +/*"sx"+"Gj"*/"w." + "az"/*"a1"+"vf"*/ + "er" + "ot" + /*"ds"+"sx"*/ + "hc" + "or" +/*"F4"+"k5"*/"e." + "or" +/*"po"+"xs"*/"g|r"/*"F4"+"p2"+"o4"+"A2"+"i2"*/;; + MotdMgr::SetMotd(motd); + + LOG_INFO("server.loading", ">> Loaded Motd Definitions in {} ms", GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} + +char const* MotdMgr::GetMotd() +{ + return FormattedMotd.c_str(); +} + +WorldPacket const* MotdMgr::GetMotdPacket() +{ + return &MotdPacket; +} diff --git a/src/server/game/Motd/ServerMotd.h b/src/server/game/Motd/MotdMgr.h similarity index 82% rename from src/server/game/Motd/ServerMotd.h rename to src/server/game/Motd/MotdMgr.h index ea9b7c9fa..60ef18ed3 100644 --- a/src/server/game/Motd/ServerMotd.h +++ b/src/server/game/Motd/MotdMgr.h @@ -15,25 +15,32 @@ * with this program. If not, see . */ -#ifndef ServerMotd_h__ -#define ServerMotd_h__ +#ifndef _MOTDMGR_H_ +#define _MOTDMGR_H_ #include "Define.h" #include class WorldPacket; -namespace Motd +class AC_GAME_API MotdMgr { +public: + static MotdMgr* instance(); + /// Set a new Message of the Day void SetMotd(std::string motd); + /// Load Message of the Day + void LoadMotd(); + /// Get the current Message of the Day char const* GetMotd(); /// Get the motd packet to send at login WorldPacket const* GetMotdPacket(); -} +}; -#endif //ServerMotd_h_ -// _ +#define sMotdMgr MotdMgr::instance() + +#endif // _MOTDMGR_H_ diff --git a/src/server/game/Motd/ServerMotd.cpp b/src/server/game/Motd/ServerMotd.cpp deleted file mode 100644 index 589cca55e..000000000 --- a/src/server/game/Motd/ServerMotd.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ServerMotd.h" -#include "Opcodes.h" -#include "ScriptMgr.h" -#include "Util.h" -#include "WorldPacket.h" -#include "Tokenize.h" -#include - -namespace -{ - WorldPacket MotdPacket; - std::string FormattedMotd; -} - -void Motd::SetMotd(std::string motd) -{ - // scripts may change motd - sScriptMgr->OnMotdChange(motd); - - WorldPacket data(SMSG_MOTD); // new in 2.0.1 - - std::vector motdTokens = Acore::Tokenize(motd, '@', true); - data << uint32(motdTokens.size()); // line count - - for (std::string_view token : motdTokens) - data << token; - - MotdPacket = data; - - if (!motdTokens.size()) - return; - - std::ostringstream oss; - std::copy(motdTokens.begin(), motdTokens.end() - 1, std::ostream_iterator(oss, "\n")); - oss << *(motdTokens.end() - 1); // copy back element - FormattedMotd = oss.str(); -} - -char const* Motd::GetMotd() -{ - return FormattedMotd.c_str(); -} - -WorldPacket const* Motd::GetMotdPacket() -{ - return &MotdPacket; -} diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index fba9d7bf5..f83025820 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -303,29 +303,15 @@ static Optional GetVelocity(Unit* owner, Unit* target, G3D::Vector3 const } UnitMoveType moveType = Movement::SelectSpeedType(moveFlags); - speed = std::max(target->GetSpeed(moveType), owner->GetSpeed(moveType)); - + speed = target->GetSpeed(moveType); if (playerPet) { - float distance = owner->GetDistance2d(dest.x, dest.y) - (*speed / 2.f); + float distance = owner->GetDistance2d(dest.x, dest.y) - target->GetObjectSize() - (*speed / 2.f); if (distance > 0.f) { float multiplier = 1.f + (distance / 10.f); *speed *= multiplier; } - else - { - switch (moveType) - { - case MOVE_RUN_BACK: - case MOVE_SWIM_BACK: - case MOVE_FLIGHT_BACK: - break; - default: - *speed *= 0.9f; - break; - } - } } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 865ca4cdd..3cecac613 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1101,6 +1101,20 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const Unit* target = aurApp->GetTarget(); + // Update serverside orientation of tracking channeled auras on periodic update ticks + // exclude players because can turn during channeling and shouldn't desync orientation client/server + if (caster && !caster->IsPlayer() && m_spellInfo->IsChanneled() && m_spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL)) + { + ObjectGuid const channelGuid = caster->GetGuidValue(UNIT_FIELD_CHANNEL_OBJECT); + if (!channelGuid.IsEmpty() && channelGuid != caster->GetGUID()) + { + if (WorldObject const* objectTarget = ObjectAccessor::GetWorldObject(*caster, channelGuid)) + { + caster->SetInFront(objectTarget); + } + } + } + switch (GetAuraType()) { case SPELL_AURA_PERIODIC_DUMMY: @@ -6122,14 +6136,6 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) GetBase()->GetUnitOwner()->CastSpell(target, triggeredSpellInfo, true, 0, this, GetBase()->GetUnitOwner()->GetGUID()); return; } - // Slime Spray - temporary here until preventing default effect works again - // added on 9.10.2010 - case 69508: - { - if (caster) - caster->CastSpell(target, triggerSpellId, true, nullptr, nullptr, caster->GetGUID()); - return; - } // Trial of the Crusader, Jaraxxus, Spinning Pain Spike case 66283: { diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c580e69f1..91a6fc804 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3317,9 +3317,6 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) if (HostileReference* forcedVictim = unitTarget->GetThreatMgr().GetOnlineContainer().getReferenceByTarget(m_caster)) unitTarget->GetThreatMgr().setCurrentVictim(forcedVictim); } - - if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE)) - unitTarget->ToCreature()->AI()->AttackStart(m_caster); } void Spell::EffectWeaponDmg(SpellEffIndex effIndex) diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index f94e31d44..67c7473db 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -662,7 +662,8 @@ void SpellMgr::LoadSpellInfoCorrections() }); // Kill Command - ApplySpellFix({ 34027 }, [](SpellInfo* spellInfo) + // Kill Command, Overpower + ApplySpellFix({ 34027, 37529 }, [](SpellInfo* spellInfo) { spellInfo->ProcCharges = 0; }); @@ -4516,6 +4517,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE; }); + // Silence + ApplySpellFix({ 18278 }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesEx4 |= SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND; + }); + // Absorb Life ApplySpellFix({ 34239 }, [](SpellInfo* spellInfo) { diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 06e5dd520..d1b216507 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -601,7 +601,6 @@ public: #ifdef MOD_PLAYERBOTS [[nodiscard]] virtual char const* GetPlayerbotsDBRevision() const = 0; #endif - virtual void LoadMotd() = 0; virtual void UpdateAreaDependentAuras() = 0; [[nodiscard]] virtual uint32 GetCleaningFlags() const = 0; virtual void SetCleaningFlags(uint32 flags) = 0; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 74ef94fa2..a35a7642d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -74,7 +74,7 @@ #include "PoolMgr.h" #include "Realm.h" #include "ScriptMgr.h" -#include "ServerMotd.h" +#include "MotdMgr.h" #include "SkillDiscovery.h" #include "SkillExtraItems.h" #include "SmartAI.h" @@ -2006,8 +2006,8 @@ void World::SetInitialWorldSettings() sAutobroadcastMgr->LoadAutobroadcasts(); ///- Load Motd - LOG_INFO("server.loading", "Loading MotD..."); - LoadMotd(); + LOG_INFO("server.loading", "Loading Motd..."); + sMotdMgr->LoadMotd(); ///- Load and initialize scripts sObjectMgr->LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) @@ -2237,39 +2237,6 @@ void World::DetectDBCLang() LOG_INFO("server.loading", " "); } -void World::LoadMotd() -{ - uint32 oldMSTime = getMSTime(); - - uint32 realmId = sConfigMgr->GetOption("RealmID", 0); - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD); - stmt->SetData(0, realmId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - std::string motd; - - if (result) - { - Field* fields = result->Fetch(); - motd = fields[0].Get(); - } - else - { - LOG_WARN("server.loading", ">> Loaded 0 motd definitions. DB table `motd` is empty for this realm!"); - LOG_INFO("server.loading", " "); - } - - motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */ motd - /*"d3"+"ce"*/ + "@|" + "cf" +/*"as"+"k4"*/"fF" + "F4" +/*"d5"+"f3"*/"A2" + "DT"/*"F4"+"Az"*/ + "hi" + "s " - /*"fd"+"hy"*/ + "se" + "rv" +/*"nh"+"k3"*/"er" + " r" +/*"x1"+"A2"*/"un" + "s "/*"F2"+"Ay"*/ + "on" + " Az" - /*"xs"+"5n"*/ + "er" + "ot" +/*"xs"+"A2"*/"hC" + "or" +/*"a4"+"f3"*/"e|" + "r "/*"f2"+"A2"*/ + "|c" + "ff" - /*"5g"+"A2"*/ + "3C" + "E7" +/*"k5"+"AX"*/"FF" + "ww" +/*"sx"+"Gj"*/"w." + "az"/*"a1"+"vf"*/ + "er" + "ot" - /*"ds"+"sx"*/ + "hc" + "or" +/*"F4"+"k5"*/"e." + "or" +/*"po"+"xs"*/"g|r"/*"F4"+"p2"+"o4"+"A2"+"i2"*/;; - Motd::SetMotd(motd); - - LOG_INFO("server.loading", ">> Loaded Motd Definitions in {} ms", GetMSTimeDiffToNow(oldMSTime)); - LOG_INFO("server.loading", " "); -} - /// Update the World ! void World::Update(uint32 diff) { diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 5fa4becef..bd156bc99 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -340,7 +340,6 @@ public: #ifdef MOD_PLAYERBOTS [[nodiscard]] char const* GetPlayerbotsDBRevision() const override { return m_PlayerbotsDBRevision.c_str(); } #endif - void LoadMotd() override; void UpdateAreaDependentAuras() override; diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index b7265e89c..639c9c91f 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -33,7 +33,7 @@ EndScriptData */ #include "LFGMgr.h" #include "Language.h" #include "MapMgr.h" -#include "ServerMotd.h" +#include "MotdMgr.h" #include "ObjectMgr.h" #include "ScriptMgr.h" #include "SkillDiscovery.h" @@ -412,9 +412,9 @@ public: static bool HandleReloadMotdCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Re-Loading Motd..."); - sWorld->LoadMotd(); + sMotdMgr->LoadMotd(); handler->SendGlobalGMSysMessage("DB table `motd` reloaded."); - handler->SendGlobalSysMessage(Motd::GetMotd()); + handler->SendGlobalSysMessage(sMotdMgr->GetMotd()); return true; } diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 228d052a2..3d580cfff 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -32,7 +32,7 @@ #include "Player.h" #include "Realm.h" #include "ScriptMgr.h" -#include "ServerMotd.h" +#include "MotdMgr.h" #include "StringConvert.h" #include "UpdateTime.h" #include "VMapFactory.h" @@ -295,7 +295,7 @@ public: // Display the 'Message of the day' for the realm static bool HandleServerMotdCommand(ChatHandler* handler) { - handler->PSendSysMessage(LANG_MOTD_CURRENT, Motd::GetMotd()); + handler->PSendSysMessage(LANG_MOTD_CURRENT, sMotdMgr->GetMotd()); return true; } @@ -567,7 +567,7 @@ public: trans->Append(stmt); LoginDatabase.CommitTransaction(trans); - sWorld->LoadMotd(); + sMotdMgr->LoadMotd(); handler->PSendSysMessage(LANG_MOTD_NEW, Acore::StringTo(realmId).value(), strMotd); return true; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp index 96d603c4a..5e005e115 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp @@ -277,13 +277,9 @@ public: { if (Creature* c = me->SummonCreature(NPC_OOZE_SPRAY_STALKER, *target, TEMPSUMMON_TIMED_DESPAWN, 8000)) { - me->SetOrientation(me->GetAngle(c)); - me->SetControlled(true, UNIT_STATE_ROOT); - me->DisableRotate(true); - me->SetFacingTo(me->GetAngle(c)); - me->SendMovementFlagUpdate(); + me->SetFacingToObject(c); Talk(EMOTE_SLIME_SPRAY); - me->CastSpell(c, SPELL_SLIME_SPRAY, false); + DoCastSelf(SPELL_SLIME_SPRAY); } } events.DelayEvents(1); diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index b9e9e8501..e5cd77c38 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -328,65 +328,69 @@ enum Outhouse SOUND_FEMALE = 12671, SOUND_MALE = 12670, // Spell - SPELL_OUTHOUSE_GROANS = 48382, SPELL_CAMERA_SHAKE = 47533, - SPELL_DUST_FIELD = 48329 + SPELL_DUST_FIELD = 48329, + // Item + ITEM_ANDERHOLS_SLIDER_CIDER = 37247, + // NPC + NPC_OUTHOUSE_BUNNY_GRIZZLY = 27326, }; -class npc_outhouse_bunny : public CreatureScript +class spell_q12227_outhouse_groans : public SpellScript { -public: - npc_outhouse_bunny() : CreatureScript("npc_outhouse_bunny") { } + PrepareSpellScript(spell_q12227_outhouse_groans); - struct npc_outhouse_bunnyAI : public ScriptedAI + bool Validate(SpellInfo const* /*spellInfo*/) override { - npc_outhouse_bunnyAI(Creature* creature) : ScriptedAI(creature) { } + return ValidateSpellInfo({ SPELL_CAMERA_SHAKE, SPELL_DUST_FIELD }); + } - void Reset() override + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Player* player = GetCaster()->ToPlayer()) { - _counter = 0; - _gender = 0; - } + player->CastSpell(player, SPELL_CAMERA_SHAKE, true); - void SetData(uint32 Type, uint32 Data) override - { - if (Type == 1) - _gender = Data; - } - - void SpellHit(Unit* Caster, SpellInfo const* Spell) override - { - if (Spell->Id == SPELL_OUTHOUSE_GROANS) + switch (GetCaster()->getGender()) { - ++_counter; - if (_counter < 5) - DoCast(Caster, SPELL_CAMERA_SHAKE, true); - else - _counter = 0; - DoCast(me, SPELL_DUST_FIELD, true); - switch (_gender) - { - case GENDER_FEMALE: - DoPlaySoundToSet(me, SOUND_FEMALE); - break; - - case GENDER_MALE: - DoPlaySoundToSet(me, SOUND_MALE); - break; - } + case GENDER_FEMALE: + player->PlayDirectSound(SOUND_FEMALE); + break; + case GENDER_MALE: + player->PlayDirectSound(SOUND_MALE); + break; + default: + break; } } - private: - uint8 _counter; - uint8 _gender; - }; + } - CreatureAI* GetAI(Creature* creature) const override + void Register() override { - return new npc_outhouse_bunnyAI(creature); + OnEffectHitTarget += SpellEffectFn(spell_q12227_outhouse_groans::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; +class spell_q12227_camera_shake : public SpellScript +{ + PrepareSpellScript(spell_q12227_camera_shake); + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DUST_FIELD }); + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Player* player = GetCaster()->ToPlayer()) + if (Creature* target = GetClosestCreatureWithEntry(player, NPC_OUTHOUSE_BUNNY_GRIZZLY, 3.0f)) // hackfix: Outhouse bunny doesnt show in any script. But the visual of Dust Field do not show if cast by the player + target->CastSpell(target, SPELL_DUST_FIELD, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q12227_camera_shake::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; // Tallhorn Stage enum TallhornStage @@ -1300,7 +1304,6 @@ void AddSC_grizzly_hills() new npc_emily(); new npc_mrfloppy(); new npc_ravenous_worg(); - new npc_outhouse_bunny(); new npc_tallhorn_stag(); new npc_amberpine_woodsman(); RegisterCreatureAI(npc_wounded_skirmisher); @@ -1314,4 +1317,6 @@ void AddSC_grizzly_hills() new spell_warhead_detonate(); new spell_vehicle_warhead_fuse(); new spell_warhead_fuse(); + RegisterSpellScript(spell_q12227_outhouse_groans); + RegisterSpellScript(spell_q12227_camera_shake); } diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 76d65a417..1f97aee7f 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -397,6 +397,113 @@ public: } }; +enum Aledis +{ + SAY_CHALLENGE = 0, + SAY_DEFEATED = 1, + EVENT_TALK = 1, + EVENT_ATTACK = 2, + EVENT_EVADE = 3, + EVENT_FIREBALL = 4, + EVENT_FROSTNOVA = 5, + SPELL_FIREBALL = 20823, + SPELL_FROSTNOVA = 11831, +}; + +struct npc_magister_aledis : public ScriptedAI +{ + npc_magister_aledis(Creature* creature) : ScriptedAI(creature) { } + + void StartFight(Player* player) + { + me->Dismount(); + me->SetFacingToObject(player); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + _playerGUID = player->GetGUID(); + _events.ScheduleEvent(EVENT_TALK, 2s); + } + + void Reset() override + { + me->RestoreFaction(); + me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetImmuneToPC(true); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*spellInfo = nullptr*/) override + { + if (damage > me->GetHealth() || me->HealthBelowPctDamaged(20, damage)) + { + damage = 0; + + _events.Reset(); + me->RestoreFaction(); + me->RemoveAllAuras(); + me->GetThreatMgr().ClearAllThreat(); + me->CombatStop(true); + me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + me->SetImmuneToPC(true); + Talk(SAY_DEFEATED); + + _events.ScheduleEvent(EVENT_EVADE, 1min); + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TALK: + Talk(SAY_CHALLENGE); + _events.ScheduleEvent(EVENT_ATTACK, 2s); + break; + case EVENT_ATTACK: + me->SetImmuneToPC(false); + me->SetFaction(FACTION_MONSTER); + if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) + { + AttackStart(player); + } + _events.ScheduleEvent(EVENT_FIREBALL, 1ms); + _events.ScheduleEvent(EVENT_FROSTNOVA, 5s); + break; + case EVENT_FIREBALL: + DoCast(SPELL_FIREBALL); + _events.ScheduleEvent(EVENT_FIREBALL, 10s); + break; + case EVENT_FROSTNOVA: + DoCastAOE(SPELL_FROSTNOVA); + _events.ScheduleEvent(EVENT_FROSTNOVA, 20s); + break; + case EVENT_EVADE: + EnterEvadeMode(); + break; + } + } + + if (UpdateVictim()) + { + DoMeleeAttackIfReady(); + } + } + + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override + { + CloseGossipMenuFor(player); + me->StopMoving(); + StartFight(player); + } + +private: + EventMap _events; + ObjectGuid _playerGUID; +}; + enum Beacon { NPC_STONESCHYE_WHELP = 16927, @@ -464,4 +571,6 @@ void AddSC_hellfire_peninsula() new npc_wounded_blood_elf(); new npc_fel_guard_hound(); new go_beacon(); + + RegisterCreatureAI(npc_magister_aledis); } diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index ac53001b3..65f7cbaf8 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -1612,19 +1612,17 @@ public: ## go_amberpine_outhouse ######*/ -#define GOSSIP_USE_OUTHOUSE "Use the outhouse." #define GO_ANDERHOLS_SLIDER_CIDER_NOT_FOUND "Quest item Anderhol's Slider Cider not found." enum AmberpineOuthouse { - ITEM_ANDERHOLS_SLIDER_CIDER = 37247, - NPC_OUTHOUSE_BUNNY = 27326, QUEST_DOING_YOUR_DUTY = 12227, SPELL_INDISPOSED = 53017, + SPELL_INDISPOSED_II = 48324, SPELL_INDISPOSED_III = 48341, - SPELL_CREATE_AMBERSEEDS = 48330, GOSSIP_OUTHOUSE_INUSE = 12775, - GOSSIP_OUTHOUSE_VACANT = 12779 + GOSSIP_OUTHOUSE_VACANT = 12779, + GOSSIP_USE_OUTHOUSE = 9492, }; class go_amberpine_outhouse : public GameObjectScript @@ -1637,7 +1635,7 @@ public: QuestStatus status = player->GetQuestStatus(QUEST_DOING_YOUR_DUTY); if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) { - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_USE_OUTHOUSE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + AddGossipItemFor(player, GOSSIP_USE_OUTHOUSE, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); SendGossipMenuFor(player, GOSSIP_OUTHOUSE_VACANT, go->GetGUID()); } else @@ -1646,21 +1644,15 @@ public: return true; } - bool OnGossipSelect(Player* player, GameObject* go, uint32 /*sender*/, uint32 action) override + bool OnGossipSelect(Player* player, GameObject* /*go*/, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); if (action == GOSSIP_ACTION_INFO_DEF + 1) { CloseGossipMenuFor(player); - Creature* target = GetClosestCreatureWithEntry(player, NPC_OUTHOUSE_BUNNY, 3.0f); - if (target) - { - target->AI()->SetData(1, player->getGender()); - go->CastSpell(target, SPELL_INDISPOSED_III); - } - go->CastSpell(player, SPELL_INDISPOSED); - if (player->HasItemCount(ITEM_ANDERHOLS_SLIDER_CIDER)) - player->CastSpell(player, SPELL_CREATE_AMBERSEEDS, true); + player->CastSpell(player, SPELL_INDISPOSED); + player->CastSpell(player, SPELL_INDISPOSED_II); + player->CastSpell(player, SPELL_INDISPOSED_III); return true; } else diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 91378335e..d1e80ef2c 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2668,6 +2668,19 @@ private: TaskScheduler _scheduler; }; +struct npc_controller : public PossessedAI +{ + npc_controller(Creature* creature) : PossessedAI(creature) { } + + void OnCharmed(bool apply) override + { + if (!apply) + { + me->GetCharmerOrOwner()->InterruptNonMeleeSpells(false); + } + } +}; + void AddSC_npcs_special() { // Ours @@ -2696,4 +2709,5 @@ void AddSC_npcs_special() new npc_stable_master(); RegisterCreatureAI(npc_arcanite_dragonling); RegisterCreatureAI(npc_crashin_thrashin_robot); + RegisterCreatureAI(npc_controller); } diff --git a/src/test/mocks/WorldMock.h b/src/test/mocks/WorldMock.h index aa8e88d6f..e8c8814f0 100644 --- a/src/test/mocks/WorldMock.h +++ b/src/test/mocks/WorldMock.h @@ -111,7 +111,6 @@ public: MOCK_METHOD(LocaleConstant, GetAvailableDbcLocale, (LocaleConstant locale), (const)); MOCK_METHOD(void, LoadDBVersion, ()); MOCK_METHOD(char const *, GetDBVersion, (), (const)); - MOCK_METHOD(void, LoadMotd, ()); MOCK_METHOD(void, UpdateAreaDependentAuras, ()); MOCK_METHOD(uint32, GetCleaningFlags, (), (const)); MOCK_METHOD(void, SetCleaningFlags, (uint32 flags), ());