diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index 0c13c1861..6955ab887 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -19,8 +19,7 @@ jobs: runs-on: ${{ matrix.os }} name: ${{ matrix.os }} env: - BOOST_ROOT: C:\local\boost_1_82_0 - + BOOST_ROOT: C:\local\boost_1_87_0 steps: - name: Checkout AzerothCore uses: actions/checkout@v4 diff --git a/apps/installer/includes/functions.sh b/apps/installer/includes/functions.sh index 79fbb355d..7f179e5c1 100644 --- a/apps/installer/includes/functions.sh +++ b/apps/installer/includes/functions.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Set SUDO variable - one liner -if [[ "$OSTYPE" == "msys"* ]]; then +if [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then SUDO="" else SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "") @@ -49,7 +49,7 @@ function inst_configureOS() { source "$AC_PATH_INSTALLER/includes/os_configs/$DISTRO.sh" ;; *bsd*) echo "BSD is not supported yet" ;; - msys*) source "$AC_PATH_INSTALLER/includes/os_configs/windows.sh" ;; + msys*|cygwin*) source "$AC_PATH_INSTALLER/includes/os_configs/windows.sh" ;; *) echo "This platform is not supported" ;; esac } diff --git a/data/sql/updates/db_auth/2026_05_03_00.sql b/data/sql/updates/db_auth/2026_05_03_00.sql new file mode 100644 index 000000000..a7e350da4 --- /dev/null +++ b/data/sql/updates/db_auth/2026_05_03_00.sql @@ -0,0 +1,11 @@ +-- DB update 2026_05_01_00 -> 2026_05_03_00 +-- RBAC permissions for .pet list (sec 1+, Mod role 198) and .pet delete (sec 3+, Admin role 196). +DELETE FROM `rbac_permissions` WHERE `id` IN (914, 915); +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(914, 'Command: pet list'), +(915, 'Command: pet delete'); + +DELETE FROM `rbac_linked_permissions` WHERE `linkedId` IN (914, 915); +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(198, 914), +(196, 915); diff --git a/data/sql/updates/db_world/2026_05_03_00.sql b/data/sql/updates/db_world/2026_05_03_00.sql new file mode 100644 index 000000000..1695c8f84 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_03_00.sql @@ -0,0 +1,9 @@ +-- DB update 2026_05_02_02 -> 2026_05_03_00 +-- acore_string entries for .pet list and .pet delete commands. +DELETE FROM `acore_string` WHERE `entry` BETWEEN 35435 AND 35439; +INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES +(35435, 'Pets owned by {} ({}):', '{}({})이(가) 소유한 펫:', 'Familiers de {} ({}) :', 'Begleiter von {} ({}):', '{} ({}) 拥有的宠物:', '{} ({}) 擁有的寵物:', 'Mascotas de {} ({}):', 'Mascotas de {} ({}):', 'Питомцы игрока {} ({}):'), +(35436, ' PetNumber: {} | Slot: {} | Entry: {} ({}) | Name: {} | Level: {} | Type: {}', ' 펫번호: {} | 슬롯: {} | Entry: {} ({}) | 이름: {} | 레벨: {} | 종류: {}', ' N° Familier : {} | Emplacement : {} | Entrée : {} ({}) | Nom : {} | Niveau : {} | Type : {}', ' Begleiter-Nr.: {} | Slot: {} | Eintrag: {} ({}) | Name: {} | Stufe: {} | Typ: {}', ' 宠物编号: {} | 槽位: {} | 条目: {} ({}) | 名称: {} | 等级: {} | 类型: {}', ' 寵物編號: {} | 槽位: {} | 條目: {} ({}) | 名稱: {} | 等級: {} | 類型: {}', ' N.º mascota: {} | Ranura: {} | Entrada: {} ({}) | Nombre: {} | Nivel: {} | Tipo: {}', ' N.º mascota: {} | Ranura: {} | Entrada: {} ({}) | Nombre: {} | Nivel: {} | Tipo: {}', ' Номер: {} | Слот: {} | Entry: {} ({}) | Имя: {} | Уровень: {} | Тип: {}'), +(35437, 'Player {} ({}) has no pets.', '플레이어 {}({})에게 펫이 없습니다.', "Le joueur {} ({}) n'a aucun familier.", 'Spieler {} ({}) besitzt keine Begleiter.', '玩家 {} ({}) 没有任何宠物。', '玩家 {} ({}) 沒有任何寵物。', 'El jugador {} ({}) no tiene mascotas.', 'El jugador {} ({}) no tiene mascotas.', 'У игрока {} ({}) нет питомцев.'), +(35438, 'No pet with PetNumber {0} found for player {1} ({2}).', '플레이어 {1} ({2})의 펫번호 {0}을(를) 찾을 수 없습니다.', "Aucun familier avec le N° {0} trouvé pour le joueur {1} ({2}).", 'Kein Begleiter mit Nummer {0} für Spieler {1} ({2}) gefunden.', '未找到玩家 {1} ({2}) 的宠物编号 {0}。', '找不到玩家 {1} ({2}) 的寵物編號 {0}。', 'No se encontró ninguna mascota con N.º {0} para el jugador {1} ({2}).', 'No se encontró ninguna mascota con N.º {0} para el jugador {1} ({2}).', 'У игрока {1} ({2}) не найден питомец с номером {0}.'), +(35439, 'Deleted pet {0} ({1}, entry {2} - {3}) from player {4} ({5}).', '플레이어 {4} ({5})로부터 펫 {0} ({1}, entry {2} - {3})을(를) 삭제했습니다.', "Familier {0} ({1}, entrée {2} - {3}) supprimé du joueur {4} ({5}).", 'Begleiter {0} ({1}, Eintrag {2} - {3}) von Spieler {4} ({5}) gelöscht.', '已从玩家 {4} ({5}) 删除宠物 {0} ({1}, 条目 {2} - {3})。', '已從玩家 {4} ({5}) 刪除寵物 {0} ({1}, 條目 {2} - {3})。', 'Eliminada la mascota {0} ({1}, entrada {2} - {3}) del jugador {4} ({5}).', 'Eliminada la mascota {0} ({1}, entrada {2} - {3}) del jugador {4} ({5}).', 'Питомец {0} ({1}, entry {2} - {3}) удалён у игрока {4} ({5}).'); diff --git a/data/sql/updates/db_world/2026_05_03_01.sql b/data/sql/updates/db_world/2026_05_03_01.sql new file mode 100644 index 000000000..fdd55d9cc --- /dev/null +++ b/data/sql/updates/db_world/2026_05_03_01.sql @@ -0,0 +1,41 @@ +-- DB update 2026_05_03_00 -> 2026_05_03_01 + +-- Edit SmartAIs +DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (-129500, -129501, -129502, -129503, -129520, -129529, -129530, -129531, -129532, -129546, -129547, -129556)) AND (`source_type` = 0) AND (`id` IN (41, 42, 43)); +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 +(-129500, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129500, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129500, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129501, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129501, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129501, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129502, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129502, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129502, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129503, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129503, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129503, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129520, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129520, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129520, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129529, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129529, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129529, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129530, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129530, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129530, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129531, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129531, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129531, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129532, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129532, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129532, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129546, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129546, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129546, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129547, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129547, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129547, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'), +(-129556, 0, 41, 42, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Remove Npc Flags Gossip'), +(-129556, 0, 42, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Path 0 Finished - Despawn In 5000 ms'), +(-129556, 0, 43, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - On Just Died - Despawn In 5000 ms'); diff --git a/data/sql/updates/db_world/2026_05_04_00.sql b/data/sql/updates/db_world/2026_05_04_00.sql new file mode 100644 index 000000000..fa6623807 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_04_00.sql @@ -0,0 +1,85 @@ +-- DB update 2026_05_03_01 -> 2026_05_04_00 + +-- Delete old waypoint & add two new ones. +DELETE FROM `script_waypoint` WHERE `entry` = 29602; +DELETE FROM `waypoint_data` WHERE (`id` IN (2960200, 2960201)); +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES +(2960200, 1, 7079.6978, -2033.1096, 764.22363, NULL, 0, 1, 0, 100, 0), +(2960200, 2, 7068.746, -2081.6372, 758.46783, NULL, 0, 1, 0, 100, 0), +(2960200, 3, 7065.993, -2130.804, 756.0072, NULL, 0, 1, 0, 100, 0), +(2960200, 4, 7088.311, -2173.4739, 759.40454, NULL, 0, 1, 0, 100, 0), +(2960200, 5, 7124.069, -2207.86, 758.34875, NULL, 0, 1, 0, 100, 0), +(2960200, 6, 7152.243, -2248.376, 759.6332, NULL, 0, 1, 0, 100, 0), +(2960200, 7, 7196.3516, -2265.1384, 756.818, NULL, 0, 1, 0, 100, 0), +(2960200, 8, 7234.0127, -2297.4749, 752.40814, NULL, 0, 1, 0, 100, 0), +(2960200, 9, 7255.4043, -2341.076, 751.73083, NULL, 0, 1, 0, 100, 0), +(2960200, 10, 7297.8813, -2368.0906, 751.5218, NULL, 0, 1, 0, 100, 0), +(2960200, 11, 7304.3057, -2416.3677, 752.8529, NULL, 0, 1, 0, 100, 0), +(2960200, 12, 7320.8213, -2463.647, 750.73145, NULL, 0, 1, 0, 100, 0), +(2960200, 13, 7362.9956, -2490.5044, 749.8022, NULL, 0, 1, 0, 100, 0), +(2960200, 14, 7409.4863, -2475.0657, 751.87994, NULL, 0, 1, 0, 100, 0), +(2960200, 15, 7422.454, -2427.5562, 752.46826, NULL, 0, 1, 0, 100, 0), +(2960200, 16, 7407.2866, -2380.3416, 753.04663, NULL, 0, 1, 0, 100, 0), +(2960200, 17, 7407.848, -2331.121, 757.12366, NULL, 0, 1, 0, 100, 0), +(2960200, 18, 7366.268, -2303.2979, 756.10443, NULL, 0, 1, 0, 100, 0), +(2960200, 19, 7318.561, -2301.5312, 754.4625, NULL, 0, 1, 0, 100, 0), +(2960200, 20, 7280.9966, -2270.3918, 756.3627, NULL, 0, 1, 0, 100, 0), +(2960200, 21, 7237.944, -2246.7197, 756.31384, NULL, 0, 1, 0, 100, 0), +(2960200, 22, 7193.8286, -2231.046, 757.79626, NULL, 0, 1, 0, 100, 0), +(2960200, 23, 7159.3477, -2195.3066, 760.58264, NULL, 0, 1, 0, 100, 0), +(2960200, 24, 7122.389, -2164.836, 760.4839, NULL, 0, 1, 0, 100, 0), +(2960200, 25, 7112.4834, -2116.8887, 759.7804, NULL, 0, 1, 0, 100, 0), +(2960200, 26, 7116.9863, -2071.1887, 766.2056, NULL, 0, 1, 0, 100, 0), +(2960200, 27, 7117.6025, -2040.7129, 767.7893, NULL, 0, 1, 0, 100, 0), +(2960200, 28, 7107.0435, -2011.1892, 770.1438, NULL, 0, 1, 0, 100, 0), +(2960200, 29, 7103.9424, -1985.653, 771.0793, NULL, 0, 1, 0, 100, 0), +(2960200, 30, 7079.7, -1966.68, 769.305, NULL, 0, 1, 0, 100, 0), +(2960200, 31, 7087.928, -1931.9026, 773.7549, NULL, 0, 1, 0, 100, 0), +(2960201, 1, 7081.8774, -2012.0011, 766.2301, NULL, 0, 1, 0, 100, 0), +(2960201, 2, 7104.026, -2056.3606, 765.3837, NULL, 0, 1, 0, 100, 0), +(2960201, 3, 7104.528, -2105.8418, 760.49347, NULL, 0, 1, 0, 100, 0), +(2960201, 4, 7116.4165, -2153.7432, 759.7369, NULL, 0, 1, 0, 100, 0), +(2960201, 5, 7147.767, -2190.783, 759.2086, NULL, 0, 1, 0, 100, 0), +(2960201, 6, 7189.606, -2217.285, 759.46906, NULL, 0, 1, 0, 100, 0), +(2960201, 7, 7231.661, -2238.2708, 757.4844, NULL, 0, 1, 0, 100, 0), +(2960201, 8, 7272.987, -2260.4424, 756.20917, NULL, 0, 1, 0, 100, 0), +(2960201, 9, 7310.389, -2289.4739, 754.7779, NULL, 0, 1, 0, 100, 0), +(2960201, 10, 7355.282, -2303.5774, 755.6713, NULL, 0, 1, 0, 100, 0), +(2960201, 11, 7401.5444, -2318.8916, 757.8036, NULL, 0, 1, 0, 100, 0), +(2960201, 12, 7413.0244, -2353.2883, 755.66315, NULL, 0, 1, 0, 100, 0), +(2960201, 13, 7386.935, -2394.2864, 749.2125, NULL, 0, 1, 0, 100, 0), +(2960201, 14, 7343.7847, -2418.5652, 749.6803, NULL, 0, 1, 0, 100, 0), +(2960201, 15, 7300.632, -2393.1646, 751.9034, NULL, 0, 1, 0, 100, 0), +(2960201, 16, 7281.886, -2347.135, 749.444, NULL, 0, 1, 0, 100, 0), +(2960201, 17, 7268.9087, -2299.5518, 752.52783, NULL, 0, 1, 0, 100, 0), +(2960201, 18, 7227.1978, -2271.2617, 755.354, NULL, 0, 1, 0, 100, 0), +(2960201, 19, 7181.099, -2253.8003, 757.4965, NULL, 0, 1, 0, 100, 0), +(2960201, 20, 7136.719, -2232.0361, 758.35034, NULL, 0, 1, 0, 100, 0), +(2960201, 21, 7103.6987, -2195.238, 759.33044, NULL, 0, 1, 0, 100, 0), +(2960201, 22, 7072.1104, -2157.011, 759.6482, NULL, 0, 1, 0, 100, 0), +(2960201, 23, 7059.117, -2109.4075, 755.57043, NULL, 0, 1, 0, 100, 0), +(2960201, 24, 7069.828, -2068.9705, 759.4906, NULL, 0, 1, 0, 100, 0), +(2960201, 25, 7092.831, -2042.584, 766.1361, NULL, 0, 1, 0, 100, 0), +(2960201, 26, 7107.4473, -2013.8727, 769.5967, NULL, 0, 1, 0, 100, 0), +(2960201, 27, 7102.1475, -1985.027, 770.659, NULL, 0, 1, 0, 100, 0), +(2960201, 28, 7079.7, -1966.68, 769.305, NULL, 0, 1, 0, 100, 0), +(2960201, 29, 7087.928, -1931.9026, 773.7549, NULL, 0, 1, 0, 100, 0); + +-- Set SmartAI +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE (`entry` = 29602); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 29602); +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 +(29602, 0, 0, 1, 27, 0, 100, 512, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Icefang - On Passenger Boarded - Set Reactstate Passive'), +(29602, 0, 1, 2, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Icefang - On Passenger Boarded - Disable Evade'), +(29602, 0, 2, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 233, 2960200, 2960201, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Icefang - On Passenger Boarded - Start Random Path 2960200-2960201'), +(29602, 0, 3, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Icefang - On Passenger Removed - Despawn Instant'), +(29602, 0, 4, 0, 109, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Icefang - On Any Path Finished - Despawn Instant'); + +-- Delete Old Condition (Icefang spellclick requires the Going Bearback quest to not be rewarded) +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 18) AND (`SourceGroup` = 29598) AND (`SourceEntry` = 54768) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 8) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 12856) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0); + +-- Add new Condition. +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 18) AND (`SourceGroup` = 29598) AND (`SourceEntry` = 54768) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 9) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 12851) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(18, 29598, 54768, 0, 0, 9, 0, 12851, 0, 0, 0, 0, 0, '', 'Icefang spellclick require Going Bearback quest taken'); diff --git a/data/sql/updates/db_world/2026_05_04_01.sql b/data/sql/updates/db_world/2026_05_04_01.sql new file mode 100644 index 000000000..50bee0bb4 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_04_01.sql @@ -0,0 +1,6 @@ +-- DB update 2026_05_04_00 -> 2026_05_04_01 + +-- Add Stitches to legacy spawn group. +DELETE FROM `spawn_group` WHERE `spawnId` = 300000; +INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES +(1, 0, 300000); diff --git a/data/sql/updates/db_world/2026_05_05_00.sql b/data/sql/updates/db_world/2026_05_05_00.sql new file mode 100644 index 000000000..c9efca237 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_05_00.sql @@ -0,0 +1,14 @@ +-- DB update 2026_05_04_01 -> 2026_05_05_00 +-- +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 3568); +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 +(3568, 0, 1, 2, 19, 0, 100, 512, 938, 0, 0, 0, 0, 0, 29, 1, 1, 3519, 938, 1, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Quest \'Mist\' Taken - Start Follow Invoker'), +(3568, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 83, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Quest \'Mist\' Taken - Remove Npc Flags Questgiver'), +(3568, 0, 3, 4, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Quest \'Mist\' Taken - Remove Flags Immune To NPC\'s'), +(3568, 0, 4, 0, 61, 0, 100, 513, 0, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Quest \'Mist\' Taken - Set Reactstate Defensive'), +(3568, 0, 5, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 70, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Just Died - Respawn Self'), +(3568, 0, 6, 7, 11, 0, 100, 512, 0, 0, 0, 0, 0, 0, 18, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Respawn - Set Flags Immune To NPC\'s'), +(3568, 0, 7, 8, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 81, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Respawn - Set Npc Flags Questgiver'), +(3568, 0, 8, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Respawn - Set Reactstate Passive'), +(3568, 0, 9, 10, 65, 0, 100, 512, 0, 0, 0, 0, 0, 0, 70, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mist - On Follow Complete - Respawn Self'), +(3568, 0, 10, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 0, 0, 19, 3519, 10, 0, 0, 0, 0, 0, 0, 'Mist - On Follow Complete - Say Line 0'); diff --git a/data/sql/updates/db_world/2026_05_05_01.sql b/data/sql/updates/db_world/2026_05_05_01.sql new file mode 100644 index 000000000..7a1291608 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_05_01.sql @@ -0,0 +1,18 @@ +-- DB update 2026_05_05_00 -> 2026_05_05_01 + +-- Edit SAI (Talbot) +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 25301; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 25301) AND (`source_type` = 0) AND (`id` IN (3, 4, 5, 6, 7, 8, 9)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(25301, 0, 3, 4, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Just Summoned - Remove Npc Flags Questgiver'), +(25301, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 232, 253011, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Just Summoned - Start Path 253011'), +(25301, 0, 5, 0, 109, 0, 100, 0, 0, 253011, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 10, 101303, 26170, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Path Finished - Send Action to Thassarian'), +(25301, 0, 6, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 19, 25250, 100, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Just Died - Send Event to General Arlos'), +(25301, 0, 7, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 19, 25251, 100, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Just Died - Send Event to Leryssa'), +(25301, 0, 8, 0, 109, 0, 100, 0, 0, 253011, 0, 0, 0, 0, 90, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Path Finished - Set Flag Standstate Kneel'), +(25301, 0, 9, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Counselor Talbot - On Respawn - Deload Equipment'); + +-- Edit Action Lists (Thassarian) +UPDATE `smart_scripts` SET `action_param3` = 1 WHERE (`entryorguid` = 2617004) AND (`source_type` = 9) AND (`id` IN (2)); +UPDATE `smart_scripts` SET `action_param3` = 1 WHERE (`entryorguid` = 2617001) AND (`source_type` = 9) AND (`id` IN (5)); diff --git a/data/sql/updates/db_world/2026_05_05_02.sql b/data/sql/updates/db_world/2026_05_05_02.sql new file mode 100644 index 000000000..a211cdd5e --- /dev/null +++ b/data/sql/updates/db_world/2026_05_05_02.sql @@ -0,0 +1,4 @@ +-- DB update 2026_05_05_01 -> 2026_05_05_02 + +-- Delete Row 7 +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 3099200) AND (`source_type` = 9) AND (`id` IN (7)); diff --git a/data/sql/updates/db_world/2026_05_05_03.sql b/data/sql/updates/db_world/2026_05_05_03.sql new file mode 100644 index 000000000..0d8d544d0 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_05_03.sql @@ -0,0 +1,14 @@ +-- DB update 2026_05_05_02 -> 2026_05_05_03 + +-- Edit Action Lists 1985100, 1985101 & update comments. +DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (1985100, 1985101)); +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 +(1985100, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Set Active On'), +(1985100, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Set Flags Immune To Players & Immune To NPC\'s'), +(1985100, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 53, 2, 1985100, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Start Waypoint Path 1985100'), +(1985100, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 15742, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Cast \'Ashcrombe`s Teleport\''), +(1985100, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Set Event Phase 2'), +(1985101, 9, 0, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 10, 70967, 19832, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Set Orientation Closest Creature \'Doctor Vomisa, Ph.T.\''), +(1985101, 9, 1, 0, 0, 0, 100, 0, 150, 150, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Say Line 0'), +(1985101, 9, 2, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 19, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Remove Flags Immune To Players & Immune To NPC\'s'), +(1985101, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 10, 70975, 19849, 0, 0, 0, 0, 0, 0, 'Negatron - Actionlist - Start Attacking'); diff --git a/data/sql/updates/db_world/2026_05_05_04.sql b/data/sql/updates/db_world/2026_05_05_04.sql new file mode 100644 index 000000000..fb23be320 --- /dev/null +++ b/data/sql/updates/db_world/2026_05_05_04.sql @@ -0,0 +1,5 @@ +-- DB update 2026_05_05_03 -> 2026_05_05_04 +-- Talisman of Troll Divinity (37734) - Touched by a Troll proc on direct heals +DELETE FROM `spell_proc` WHERE `SpellId` = 60517; +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES +(60517, 0, 0, 0, 0, 0, 0x4000, 2, 2, 0, 0, 0, 0, 100, 0, 0); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 8ce3641e8..f84e84c34 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -1241,6 +1241,23 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui void SmartAI::StopFollow(bool complete) { + if (complete) + { + Player* player = ObjectAccessor::GetPlayer(*me, mFollowGuid); + if (player && mFollowCredit > 0) + { + if (!mFollowCreditType) + player->RewardPlayerAndGroupAtEvent(mFollowCredit, me); + else + player->GroupEventHappens(mFollowCredit, me); + } + + SetDespawnTime(5000); + StartDespawn(); + + GetScript()->ProcessEventsFor(SMART_EVENT_FOLLOW_COMPLETED, player); + } + mFollowGuid.Clear(); mFollowDist = 0; mFollowAngle = 0; @@ -1252,23 +1269,6 @@ void SmartAI::StopFollow(bool complete) me->GetMotionMaster()->Clear(false); me->StopMoving(); me->GetMotionMaster()->MoveIdle(); - - if (!complete) - return; - - Player* player = ObjectAccessor::GetPlayer(*me, mFollowGuid); - if (player) - { - if (!mFollowCreditType) - player->RewardPlayerAndGroupAtEvent(mFollowCredit, me); - else - player->GroupEventHappens(mFollowCredit, me); - } - - SetDespawnTime(5000); - StartDespawn(); - - GetScript()->ProcessEventsFor(SMART_EVENT_FOLLOW_COMPLETED, player); } void SmartAI::SetScript9(SmartScriptHolder& e, uint32 entry, WorldObject* invoker) diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index c4af7947e..de2419a2f 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -676,6 +676,8 @@ enum RBACPermissions RBAC_PERM_COMMAND_CHARACTER_CHECK_PROFESSION = 911, RBAC_PERM_COMMAND_GOBJECT_LOAD = 912, RBAC_PERM_COMMAND_BF_QUEUE = 913, + RBAC_PERM_COMMAND_PET_LIST = 914, + RBAC_PERM_COMMAND_PET_DELETE = 915, // custom permissions 1000+ RBAC_PERM_MAX }; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 4537b5e0f..c31d8f2db 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2718,7 +2718,8 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const float x, y, z; x = y = z = 0.0f; - if (GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)->GetResetPosition(x, y, z)) + MovementGenerator* idleSlot = GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE); + if (idleSlot && idleSlot->GetResetPosition(x, y, z)) return IsInDist2d(x, y, dist); else return IsInDist2d(&m_homePosition, dist); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a74c0c0d6..639b1cc53 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14351,7 +14351,7 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(c->GetEntry()); if (clickPair.first == clickPair.second) - return true; + return false; for (SpellClickInfoContainer::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 7a0049d2b..91d48e50a 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8387,8 +8387,10 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers p { victim->ModifyPower(powerType, damage, false); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID)) - victim->GetThreatMgr().ForwardThreatForAssistingMe(this, float(damage) / 2.0f, spellInfo, true); + // Happiness is internal hunter pet state, not combat assistance — energizing it must not generate threat + if (powerType != POWER_HAPPINESS) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID)) + victim->GetThreatMgr().ForwardThreatForAssistingMe(this, float(damage) / 2.0f, spellInfo, true); SendEnergizeSpellLog(victim, spellID, damage, powerType); } diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 8266d13d1..1cd6066d7 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -459,14 +459,35 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) return; } - // log traded items before moving (pointers become invalid after moveItems) + // cache traded item info before moving (pointers become invalid after moveItems if items merge into existing stacks) + struct TradedItemInfo + { + bool present = false; + std::string name; + uint32 entry = 0; + uint32 count = 0; + }; + TradedItemInfo myItemsInfo[TRADE_SLOT_TRADED_COUNT]; + TradedItemInfo hisItemsInfo[TRADE_SLOT_TRADED_COUNT]; std::string myItemsStr, hisItemsStr; for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (myItems[i]) - myItemsStr += Acore::StringFormat("{} (Entry:{}) x{}, ", myItems[i]->GetTemplate()->Name1, myItems[i]->GetEntry(), myItems[i]->GetCount()); + { + myItemsInfo[i].present = true; + myItemsInfo[i].name = myItems[i]->GetTemplate()->Name1; + myItemsInfo[i].entry = myItems[i]->GetEntry(); + myItemsInfo[i].count = myItems[i]->GetCount(); + myItemsStr += Acore::StringFormat("{} (Entry:{}) x{}, ", myItemsInfo[i].name, myItemsInfo[i].entry, myItemsInfo[i].count); + } if (hisItems[i]) - hisItemsStr += Acore::StringFormat("{} (Entry:{}) x{}, ", hisItems[i]->GetTemplate()->Name1, hisItems[i]->GetEntry(), hisItems[i]->GetCount()); + { + hisItemsInfo[i].present = true; + hisItemsInfo[i].name = hisItems[i]->GetTemplate()->Name1; + hisItemsInfo[i].entry = hisItems[i]->GetEntry(); + hisItemsInfo[i].count = hisItems[i]->GetCount(); + hisItemsStr += Acore::StringFormat("{} (Entry:{}) x{}, ", hisItemsInfo[i].name, hisItemsInfo[i].entry, hisItemsInfo[i].count); + } } // execute trade: 1. remove @@ -509,10 +530,10 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { - if (myItems[i]) + if (myItemsInfo[i].present) LOG_GM(GetAccountId(), "GM {} (Account: {}) traded item: {} (Entry: {} Count: {}) to {}", _player->GetName(), GetAccountId(), - myItems[i]->GetTemplate()->Name1, myItems[i]->GetEntry(), myItems[i]->GetCount(), + myItemsInfo[i].name, myItemsInfo[i].entry, myItemsInfo[i].count, trader->GetName()); } if (my_trade->GetMoney() > 0) @@ -523,10 +544,10 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { - if (hisItems[i]) + if (hisItemsInfo[i].present) LOG_GM(trader->GetSession()->GetAccountId(), "GM {} (Account: {}) traded item: {} (Entry: {} Count: {}) to {}", trader->GetName(), trader->GetSession()->GetAccountId(), - hisItems[i]->GetTemplate()->Name1, hisItems[i]->GetEntry(), hisItems[i]->GetCount(), + hisItemsInfo[i].name, hisItemsInfo[i].entry, hisItemsInfo[i].count, _player->GetName()); } if (his_trade->GetMoney() > 0) diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index de55d37cd..9ab22993a 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1478,6 +1478,15 @@ enum AcoreStrings LANG_POOL_LOOKUP_IN_POOL = 35431, LANG_POOL_LOOKUP_NOT_IN_POOL = 35432, LANG_POOL_LOOKUP_USE_INFO = 35433, - LANG_POOL_LOOKUP_NOTARGET = 35434 + LANG_POOL_LOOKUP_NOTARGET = 35434, + + // Pet list command + LANG_PET_LIST_HEADER = 35435, + LANG_PET_LIST_ENTRY = 35436, + LANG_PET_LIST_EMPTY = 35437, + + // Pet delete command + LANG_PET_DELETE_NOT_FOUND = 35438, + LANG_PET_DELETE_SUCCESS = 35439 }; #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 964fa9c06..4817aa222 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5390,10 +5390,10 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool { if (target->isDead() && GetBase() && target->IsCreature() && target->GetEntry() == 24601) { - auto caster2 = GetBase()->GetCaster(); - if (caster2 && caster2->IsPlayer()) + if (Unit* caster2 = GetBase()->GetCaster()) { - caster2->ToPlayer()->KilledMonsterCredit(25987); + if (Player* player = caster2->GetCharmerOrOwnerPlayerOrPlayerItself()) + player->KilledMonsterCredit(25987); } } return; diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp index 42137e367..ed46d2982 100644 --- a/src/server/scripts/Commands/cs_pet.cpp +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -17,6 +17,8 @@ #include "Chat.h" #include "CommandScript.h" +#include "DatabaseEnv.h" +#include #include "Language.h" #include "Log.h" #include "ObjectMgr.h" @@ -37,9 +39,11 @@ public: { static ChatCommandTable petCommandTable = { - { "create", HandlePetCreateCommand, rbac::RBAC_PERM_COMMAND_PET_CREATE, Console::No }, - { "learn", HandlePetLearnCommand, rbac::RBAC_PERM_COMMAND_PET_LEARN, Console::No }, - { "unlearn", HandlePetUnlearnCommand, rbac::RBAC_PERM_COMMAND_PET_UNLEARN, Console::No } + { "create", HandlePetCreateCommand, rbac::RBAC_PERM_COMMAND_PET_CREATE, Console::No }, + { "delete", HandlePetDeleteCommand, rbac::RBAC_PERM_COMMAND_PET_DELETE, Console::Yes }, + { "learn", HandlePetLearnCommand, rbac::RBAC_PERM_COMMAND_PET_LEARN, Console::No }, + { "list", HandlePetListCommand, rbac::RBAC_PERM_COMMAND_PET_LIST, Console::Yes }, + { "unlearn", HandlePetUnlearnCommand, rbac::RBAC_PERM_COMMAND_PET_UNLEARN, Console::No } }; static ChatCommandTable commandTable = @@ -126,6 +130,103 @@ public: return true; } + static bool HandlePetDeleteCommand(ChatHandler* handler, PlayerIdentifier owner, uint32 petNumber) + { + ObjectGuid ownerGuid = owner.GetGUID(); + + QueryResult result = CharacterDatabase.Query( + "SELECT entry, name FROM character_pet WHERE id = {} AND owner = {}", + petNumber, ownerGuid.GetCounter()); + + if (!result) + { + handler->SendErrorMessage(LANG_PET_DELETE_NOT_FOUND, petNumber, owner.GetName(), + ownerGuid.GetCounter()); + return false; + } + + if (Player* online = owner.GetConnectedPlayer()) + { + if (Pet* activePet = online->GetPet()) + { + if (activePet->GetCharmInfo() && + activePet->GetCharmInfo()->GetPetNumber() == petNumber) + { + online->RemovePet(activePet, PET_SAVE_AS_DELETED); + } + } + + // Drop the pet from the in-memory PetStable so the stable UI / call-pet + // logic does not reference a row that no longer exists in the database. + if (PetStable* stable = online->GetPetStable()) + { + if (stable->CurrentPet && stable->CurrentPet->PetNumber == petNumber) + stable->CurrentPet.reset(); + + for (Optional& stabled : stable->StabledPets) + if (stabled && stabled->PetNumber == petNumber) + stabled.reset(); + + stable->UnslottedPets.erase( + std::remove_if(stable->UnslottedPets.begin(), stable->UnslottedPets.end(), + [petNumber](PetStable::PetInfo const& p) { return p.PetNumber == petNumber; }), + stable->UnslottedPets.end()); + } + } + + Field* fields = result->Fetch(); + uint32 entry = fields[0].Get(); + std::string name = fields[1].Get(); + + std::string creatureName = ""; + if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry)) + creatureName = cInfo->Name; + + Pet::DeleteFromDB(petNumber); + + handler->PSendSysMessage(LANG_PET_DELETE_SUCCESS, petNumber, name, entry, creatureName, + owner.GetName(), ownerGuid.GetCounter()); + return true; + } + + static bool HandlePetListCommand(ChatHandler* handler, PlayerIdentifier owner) + { + ObjectGuid ownerGuid = owner.GetGUID(); + + QueryResult result = CharacterDatabase.Query( + "SELECT id, entry, level, slot, name, PetType FROM character_pet " + "WHERE owner = {} ORDER BY slot, id", + ownerGuid.GetCounter()); + + if (!result) + { + handler->PSendSysMessage(LANG_PET_LIST_EMPTY, owner.GetName(), ownerGuid.GetCounter()); + return true; + } + + handler->PSendSysMessage(LANG_PET_LIST_HEADER, owner.GetName(), ownerGuid.GetCounter()); + + do + { + Field* fields = result->Fetch(); + uint32 petNumber = fields[0].Get(); + uint32 entry = fields[1].Get(); + uint8 level = fields[2].Get(); + uint8 slot = fields[3].Get(); + std::string name = fields[4].Get(); + uint8 petType = fields[5].Get(); + + std::string creatureName = ""; + if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry)) + creatureName = cInfo->Name; + + handler->PSendSysMessage(LANG_PET_LIST_ENTRY, petNumber, uint32(slot), entry, + creatureName, name, uint32(level), uint32(petType)); + } while (result->NextRow()); + + return true; + } + static bool HandlePetUnlearnCommand(ChatHandler* handler, SpellInfo const* spell) { if (!spell) diff --git a/src/server/scripts/Commands/cs_send.cpp b/src/server/scripts/Commands/cs_send.cpp index 3e3d6f56f..0bc074e4b 100644 --- a/src/server/scripts/Commands/cs_send.cpp +++ b/src/server/scripts/Commands/cs_send.cpp @@ -189,17 +189,31 @@ public: return true; } - static bool HandleSendMoneyCommand(ChatHandler* handler, Optional target, QuotedString subject, QuotedString text, uint32 money) + static bool HandleSendMoneyCommand(ChatHandler* handler, Optional target, QuotedString subject, QuotedString text, Tail money) { if (!target) - { target = PlayerIdentifier::FromTargetOrSelf(handler); - } if (!target) - { return false; - } + + auto IsExistWord = [](std::string_view line, std::initializer_list words) + { + for (auto const& word : words) + { + if (line.find(word) != std::string_view::npos) + return true; + } + + return false; + }; + + Optional moneyToAddO = IsExistWord(money, { "g", "s", "c" }) ? MoneyStringToMoney(money) : Acore::StringTo(money); + + if (!moneyToAddO) + return false; + + int32 moneyToAdd = *moneyToAddO; // from console show not existed sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); @@ -207,7 +221,7 @@ public: CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(subject, text) - .AddMoney(money) + .AddMoney(moneyToAdd) .SendMailTo(trans, MailReceiver(target->GetConnectedPlayer(), target->GetGUID().GetCounter()), sender); CharacterDatabase.CommitTransaction(trans); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp index dc6ada187..fe089e2e8 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp @@ -21,10 +21,10 @@ enum Spells { - SPELL_SHADOWWORDPAIN = 10894, - SPELL_MANABURN = 10876, - SPELL_PSYCHICSCREAM = 8122, - SPELL_SHADOWSHIELD = 22417 + SPELL_SHADOWWORDPAIN = 14032, + SPELL_MANABURN = 14033, + SPELL_PSYCHICSCREAM = 13704, + SPELL_SHADOWSHIELD = 12040 }; struct boss_high_interrogator_gerstahn : public ScriptedAI diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index fb1670616..baa8c1596 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -416,6 +416,9 @@ struct boss_sartharion : public BossAI for (uint32 i : dragons) if (Creature* boss = instance->GetCreature(i)) boss->DespawnOrUnsummon(); + + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESPERON); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION); } void SetData(uint32 type, uint32 data) override @@ -838,6 +841,8 @@ struct boss_sartharion_dragonAI : public BossAI { Talk(SAY_VESPERON_DEATH); instance->DoAction(ACTION_CLEAR_PORTAL); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_VESPERON); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_TWILIGHT_TORMENT_SARTHARION); if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) instance->SetBossState(DATA_VESPERON, DONE); break; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index c6fbed94b..e99b6cbc7 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -215,12 +215,10 @@ public: instance = me->GetInstanceScript(); if (!instance) me->IsAIEnabled = false; - first = (instance && !instance->GetPersistentData(PERSISTENT_DATA_INTRO)); } InstanceScript* instance; EventMap events; - bool first; bool shortver; void Reset() override @@ -228,9 +226,8 @@ public: shortver = false; events.Reset(); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - if (first) + if (instance && !instance->GetPersistentData(PERSISTENT_DATA_INTRO)) { - first = false; events.ScheduleEvent(EVENT_PRE_INTRO_1, 10s); events.ScheduleEvent(EVENT_PRE_INTRO_2, 11s); events.ScheduleEvent(EVENT_EMOTE_LEADER_1, 16s); diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 5140656c0..7b5637693 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -493,51 +493,6 @@ public: } }; -class npc_icefang : public CreatureScript -{ -public: - npc_icefang() : CreatureScript("npc_icefang") { } - - struct npc_icefangAI : public npc_escortAI - { - npc_icefangAI(Creature* creature) : npc_escortAI(creature) { } - - void AttackStart(Unit* /*who*/) override { } - void JustEngagedWith(Unit* /*who*/) override { } - void EnterEvadeMode(EvadeReason /*why*/) override { } - - void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override - { - if (who->IsPlayer()) - { - if (apply) - { - me->SetWalk(false); - Start(false, who->GetGUID()); - } - } - } - - using CreatureAI::WaypointReached; - void WaypointReached(uint32 /*waypointId*/) override { } - void JustDied(Unit* /*killer*/) override { } - void OnCharmed(bool /*apply*/) override { } - - void UpdateAI(uint32 diff) override - { - npc_escortAI::UpdateAI(diff); - - if (!UpdateVictim()) - return; - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_icefangAI(creature); - } -}; - struct npc_hyldsmeet_protodrake : public CreatureAI { explicit npc_hyldsmeet_protodrake(Creature* creature) : CreatureAI(creature), _accessoryInstalled(false), _accessoryRespawnTimer(0) @@ -1344,7 +1299,6 @@ void AddSC_storm_peaks() RegisterSpellScript(spell_q13007_iron_colossus); new npc_brunnhildar_prisoner(); new npc_freed_protodrake(); - new npc_icefang(); RegisterCreatureAI(npc_hyldsmeet_protodrake); RegisterSpellScript(spell_close_rift_aura); new npc_vehicle_d16_propelled_delivery(); diff --git a/src/server/scripts/Pet/pet_dk.cpp b/src/server/scripts/Pet/pet_dk.cpp index f3d561f37..1c62f96a0 100644 --- a/src/server/scripts/Pet/pet_dk.cpp +++ b/src/server/scripts/Pet/pet_dk.cpp @@ -209,6 +209,16 @@ struct npc_pet_dk_ebon_gargoyle : ScriptedAI _decisionTimer -= diff; if (!UpdateVictimWithGaze()) { + // Re-engage if we still have a valid victim but lost engagement + // (e.g., PvP combat reference expired during CC like Cyclone) + if (Unit* victim = me->GetVictim()) + { + if (me->IsValidAttackTarget(victim)) + { + me->EngageWithTarget(victim); + return; + } + } MySelectNextTarget(); return; } @@ -356,6 +366,26 @@ struct npc_pet_dk_army_of_the_dead : public AggressorAI if (me->IsValidAttackTarget(attacker)) AttackStart(attacker); } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + { + // Re-engage if we still have a valid victim but lost engagement + // (e.g., combat reference expired during CC like knockback) + if (Unit* victim = me->GetVictim()) + { + if (me->IsValidAttackTarget(victim)) + { + me->EngageWithTarget(victim); + return; + } + } + return; + } + + DoMeleeAttackIfReady(); + } }; struct npc_pet_dk_dancing_rune_weapon : public NullCreatureAI