From c55e737fdda996abbfc41acbfb1ef7ba37fae3b2 Mon Sep 17 00:00:00 2001 From: Ryan Turner Date: Sun, 15 Jun 2025 19:32:55 +0100 Subject: [PATCH 01/50] fix(DB/Loot) - Archimonde now properly drops the Helms (#22322) Co-authored-by: amed80 <8395873+amed80@users.noreply.github.com> --- data/sql/updates/pending_db_world/rev_1750008344185215400.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1750008344185215400.sql diff --git a/data/sql/updates/pending_db_world/rev_1750008344185215400.sql b/data/sql/updates/pending_db_world/rev_1750008344185215400.sql new file mode 100644 index 000000000..dd5a0a150 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1750008344185215400.sql @@ -0,0 +1,4 @@ +-- +UPDATE `reference_loot_template` SET `Chance` = 0, `GroupId` = 3 WHERE `Entry` = 1276884; + +UPDATE `creature_loot_template` SET `MinCount` = 3, `MaxCount` = 3 WHERE `Entry`= 17968 AND`Item` = 34069 AND `Reference` = 1276884; From 6a054da69dafd6d1a34bc67acd346a090749d2d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Jun 2025 18:33:54 +0000 Subject: [PATCH 02/50] chore(DB): import pending files Referenced commit(s): c55e737fdda996abbfc41acbfb1ef7ba37fae3b2 --- .../rev_1750008344185215400.sql => db_world/2025_06_15_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1750008344185215400.sql => db_world/2025_06_15_00.sql} (83%) diff --git a/data/sql/updates/pending_db_world/rev_1750008344185215400.sql b/data/sql/updates/db_world/2025_06_15_00.sql similarity index 83% rename from data/sql/updates/pending_db_world/rev_1750008344185215400.sql rename to data/sql/updates/db_world/2025_06_15_00.sql index dd5a0a150..de61aff3b 100644 --- a/data/sql/updates/pending_db_world/rev_1750008344185215400.sql +++ b/data/sql/updates/db_world/2025_06_15_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_12_04 -> 2025_06_15_00 -- UPDATE `reference_loot_template` SET `Chance` = 0, `GroupId` = 3 WHERE `Entry` = 1276884; From c5cb54c2ea1b66f2f38b7d57dc55a430518a666f Mon Sep 17 00:00:00 2001 From: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Date: Sun, 15 Jun 2025 16:47:46 -0400 Subject: [PATCH 03/50] fix(Scripts/ScarletEnclave): Improve Might of Mograine aura behavior. (#22320) --- data/sql/updates/pending_db_world/might-of-mograine.sql | 4 ++++ .../scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp | 2 +- src/server/scripts/Spells/spell_generic.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 data/sql/updates/pending_db_world/might-of-mograine.sql diff --git a/data/sql/updates/pending_db_world/might-of-mograine.sql b/data/sql/updates/pending_db_world/might-of-mograine.sql new file mode 100644 index 000000000..d7b2b0592 --- /dev/null +++ b/data/sql/updates/pending_db_world/might-of-mograine.sql @@ -0,0 +1,4 @@ +UPDATE `spell_script_names` SET `ScriptName` = 'spell_gen_area_aura_select_players_and_caster' WHERE `spell_id` = 53642; + +DELETE FROM `spell_custom_attr` WHERE `spell_id` = 53642; +INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES (53642, 2048); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index 1edb08561..31233da0a 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -661,7 +661,7 @@ public: me->SetHomePosition(pos); me->SetWalk(false); me->GetMotionMaster()->MovePoint(1, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, true); - me->CastSpell(me, SPELL_THE_MIGHT_OF_MOGRAINE, true); + DoCastSelf(SPELL_THE_MIGHT_OF_MOGRAINE, true); break; } case EVENT_START_COUNTDOWN_14: diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 80c7365e8..0678db1e4 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -606,7 +606,6 @@ class spell_gen_black_magic_enchant : public AuraScript } }; -// 53642 - The Might of Mograine // 64174 - Protective Gaze class spell_gen_area_aura_select_players : public AuraScript { @@ -622,6 +621,7 @@ class spell_gen_area_aura_select_players : public AuraScript } }; +// 53642 - The Might of Mograine // 62650 - Fortitude of Frost // 62670 - Resilience of Nature // 62671 - Speed of Invention From 8daba92e583186948b13047115e49f740dc40a14 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Jun 2025 20:48:50 +0000 Subject: [PATCH 04/50] chore(DB): import pending files Referenced commit(s): c5cb54c2ea1b66f2f38b7d57dc55a430518a666f --- .../might-of-mograine.sql => db_world/2025_06_15_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/might-of-mograine.sql => db_world/2025_06_15_01.sql} (85%) diff --git a/data/sql/updates/pending_db_world/might-of-mograine.sql b/data/sql/updates/db_world/2025_06_15_01.sql similarity index 85% rename from data/sql/updates/pending_db_world/might-of-mograine.sql rename to data/sql/updates/db_world/2025_06_15_01.sql index d7b2b0592..089679531 100644 --- a/data/sql/updates/pending_db_world/might-of-mograine.sql +++ b/data/sql/updates/db_world/2025_06_15_01.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_15_00 -> 2025_06_15_01 UPDATE `spell_script_names` SET `ScriptName` = 'spell_gen_area_aura_select_players_and_caster' WHERE `spell_id` = 53642; DELETE FROM `spell_custom_attr` WHERE `spell_id` = 53642; From a473138dbb89b4cd616bd8c05f8b5f3b96607e07 Mon Sep 17 00:00:00 2001 From: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Date: Sun, 15 Jun 2025 17:42:51 -0400 Subject: [PATCH 05/50] fix(DB/Gameobject): Correct Area 52 Mailbox faction. (#22319) --- data/sql/updates/pending_db_world/area-52-mailbox.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 data/sql/updates/pending_db_world/area-52-mailbox.sql diff --git a/data/sql/updates/pending_db_world/area-52-mailbox.sql b/data/sql/updates/pending_db_world/area-52-mailbox.sql new file mode 100644 index 000000000..cf8a88e26 --- /dev/null +++ b/data/sql/updates/pending_db_world/area-52-mailbox.sql @@ -0,0 +1 @@ +UPDATE `gameobject_template_addon` SET `faction` = 35 WHERE `entry` = 184085; From dd96b57be4c7178fbf376bdd7523aa801512ecda Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Jun 2025 21:43:51 +0000 Subject: [PATCH 06/50] chore(DB): import pending files Referenced commit(s): a473138dbb89b4cd616bd8c05f8b5f3b96607e07 --- .../area-52-mailbox.sql => db_world/2025_06_15_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/area-52-mailbox.sql => db_world/2025_06_15_02.sql} (63%) diff --git a/data/sql/updates/pending_db_world/area-52-mailbox.sql b/data/sql/updates/db_world/2025_06_15_02.sql similarity index 63% rename from data/sql/updates/pending_db_world/area-52-mailbox.sql rename to data/sql/updates/db_world/2025_06_15_02.sql index cf8a88e26..cc5d08b1a 100644 --- a/data/sql/updates/pending_db_world/area-52-mailbox.sql +++ b/data/sql/updates/db_world/2025_06_15_02.sql @@ -1 +1,2 @@ +-- DB update 2025_06_15_01 -> 2025_06_15_02 UPDATE `gameobject_template_addon` SET `faction` = 35 WHERE `entry` = 184085; From 080e9e05da5ef2f155af6a0354b295a162c0d928 Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Mon, 16 Jun 2025 18:39:03 +0300 Subject: [PATCH 07/50] =?UTF-8?q?fix(Scripts/Items):=20Bloodsail=20Admiral?= =?UTF-8?q?'s=20hat=20should=20despawn=20parrot=20on=20=E2=80=A6=20(#22327?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rev_1750044481482063700.sql | 3 +++ src/server/scripts/Spells/spell_item.cpp | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1750044481482063700.sql diff --git a/data/sql/updates/pending_db_world/rev_1750044481482063700.sql b/data/sql/updates/pending_db_world/rev_1750044481482063700.sql new file mode 100644 index 000000000..8493a7c60 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1750044481482063700.sql @@ -0,0 +1,3 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id`=60244 AND `ScriptName`='spell_item_bloodsail_admiral_hat'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (60244, 'spell_item_bloodsail_admiral_hat'); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 62b370b05..bb9e3e079 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -4187,6 +4187,28 @@ class spell_item_multiphase_goggles : public AuraScript } }; +// 60244 - Blood Parrot Despawn Aura (Item: 12185 - Bloodsail Admiral's Hat) +enum BloodsailAdmiralHat +{ + NPC_ADMIRAL_HAT_PARROT = 11236, // Blood Parrot +}; + +class spell_item_bloodsail_admiral_hat : public AuraScript +{ + PrepareAuraScript(spell_item_bloodsail_admiral_hat); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetCaster()->ToPlayer()) + player->RemoveAllMinionsByEntry(NPC_ADMIRAL_HAT_PARROT); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_item_bloodsail_admiral_hat::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_item_spell_scripts() { RegisterSpellScript(spell_item_massive_seaforium_charge); @@ -4315,4 +4337,5 @@ void AddSC_item_spell_scripts() RegisterSpellScript(spell_item_luffa); RegisterSpellScript(spell_item_spell_reflectors); RegisterSpellScript(spell_item_multiphase_goggles); + RegisterSpellScript(spell_item_bloodsail_admiral_hat); } From d3cbce652d0fa30187a269cd0a264fe62107c299 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 15:40:04 +0000 Subject: [PATCH 08/50] chore(DB): import pending files Referenced commit(s): 080e9e05da5ef2f155af6a0354b295a162c0d928 --- .../rev_1750044481482063700.sql => db_world/2025_06_16_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1750044481482063700.sql => db_world/2025_06_16_00.sql} (83%) diff --git a/data/sql/updates/pending_db_world/rev_1750044481482063700.sql b/data/sql/updates/db_world/2025_06_16_00.sql similarity index 83% rename from data/sql/updates/pending_db_world/rev_1750044481482063700.sql rename to data/sql/updates/db_world/2025_06_16_00.sql index 8493a7c60..e0fe3b3db 100644 --- a/data/sql/updates/pending_db_world/rev_1750044481482063700.sql +++ b/data/sql/updates/db_world/2025_06_16_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_15_02 -> 2025_06_16_00 -- DELETE FROM `spell_script_names` WHERE `spell_id`=60244 AND `ScriptName`='spell_item_bloodsail_admiral_hat'; INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (60244, 'spell_item_bloodsail_admiral_hat'); From 03df00247115517db24816f00f90f01f0ef56cea Mon Sep 17 00:00:00 2001 From: Yehonal Date: Tue, 17 Jun 2025 19:30:51 +0200 Subject: [PATCH 09/50] fix(bash): repository initialization bugs and update configurations (#22311) --- .editorconfig | 2 +- .gitignore | 6 ++++++ .vscode/extensions.json | 1 - apps/installer/includes/os_configs/debian.sh | 10 ++++++++-- apps/installer/includes/os_configs/ubuntu.sh | 10 ++++++++-- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.editorconfig b/.editorconfig index 66e87791e..b9d8a411b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,7 @@ insert_final_newline = true trim_trailing_whitespace = true max_line_length = 80 -[*.{json,ts,js,yml}] +[*.{json,ts,js,yml,sh}] charset = utf-8 indent_style = space indent_size = 2 diff --git a/.gitignore b/.gitignore index 8d6ed8f64..548213a63 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,12 @@ cmake-build-*/* coverage-report/ .vs +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + # # Eclipse # diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a03767c6f..28a4c8d3f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,7 +5,6 @@ "xaver.clang-format", "bbenoist.doxygen", "ms-vscode.cpptools", - "austin.code-gnu-global", "twxs.cmake", "mhutchie.git-graph", "github.vscode-pull-request-github", diff --git a/apps/installer/includes/os_configs/debian.sh b/apps/installer/includes/os_configs/debian.sh index da137922d..418392565 100644 --- a/apps/installer/includes/os_configs/debian.sh +++ b/apps/installer/includes/os_configs/debian.sh @@ -1,3 +1,7 @@ +#!/usr/bin/env bash + +CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + if ! command -v lsb_release &>/dev/null ; then sudo apt-get install -y lsb-release fi @@ -22,8 +26,10 @@ sudo apt-get install -y gdbserver gdb unzip curl \ libssl-dev libbz2-dev \ libboost-all-dev gnupg wget +VAR_PATH="$CURRENT_PATH/../../../../var" + # run noninteractive install for MYSQL 8.4 LTS -wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb -sudo DEBIAN_FRONTEND="noninteractive" dpkg -i ./mysql-apt-config_0.8.32-1_all.deb +wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb -P "$VAR_PATH" +sudo DEBIAN_FRONTEND="noninteractive" dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb" sudo apt-get update sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server libmysqlclient-dev diff --git a/apps/installer/includes/os_configs/ubuntu.sh b/apps/installer/includes/os_configs/ubuntu.sh index 662458895..02e6997cc 100644 --- a/apps/installer/includes/os_configs/ubuntu.sh +++ b/apps/installer/includes/os_configs/ubuntu.sh @@ -1,3 +1,7 @@ +#!/usr/bin/env bash + +CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + if ! command -v lsb_release &>/dev/null ; then sudo apt-get install -y lsb-release fi @@ -36,9 +40,11 @@ else libboost-all-dev libbz2-dev libncurses-dev libreadline-dev \ libssl-dev + VAR_PATH="$CURRENT_PATH/../../../../var" + # run noninteractive install for MYSQL 8.4 LTS - wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb - sudo DEBIAN_FRONTEND="noninteractive" dpkg -i ./mysql-apt-config_0.8.32-1_all.deb + wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb -P "$VAR_PATH" + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i "$VAR_PATH/mysql-apt-config_0.8.32-1_all.deb" sudo apt-get update sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server fi From 19626d0bfad406d251804f5906c36c558efb6075 Mon Sep 17 00:00:00 2001 From: Lyn Date: Tue, 17 Jun 2025 19:46:46 +0200 Subject: [PATCH 10/50] fix(DB/Creature): Molten War Golem - Added immunities (#22315) Co-authored-by: ratkosrb --- .../pending_db_world/molten-war-golem-distract-immunity.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql diff --git a/data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql b/data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql new file mode 100644 index 000000000..375e8f170 --- /dev/null +++ b/data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql @@ -0,0 +1,2 @@ +-- Set Distract immunity to Molten War Golem +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | (8|64|1024) WHERE `entry` = 8908; From 7f46986771acf7a74b7d5c3c9dd73e11b6bb6abe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Jun 2025 17:47:49 +0000 Subject: [PATCH 11/50] chore(DB): import pending files Referenced commit(s): 19626d0bfad406d251804f5906c36c558efb6075 --- .../2025_06_17_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/molten-war-golem-distract-immunity.sql => db_world/2025_06_17_00.sql} (78%) diff --git a/data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql b/data/sql/updates/db_world/2025_06_17_00.sql similarity index 78% rename from data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql rename to data/sql/updates/db_world/2025_06_17_00.sql index 375e8f170..3739e2aa8 100644 --- a/data/sql/updates/pending_db_world/molten-war-golem-distract-immunity.sql +++ b/data/sql/updates/db_world/2025_06_17_00.sql @@ -1,2 +1,3 @@ +-- DB update 2025_06_16_00 -> 2025_06_17_00 -- Set Distract immunity to Molten War Golem UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` | (8|64|1024) WHERE `entry` = 8908; From e50a692fc7bad3b58b573fb3ec15de8e18ba8c12 Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Tue, 17 Jun 2025 19:49:18 +0200 Subject: [PATCH 12/50] fix(DB): set game_event_* tables to use smallint (#22309) --- .../updates/pending_db_world/rev_1749848424024494127.sql | 6 ++++++ src/server/game/Events/GameEventMgr.cpp | 6 +++--- src/server/game/Globals/ObjectMgr.cpp | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1749848424024494127.sql diff --git a/data/sql/updates/pending_db_world/rev_1749848424024494127.sql b/data/sql/updates/pending_db_world/rev_1749848424024494127.sql new file mode 100644 index 000000000..4c18e8ca7 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1749848424024494127.sql @@ -0,0 +1,6 @@ +-- +ALTER TABLE `game_event_creature` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event. Put negative entry to remove during event.'; +ALTER TABLE `game_event_gameobject` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event. Put negative entry to remove during event.'; +ALTER TABLE `game_event_model_equip` MODIFY COLUMN `eventEntry` tinyint unsigned NOT NULL COMMENT 'Entry of the game event.'; +ALTER TABLE `game_event_npc_vendor` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event.'; +ALTER TABLE `game_event_pool` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event. Put negative entry to remove during event.'; diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 1f61f8c5d..29b813deb 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -512,7 +512,7 @@ void GameEventMgr::LoadEventCreatureData() Field* fields = result->Fetch(); ObjectGuid::LowType guid = fields[0].Get(); - int16 eventId = fields[1].Get(); + int16 eventId = fields[1].Get(); CreatureData const* data = sObjectMgr->GetCreatureData(guid); if (!data) @@ -562,7 +562,7 @@ void GameEventMgr::LoadEventGameObjectData() Field* fields = result->Fetch(); ObjectGuid::LowType guid = fields[0].Get(); - int16 eventId = fields[1].Get(); + int16 eventId = fields[1].Get(); int32 internal_event_id = _gameEvent.size() + eventId - 1; @@ -1020,7 +1020,7 @@ void GameEventMgr::LoadEventPoolData() Field* fields = result->Fetch(); uint32 entry = fields[0].Get(); - int16 eventId = fields[1].Get(); + int16 eventId = fields[1].Get(); int32 internal_event_id = _gameEvent.size() + eventId - 1; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 330ee91e0..ed2ed79ea 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2317,7 +2317,7 @@ void ObjectMgr::LoadCreatures() data.movementType = fields[15].Get(); data.spawnMask = fields[16].Get(); data.phaseMask = fields[17].Get(); - int16 gameEvent = fields[18].Get(); + int16 gameEvent = fields[18].Get(); uint32 PoolId = fields[19].Get(); data.npcflag = fields[20].Get(); data.unit_flags = fields[21].Get(); @@ -2709,7 +2709,7 @@ void ObjectMgr::LoadGameobjects() LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) that has wrong spawn mask {} including not supported difficulty modes for map (Id: {}), skip", guid, data.id, data.spawnMask, data.mapid); data.phaseMask = fields[15].Get(); - int16 gameEvent = fields[16].Get(); + int16 gameEvent = fields[16].Get(); uint32 PoolId = fields[17].Get(); if (data.rotation.x < -1.0f || data.rotation.x > 1.0f) From a902e7314c997d527e7c2eef1b736ceda5a00abd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Jun 2025 17:50:18 +0000 Subject: [PATCH 13/50] chore(DB): import pending files Referenced commit(s): e50a692fc7bad3b58b573fb3ec15de8e18ba8c12 --- .../rev_1749848424024494127.sql => db_world/2025_06_17_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1749848424024494127.sql => db_world/2025_06_17_01.sql} (94%) diff --git a/data/sql/updates/pending_db_world/rev_1749848424024494127.sql b/data/sql/updates/db_world/2025_06_17_01.sql similarity index 94% rename from data/sql/updates/pending_db_world/rev_1749848424024494127.sql rename to data/sql/updates/db_world/2025_06_17_01.sql index 4c18e8ca7..239390474 100644 --- a/data/sql/updates/pending_db_world/rev_1749848424024494127.sql +++ b/data/sql/updates/db_world/2025_06_17_01.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_17_00 -> 2025_06_17_01 -- ALTER TABLE `game_event_creature` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event. Put negative entry to remove during event.'; ALTER TABLE `game_event_gameobject` MODIFY COLUMN `eventEntry` smallint NOT NULL COMMENT 'Entry of the game event. Put negative entry to remove during event.'; From 8c2b1bc79bf024315d0bcb79d58493377d8bf64f Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Tue, 17 Jun 2025 20:50:29 +0300 Subject: [PATCH 14/50] fix(Scripts/HoL): Ionar's Static Overload missing knockback (#22049) --- .../rev_1746345420196375200.sql | 9 ++++++ .../Ulduar/HallsOfLightning/boss_ionar.cpp | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1746345420196375200.sql diff --git a/data/sql/updates/pending_db_world/rev_1746345420196375200.sql b/data/sql/updates/pending_db_world/rev_1746345420196375200.sql new file mode 100644 index 000000000..f472b5c34 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1746345420196375200.sql @@ -0,0 +1,9 @@ +-- HoL - Static Overload +DELETE FROM `spell_script_names` WHERE `spell_id` IN (52658,59795) AND `ScriptName`='spell_ionar_static_overload'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(52658, 'spell_ionar_static_overload'), +(59795, 'spell_ionar_static_overload'); + +DELETE FROM `spelldifficulty_dbc` WHERE `ID` = 53337; +INSERT INTO `spelldifficulty_dbc` (`ID`, `DifficultySpellID_1`, `DifficultySpellID_2`, `DifficultySpellID_3`, `DifficultySpellID_4`) VALUES +(53337, 53337, 59798, 0, 0); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 0524fd43f..752ef36a3 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -18,6 +18,8 @@ #include "CreatureScript.h" #include "Player.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" #include "SpellInfo.h" #include "halls_of_lightning.h" @@ -27,6 +29,7 @@ enum IonarSpells SPELL_BALL_LIGHTNING_H = 59800, SPELL_STATIC_OVERLOAD_N = 52658, SPELL_STATIC_OVERLOAD_H = 59795, + SPELL_STATIC_OVERLOAD_KNOCK = 53337, SPELL_DISPERSE = 52770, SPELL_SUMMON_SPARK = 52746, @@ -272,8 +275,34 @@ public: }; }; +// 52658, 59795 - Static Overload +class spell_ionar_static_overload : public AuraScript +{ + PrepareAuraScript(spell_ionar_static_overload); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_STATIC_OVERLOAD_KNOCK }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + return; + + if (Unit* target = GetTarget()) + target->CastSpell(target, SPELL_STATIC_OVERLOAD_KNOCK, true); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_ionar_static_overload::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_boss_ionar() { new boss_ionar(); new npc_spark_of_ionar(); + RegisterSpellScript(spell_ionar_static_overload); } From 31f466fa3230cead5fbe5b72868a05f1c723e3dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Jun 2025 17:51:17 +0000 Subject: [PATCH 15/50] chore(DB): import pending files Referenced commit(s): a902e7314c997d527e7c2eef1b736ceda5a00abd --- .../rev_1746345420196375200.sql => db_world/2025_06_17_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1746345420196375200.sql => db_world/2025_06_17_02.sql} (92%) diff --git a/data/sql/updates/pending_db_world/rev_1746345420196375200.sql b/data/sql/updates/db_world/2025_06_17_02.sql similarity index 92% rename from data/sql/updates/pending_db_world/rev_1746345420196375200.sql rename to data/sql/updates/db_world/2025_06_17_02.sql index f472b5c34..13dacde85 100644 --- a/data/sql/updates/pending_db_world/rev_1746345420196375200.sql +++ b/data/sql/updates/db_world/2025_06_17_02.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_17_01 -> 2025_06_17_02 -- HoL - Static Overload DELETE FROM `spell_script_names` WHERE `spell_id` IN (52658,59795) AND `ScriptName`='spell_ionar_static_overload'; INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES From 84533758f9b0a545987fa89325be35f85fe180b9 Mon Sep 17 00:00:00 2001 From: Ryan Turner Date: Tue, 17 Jun 2025 20:14:45 +0100 Subject: [PATCH 16/50] fix(core/SMART_EVENT_LINK) - Seperation and clarification of "not found or invalid, skipped" (#22240) --- src/server/game/AI/SmartScripts/SmartScript.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 4b54ff788..cbccce1de 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3303,10 +3303,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.link && e.link != e.event_id) { auto linked = FindLinkedEvent(e.link); - if (linked.has_value() && linked.value().get().GetEventType() == SMART_EVENT_LINK) - executionStack.emplace_back(SmartScriptFrame{ linked.value(), unit, var0, var1, bvar, spell, gob }); + if (linked.has_value()) + { + auto& linkedEvent = linked.value().get(); + if (linkedEvent.GetEventType() == SMART_EVENT_LINK) + executionStack.emplace_back(SmartScriptFrame{ linkedEvent, unit, var0, var1, bvar, spell, gob }); + else + LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} found but has wrong type (should be 61, is {}).", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link, linkedEvent.GetEventType()); + } else - LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); + LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); } } From c5f3c968ad811b84132215a6264735f4e8105706 Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Tue, 17 Jun 2025 19:15:31 +0000 Subject: [PATCH 17/50] fix(DB/Creature) add CC immunities to the Fel Crystals in the Selin Fireheart encounter (#22304) --- data/sql/updates/pending_db_world/rev_1749586097955432885.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1749586097955432885.sql diff --git a/data/sql/updates/pending_db_world/rev_1749586097955432885.sql b/data/sql/updates/pending_db_world/rev_1749586097955432885.sql new file mode 100644 index 000000000..af73c7d1e --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1749586097955432885.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` | 646135679 WHERE `entry` IN (24722,25552); From 4f44add274684b5137c6008279c900075831a5fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Jun 2025 19:15:44 +0000 Subject: [PATCH 18/50] chore(DB): import pending files Referenced commit(s): 84533758f9b0a545987fa89325be35f85fe180b9 --- .../rev_1749586097955432885.sql => db_world/2025_06_17_03.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1749586097955432885.sql => db_world/2025_06_17_03.sql} (74%) diff --git a/data/sql/updates/pending_db_world/rev_1749586097955432885.sql b/data/sql/updates/db_world/2025_06_17_03.sql similarity index 74% rename from data/sql/updates/pending_db_world/rev_1749586097955432885.sql rename to data/sql/updates/db_world/2025_06_17_03.sql index af73c7d1e..5a8f28e1a 100644 --- a/data/sql/updates/pending_db_world/rev_1749586097955432885.sql +++ b/data/sql/updates/db_world/2025_06_17_03.sql @@ -1,2 +1,3 @@ +-- DB update 2025_06_17_02 -> 2025_06_17_03 -- UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` | 646135679 WHERE `entry` IN (24722,25552); From 4d2fe013fd4f18f2f75cc74dd91f0b9a8ff1cac7 Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Tue, 17 Jun 2025 22:26:17 +0200 Subject: [PATCH 19/50] chore(vscode): update extensions, settings, tasks (#22200) --- .devcontainer/devcontainer.json | 3 +-- .vscode/extensions.json | 2 +- .vscode/settings.json | 5 +---- .vscode/tasks.json | 35 ++++++++++++++++++++++----------- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a7cc6c681..cdf6fc887 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -27,8 +27,7 @@ "xaver.clang-format", "bbenoist.doxygen", "ms-vscode.cpptools", - "austin.code-gnu-global", - "twxs.cmake", + "ms-vscode.cmake-tools", "mhutchie.git-graph", "github.vscode-pull-request-github", "eamodio.gitlens", diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 28a4c8d3f..2b4b837a2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,7 +5,7 @@ "xaver.clang-format", "bbenoist.doxygen", "ms-vscode.cpptools", - "twxs.cmake", + "ms-vscode.cmake-tools", "mhutchie.git-graph", "github.vscode-pull-request-github", "eamodio.gitlens", diff --git a/.vscode/settings.json b/.vscode/settings.json index d3250c271..70f526afc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -115,8 +115,5 @@ "xutility": "cpp", "*.ipp": "cpp", "resumable": "cpp" - }, - "deno.enable": true, - "deno.path": "deps/deno/bin/deno", - "deno.lint": true + } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index fab16be00..c22c4f535 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,18 +13,7 @@ "problemMatcher": [] }, { - "label": "AzerothCore: Import/update database", - "type": "shell", - "command": "./acore.sh db-assembler import-all", - "group": "build", - "presentation": { - "reveal": "always", - "panel": "new" - }, - "problemMatcher": [] - }, - { - "label": "AzerothCore: download client-data", + "label": "AzerothCore: Download client-data", "type": "shell", "command": "./acore.sh client-data", "group": "none", @@ -59,6 +48,28 @@ }, "problemMatcher": [] }, + { + "label": "AzerothCore: Check codestyle cpp", + "type": "shell", + "command": "python apps/codestyle/codestyle-cpp.py", + "group": "none", + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "AzerothCore: Check codestyle sql", + "type": "shell", + "command": "python apps/codestyle/codestyle-sql.py", + "group": "none", + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, { "label": "AzerothCore: Run authserver (restarter)", "type": "shell", From d94fbb16090d53f27e8644323bc8bc1d8cd761cc Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 18 Jun 2025 10:47:10 -0300 Subject: [PATCH 20/50] fix(Scripts/ZulDrak): Fix Ghymer not being healed by storm clouds (#22302) --- .../rev_1749529028851693000.sql | 3 ++ src/server/scripts/Northrend/zone_zuldrak.cpp | 49 ------------------- src/server/scripts/Spells/spell_quest.cpp | 17 +++++-- 3 files changed, 15 insertions(+), 54 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1749529028851693000.sql diff --git a/data/sql/updates/pending_db_world/rev_1749529028851693000.sql b/data/sql/updates/pending_db_world/rev_1749529028851693000.sql new file mode 100644 index 000000000..eb968d561 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1749529028851693000.sql @@ -0,0 +1,3 @@ +-- +UPDATE `creature_template_addon` SET `auras` = '55708' WHERE `entry` = 29939; +UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 29939; diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp index 4ca892918..8b36a3106 100644 --- a/src/server/scripts/Northrend/zone_zuldrak.cpp +++ b/src/server/scripts/Northrend/zone_zuldrak.cpp @@ -819,54 +819,6 @@ public: } }; -enum StormCloud -{ - STORM_COULD = 29939, - HEALING_WINDS = 55549, - STORM_VISUAL = 55708, - GYMERS_GRAB = 55516, - RIDE_VEHICLE = 43671 -}; - -class npc_storm_cloud : public CreatureScript -{ -public: - npc_storm_cloud() : CreatureScript("npc_storm_cloud") { } - - struct npc_storm_cloudAI : public ScriptedAI - { - npc_storm_cloudAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override - { - me->CastSpell(me, STORM_VISUAL, true); - } - - void JustRespawned() override - { - Reset(); - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (spell->Id != GYMERS_GRAB) - return; - - if (Vehicle* veh = caster->GetVehicleKit()) - if (veh->GetAvailableSeatCount() != 0) - { - me->CastSpell(caster, RIDE_VEHICLE, true); - me->CastSpell(caster, HEALING_WINDS, true); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_storm_cloudAI(creature); - } -}; - enum ScourgeDisguiseInstability { SCOURGE_DISGUISE_FAILING_MESSAGE_1 = 28552, // Scourge Disguise Failing! Find a safe place! @@ -922,7 +874,6 @@ void AddSC_zuldrak() new npc_released_offspring_harkoa(); new npc_crusade_recruit(); new go_scourge_enclosure(); - new npc_storm_cloud(); RegisterSpellScript(spell_scourge_disguise_instability); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index a68e0bc52..7d869c9ce 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2269,7 +2269,10 @@ class spell_q12619_emblazon_runeblade_effect : public SpellScript enum Quest_The_Storm_King { SPELL_RIDE_GYMER = 43671, - SPELL_GRABBED = 55424 + SPELL_GRABBED = 55424, + SPELL_HEALING_WINDS = 55549, + + NPC_STORM_CLOUD = 29939 }; class spell_q12919_gymers_grab : public SpellScript @@ -2284,10 +2287,14 @@ class spell_q12919_gymers_grab : public SpellScript void HandleScript(SpellEffIndex /*effIndex*/) { int8 seatId = 2; - if (!GetHitCreature()) - return; - GetHitCreature()->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true); - GetHitCreature()->CastSpell(GetHitCreature(), SPELL_GRABBED, true); + if (Creature* creature = GetHitCreature()) + { + creature->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true); + creature->CastSpell(creature, SPELL_GRABBED, true); + + if (creature->GetEntry() == NPC_STORM_CLOUD) + creature->CastSpell(GetCaster(), SPELL_HEALING_WINDS, true); + } } void Register() override From 56f8f6ab987d4a9f9cba547aea96d481c2de4d4a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 18 Jun 2025 13:48:10 +0000 Subject: [PATCH 21/50] chore(DB): import pending files Referenced commit(s): d94fbb16090d53f27e8644323bc8bc1d8cd761cc --- .../rev_1749529028851693000.sql => db_world/2025_06_18_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1749529028851693000.sql => db_world/2025_06_18_00.sql} (77%) diff --git a/data/sql/updates/pending_db_world/rev_1749529028851693000.sql b/data/sql/updates/db_world/2025_06_18_00.sql similarity index 77% rename from data/sql/updates/pending_db_world/rev_1749529028851693000.sql rename to data/sql/updates/db_world/2025_06_18_00.sql index eb968d561..000b6d5ed 100644 --- a/data/sql/updates/pending_db_world/rev_1749529028851693000.sql +++ b/data/sql/updates/db_world/2025_06_18_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_17_03 -> 2025_06_18_00 -- UPDATE `creature_template_addon` SET `auras` = '55708' WHERE `entry` = 29939; UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 29939; From e21dd803812c6ba324b70e3b3fde8d42f0656fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francesco=20Borz=C3=AC?= Date: Wed, 18 Jun 2025 20:10:33 +0200 Subject: [PATCH 22/50] fix(Core/PlayerTaxi): prevent pop_front crash (#22292) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/server/game/Entities/Player/PlayerTaxi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/game/Entities/Player/PlayerTaxi.h b/src/server/game/Entities/Player/PlayerTaxi.h index a200ad8f7..3b064ba7a 100644 --- a/src/server/game/Entities/Player/PlayerTaxi.h +++ b/src/server/game/Entities/Player/PlayerTaxi.h @@ -65,6 +65,9 @@ public: [[nodiscard]] uint32 GetCurrentTaxiPath() const; uint32 NextTaxiDestination() { + if (m_TaxiDestinations.empty()) + return 0; + m_TaxiDestinations.pop_front(); return GetTaxiDestination(); } From 7fc8b14e3eb4eaf2acec0f27cecd4a7e44015f09 Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Fri, 20 Jun 2025 23:18:05 +0200 Subject: [PATCH 23/50] feat(Core/Utilities): add `Seconds` overload for `randtime` (#22337) --- src/common/Utilities/Random.cpp | 8 ++++++++ src/common/Utilities/Random.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp index 40090caa1..babf23500 100644 --- a/src/common/Utilities/Random.cpp +++ b/src/common/Utilities/Random.cpp @@ -69,6 +69,14 @@ Milliseconds randtime(Milliseconds min, Milliseconds max) return min + Milliseconds(urand(0, diff)); } +Seconds randtime(Seconds min, Seconds max) +{ + long long diff = max.count() - min.count(); + ASSERT(diff >= 0); + ASSERT(diff <= (uint32) - 1); + return min + Seconds(urand(0, diff)); +} + uint32 rand32() { return GetRng()->RandomUInt32(); diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h index 60d543bc4..654b1817d 100644 --- a/src/common/Utilities/Random.h +++ b/src/common/Utilities/Random.h @@ -38,6 +38,9 @@ AC_COMMON_API uint32 rand32(); /* Return a random time in the range min..max (up to millisecond precision). Only works for values where millisecond difference is a valid uint32. */ AC_COMMON_API Milliseconds randtime(Milliseconds min, Milliseconds max); +/* Return a random time in the range min..max (up to second precision). */ +AC_COMMON_API Seconds randtime(Seconds min, Seconds max); + /* Return a random number in the range min..max */ AC_COMMON_API float frand(float min, float max); From 9d03f229c9f7193630f77a14f5ca82d02b755278 Mon Sep 17 00:00:00 2001 From: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:21:29 +0200 Subject: [PATCH 24/50] fix(DB/Condition): Deliver Stolen Horse only works near Salanar. (#22341) --- data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql diff --git a/data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql b/data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql new file mode 100644 index 000000000..77aed2b1a --- /dev/null +++ b/data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql @@ -0,0 +1,5 @@ + +-- Add Condition "Player should be within 5 yard of Salanar". +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 52264) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 29) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 28653) AND (`ConditionValue2` = 5) AND (`ConditionValue3` = 0); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 52264, 0, 0, 29, 0, 28653, 5, 0, 0, 0, 0, '', 'Deliver Stolen Horse only near Salanar the Horseman'); From 58b966cbfff985f36391e1c966a2c3eeddee01bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Jun 2025 16:22:29 +0000 Subject: [PATCH 25/50] chore(DB): import pending files Referenced commit(s): 9d03f229c9f7193630f77a14f5ca82d02b755278 --- .../Stolen_Horse_Cond.sql => db_world/2025_06_21_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/Stolen_Horse_Cond.sql => db_world/2025_06_21_00.sql} (94%) diff --git a/data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql b/data/sql/updates/db_world/2025_06_21_00.sql similarity index 94% rename from data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql rename to data/sql/updates/db_world/2025_06_21_00.sql index 77aed2b1a..3d71b6931 100644 --- a/data/sql/updates/pending_db_world/Stolen_Horse_Cond.sql +++ b/data/sql/updates/db_world/2025_06_21_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_18_00 -> 2025_06_21_00 -- Add Condition "Player should be within 5 yard of Salanar". DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 52264) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 29) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 28653) AND (`ConditionValue2` = 5) AND (`ConditionValue3` = 0); From 711f674c8ad19c0714b5a576a5fdd67be1e292bc Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sat, 21 Jun 2025 14:32:22 -0300 Subject: [PATCH 26/50] fix(Scripts/ScarletEnclave): Rewrite Brothers in Death (#22303) --- .../rev_1750043682130947900.sql | 165 +++++++ .../ScarletEnclave/chapter2.cpp | 436 +++++++----------- 2 files changed, 343 insertions(+), 258 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1750043682130947900.sql diff --git a/data/sql/updates/pending_db_world/rev_1750043682130947900.sql b/data/sql/updates/pending_db_world/rev_1750043682130947900.sql new file mode 100644 index 000000000..ee27ec118 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1750043682130947900.sql @@ -0,0 +1,165 @@ +-- +-- Pathing for Entry: 29007 +SET @NPC := 29007; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1649.966,-6042.5713,127.57849,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000465DB5 .go xyz 1649.966 -6042.5713 127.57849 + +-- Pathing for Entry: 29007 +SET @NPC := 29008; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1649.966,-6042.5713,127.57849,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000465DD2 .go xyz 1649.966 -6042.5713 127.57849 + +-- Pathing for Entry: 29007 +SET @NPC := 29009; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1649.966,-6042.5713,127.57849,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000465DE7 .go xyz 1649.966 -6042.5713 127.57849 + +-- Pathing for Entry: 29007 +SET @NPC := 29010; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1640.7407,-6032.02,134.73505,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000C65DB5 .go xyz 1640.7407 -6032.02 134.73505 + +-- Pathing for Entry: 29007 +SET @NPC := 29011; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1640.7958,-6030.307,134.73505,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000C65DD2 .go xyz 1640.7958 -6030.307 134.73505 + +-- Pathing for Entry: 29007 +SET @NPC := 29012; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1646.2389,-6032.526,134.73506,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0000C65DE7 .go xyz 1646.2389 -6032.526 134.73506 + +-- Pathing for Entry: 29007 +SET @NPC := 29013; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1640.6724,-6032.0527,134.73506,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0001465DB5 .go xyz 1640.6724 -6032.0527 134.73506 + +-- Pathing for Entry: 29007 +SET @NPC := 29014; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1638.7998,-6036.4976,132.57643,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0001465DD2 .go xyz 1638.7998 -6036.4976 132.57643 + +-- Pathing for Entry: 29007 +SET @NPC := 29015; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1638.2631,-6030.1514,134.73505,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0001465DE7 .go xyz 1638.2631 -6030.1514 134.73505 + +-- Pathing for Entry: 29007 +SET @NPC := 29016; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1642.4694,-6029.949,134.73505,0,0,1,0,100,0); +-- 0x202F2C4C201C53C000084E0001C65DE7 .go xyz 1642.4694 -6029.949 134.73505 + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 29007; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29007) AND (`source_type` = 0) AND (`id` IN (1, 2, 3, 4)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(29007, 0, 1, 0, 0, 0, 100, 0, 1000, 4000, 4000, 6000, 0, 0, 11, 15498, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Crimson Acolyte - In Combat - Cast \'Holy Smite\''), +(29007, 0, 2, 0, 0, 0, 100, 0, 6000, 9000, 25000, 30000, 0, 0, 11, 19725, 64, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 'Crimson Acolyte - In Combat - Cast \'Turn Undead\''), +(29007, 0, 3, 4, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crimson Acolyte - On Path 0 Finished - Remove Flags Immune To Players'), +(29007, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 9, 0, 0, 50, 0, 0, 0, 0, 0, 'Crimson Acolyte - On Path 0 Finished - Set In Combat With Zone'); + +UPDATE `creature_template` SET `unit_flags` = `unit_flags`|256 WHERE `entry` = 29007; + +-- Pathing for Entry: 29001 +SET @NPC := 29001; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1648.3103,-6043.6396,127.57861,0,0,1,0,100,0); + +DELETE FROM `script_waypoint` WHERE `entry` = 28912; + +SET @NPC := 28912; +SET @PATH := @NPC * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1653.36,-6038.34,127.584,0,0,0,0,100,0), +(@PATH,2,1653.7653,-6035.075,127.5844,1.596199,5000,0,0,100,0), +(@PATH,3,1651.8898,-6037.1006,127.5844,0,0,0,0,100,0), +(@PATH,4,1651.8898,-6037.1006,127.5844,3.839724302291870117,0,0,0,100,0); + +SET @PATH := (@NPC + 1) * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,1653.3759,-5971.8735,132.25667,0,0,1,0,100,0), +(@PATH,2,1685.0416,-5887.038,116.1461,0,0,1,0,100,0); + +DELETE FROM `creature_text` WHERE `CreatureID` = 28912; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(28912, 0, 0, 'Damn the Crusade! I think my ribs are broken and I might be bleeding internally.', 12, 0, 100, 0, 0, 0, 29197, 0, 'koltira deathweaver'), +(28912, 1, 0, 'I\'ll need to get my runeblade and armor... Just need a little more time.', 12, 0, 100, 0, 0, 0, 29201, 0, 'koltira deathweaver'), +(28912, 2, 0, 'I\'m still weak, but I think I can get an anti-magic barrier up. Stay inside it or you\'ll be destroyed by their spells.', 12, 0, 100, 0, 0, 0, 29203, 0, 'koltira deathweaver'), +(28912, 3, 0, 'Maintaining this barrier will require all of my concentration. Kill them all!', 12, 0, 100, 0, 0, 0, 29205, 0, 'koltira deathweaver'), +(28912, 4, 0, 'There are more coming. Defend yourself! Don\'t fall out of the anti-magic field! They\'ll tear you apart without its protection!', 12, 0, 100, 0, 0, 0, 29207, 0, 'koltira deathweaver'), +(28912, 5, 0, 'I can\'t keep this barrier up much longer... Where is that coward?', 12, 0, 100, 0, 0, 0, 29208, 0, 'koltira deathweaver'), +(28912, 6, 0, 'The High Inquisitor comes! Be ready, death knight! Do not let him draw you out of the protective bounds of my anti-magic field! Kill him and take his head!', 12, 0, 100, 0, 0, 0, 29210, 0, 'koltira deathweaver'), +(28912, 7, 0, 'Stay in the anti-magic field! Make them come to you!', 12, 0, 100, 0, 0, 0, 29225, 0, 'koltira deathweaver'), +(28912, 8, 0, 'The death of the High Inquisitor of New Avalon will not go unnoticed. You need to get out of here at once! Go, before more of them show up. I\'ll be fine on my own.', 12, 0, 100, 1, 0, 0, 29239, 0, 'koltira deathweaver'), +(28912, 9, 0, 'I\'ll draw their fire, you make your escape behind me.', 12, 0, 100, 1, 0, 0, 29240, 0, 'koltira deathweaver'), +(28912, 10, 0, 'Your High Inquisitor is nothing more than a pile of meat, Crusaders! There are none beyond the grasp of the Scourge!', 14, 0, 100, 5, 0, 0, 29241, 0, 'koltira deathweaver'), +(28912, 11, 0, '%s collapses to the ground.', 41, 0, 100, 0, 0, 0, 29230, 0, 'koltira deathweaver'); + +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 29001; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29001) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6, 7)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(29001, 0, 0, 0, 0, 0, 100, 0, 1000, 1000, 1000, 3000, 0, 0, 11, 52926, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - In Combat - Cast \'Valroth`s Smite\''), +(29001, 0, 1, 0, 2, 0, 100, 0, 0, 50, 0, 0, 0, 0, 11, 38210, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - Between 0-50% Health - Cast \'Renew\''), +(29001, 0, 2, 3, 0, 0, 100, 0, 2000, 7000, 2000, 7000, 0, 0, 11, 52922, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - In Combat - Cast \'The Inquisitor`s Penance\''), +(29001, 0, 3, 0, 61, 0, 50, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - In Combat - Say Line 2'), +(29001, 0, 4, 0, 109, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - On Path 0 Finished - Remove Flags Immune To Players'), +(29001, 0, 5, 6, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 52929, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - On Just Died - Cast \'Summon Valroth`s Remains\''), +(29001, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - On Just Died - Say Line 3'), +(29001, 0, 7, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Valroth - On Aggro - Say Line 6'); + +DELETE FROM `creature_text` WHERE `CreatureID` = 29001; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(29001, 0, 0, 'The Crusade will purge your kind from this world!', 14, 0, 100, 0, 0, 0, 29215, 0, 'high inquisitor valroth'), +(29001, 1, 0, 'It seems that I\'ll need to deal with you myself. The High Inquisitor comes for you, Scourge!', 14, 0, 100, 0, 0, 0, 29216, 0, 'high inquisitor valroth'), +(29001, 2, 0, 'You have come seeking deliverance? I have come to deliver!', 12, 0, 100, 0, 0, 0, 29222, 0, 'high inquisitor valroth'), +(29001, 2, 1, 'LIGHT PURGE YOU!', 12, 0, 100, 0, 0, 0, 29221, 0, 'high inquisitor'), +(29001, 2, 2, 'Coward!', 12, 0, 100, 0, 0, 0, 30699, 0, 'high inquisitor valroth'), +(29001, 3, 0, '%s\'s remains fall to the ground.', 41, 0, 100, 0, 0, 0, 29223, 0, 'high inquisitor'), +(29001, 4, 0, 'Acolytes, chain them all up! Prepare them for questioning!', 14, 0, 100, 0, 0, 0, 29202, 0, 'high inquisitor'), +(29001, 5, 0, 'Scourge filth! By the Light be cleansed!', 14, 0, 100, 0, 0, 0, 29214, 0, 'high inquisitor'), +(29001, 6, 0, 'Your dark Scourge magic won\'t protect you from the Light!', 12, 0, 100, 0, 0, 0, 29218, 0, 'high inquisitor'); + +DELETE FROM `gossip_menu_option` WHERE `MenuID` = 9762; +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`) VALUES +(9762, 0, 0, 'Koltira, let\'s get out of here!', 29243, 1, 1, 0); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 9762) AND (`SourceEntry` = 0) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 47) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 12727) AND (`ConditionValue2` = 8) AND (`ConditionValue3` = 0); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 9762, 0, 0, 0, 47, 0, 12727, 8, 0, 0, 0, 0, '', 'Only show Koltira gossip if player has quest Bloody Breakout incomplete'); + +UPDATE `creature_addon` SET `auras` = '' WHERE `guid` IN (130354, 129716); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp index 77ca10551..16adbed9c 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp @@ -18,6 +18,7 @@ #include "CombatAI.h" #include "CreatureScript.h" #include "CreatureTextMgr.h" +#include "ScriptedGossip.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedEscortAI.h" @@ -185,16 +186,23 @@ public: enum Koltira { - SAY_BREAKOUT1 = 0, - SAY_BREAKOUT2 = 1, - SAY_BREAKOUT3 = 2, - SAY_BREAKOUT4 = 3, - SAY_BREAKOUT5 = 4, - SAY_BREAKOUT6 = 5, - SAY_BREAKOUT7 = 6, - SAY_BREAKOUT8 = 7, - SAY_BREAKOUT9 = 8, - SAY_BREAKOUT10 = 9, + SAY_BREAKOUT0 = 0, + SAY_BREAKOUT1 = 1, + SAY_BREAKOUT2 = 2, + SAY_BREAKOUT3 = 3, + SAY_BREAKOUT4 = 4, + SAY_BREAKOUT5 = 5, + SAY_BREAKOUT6 = 6, + SAY_BREAKOUT7 = 7, + SAY_BREAKOUT8 = 8, + SAY_BREAKOUT9 = 9, + SAY_BREAKOUT10 = 10, + EMOTE_KOLTIRA_COLLAPSES = 11, + + SAY_VALROTH_WAVE3 = 0, + SAY_VALROTH_AGGRO = 1, + SAY_VALROTH_WAVE1 = 4, + SAY_VALROTH_WAVE2 = 5, SPELL_KOLTIRA_TRANSFORM = 52899, SPELL_ANTI_MAGIC_ZONE = 52894, @@ -206,7 +214,14 @@ enum Koltira //not sure about this id //NPC_DEATH_KNIGHT_MOUNT = 29201, - MODEL_DEATH_KNIGHT_MOUNT = 25278 + MODEL_DEATH_KNIGHT_MOUNT = 25278, + + POINT_STAND_UP = 0, + POINT_BOX = 1, + POINT_ANTI_MAGIC_ZONE = 2, + + POINT_MOUNT = 0, + POINT_DESPAWN = 1 }; class npc_koltira_deathweaver : public CreatureScript @@ -214,205 +229,203 @@ class npc_koltira_deathweaver : public CreatureScript public: npc_koltira_deathweaver() : CreatureScript("npc_koltira_deathweaver") { } - bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest) override - { - if (quest->GetQuestId() == QUEST_BREAKOUT) - { - creature->SetStandState(UNIT_STAND_STATE_STAND); - creature->setActive(true); - - if (npc_escortAI* pEscortAI = CAST_AI(npc_koltira_deathweaver::npc_koltira_deathweaverAI, creature->AI())) - pEscortAI->Start(false, false, player->GetGUID()); - } - return true; - } - CreatureAI* GetAI(Creature* creature) const override { return new npc_koltira_deathweaverAI(creature); } - struct npc_koltira_deathweaverAI : public npc_escortAI + struct npc_koltira_deathweaverAI : public ScriptedAI { - npc_koltira_deathweaverAI(Creature* creature) : npc_escortAI(creature), summons(me) - { - me->SetReactState(REACT_DEFENSIVE); - } - - uint32 m_uiWave; - uint32 m_uiWave_Timer; - ObjectGuid m_uiValrothGUID; - SummonList summons; + npc_koltira_deathweaverAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { - if (!HasEscortState(STATE_ESCORT_ESCORTING)) - { - m_uiWave = 0; - m_uiWave_Timer = 3000; - m_uiValrothGUID.Clear(); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->LoadEquipment(0, true); - me->RemoveAllAuras(); - summons.DespawnAll(); - } + scheduler.CancelAll(); + me->m_Events.KillAllEvents(false); + me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + me->setActive(false); } - void EnterEvadeMode(EvadeReason /*why*/) override + void StartEvent() { - me->GetThreatMgr().ClearAllThreat(); - me->CombatStop(false); - me->SetLootRecipient(nullptr); - - if (HasEscortState(STATE_ESCORT_ESCORTING)) - { - AddEscortState(STATE_ESCORT_RETURNING); - ReturnToLastPoint(); - LOG_DEBUG("scripts.ai", "EscortAI has left combat and is now returning to last point"); - } - else - { - me->GetMotionMaster()->MoveTargetedHome(); - me->SetImmuneToNPC(true); - Reset(); - } - } - - void AttackStart(Unit* who) override - { - if (HasEscortState(STATE_ESCORT_PAUSED)) + if (!me->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) // Already in progress return; - npc_escortAI::AttackStart(who); + me->SetStandState(UNIT_STAND_STATE_SIT); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->setActive(true); + + Talk(SAY_BREAKOUT0); + + me->m_Events.AddEventAtOffset([&] { + me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false); + }, 5s); } - void WaypointReached(uint32 waypointId) override + void sQuestAccept(Player* /*player*/, Quest const* quest) override { - switch (waypointId) + if (quest->GetQuestId() == QUEST_BREAKOUT) + StartEvent(); + } + + void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override + { + if (player->GetQuestStatus(QUEST_BREAKOUT) == QUEST_STATUS_INCOMPLETE) { - case 0: - Talk(SAY_BREAKOUT1); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - break; - case 1: - me->SetStandState(UNIT_STAND_STATE_KNEEL); - break; - case 2: - me->SetStandState(UNIT_STAND_STATE_STAND); - //me->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not - DoCast(me, SPELL_KOLTIRA_TRANSFORM); - me->LoadEquipment(); - break; - case 3: - SetEscortPaused(true); - me->SetStandState(UNIT_STAND_STATE_KNEEL); - Talk(SAY_BREAKOUT2); - DoCast(me, SPELL_ANTI_MAGIC_ZONE); // cast again that makes bubble up - break; - case 4: - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); - SetRun(true); - break; - case 9: - me->Mount(MODEL_DEATH_KNIGHT_MOUNT); - break; - case 10: - me->Dismount(); - break; + CloseGossipMenuFor(player); + StartEvent(); } } - void JustSummoned(Creature* summoned) override + void MovementInform(uint32 type, uint32 id) override { - if (Player* player = GetPlayerForEscort()) - summoned->AI()->AttackStart(player); + if (type != WAYPOINT_MOTION_TYPE) + return; - if (summoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH) - m_uiValrothGUID = summoned->GetGUID(); - - summoned->AddThreat(me, 0.0f); - summoned->SetImmuneToPC(false); - summons.Summon(summoned); - } - - void SummonAcolyte(uint32 uiAmount) - { - for (uint32 i = 0; i < uiAmount; ++i) - me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - } - - void UpdateAI(uint32 uiDiff) override - { - npc_escortAI::UpdateAI(uiDiff); - - if (HasEscortState(STATE_ESCORT_PAUSED)) + if (!me->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC)) { - if (m_uiWave_Timer <= uiDiff) + if (id == POINT_MOUNT) + me->Mount(MODEL_DEATH_KNIGHT_MOUNT); + else if (id == POINT_DESPAWN) { - switch (m_uiWave) + me->Dismount(); + me->DespawnOrUnsummon(); + } + + return; + } + + switch (id) + { + case POINT_STAND_UP: + Talk(SAY_BREAKOUT1); + break; + case POINT_BOX: + me->SetStandState(UNIT_STAND_STATE_KNEEL); + + scheduler.Schedule(5s, [this](TaskContext context) { + switch (context.GetRepeatCounter()) + { case 0: Talk(SAY_BREAKOUT3); - SummonAcolyte(3); - m_uiWave_Timer = 20000; + + // Shouldn't actually be spawned at this point, but no way to send his yells otherwise? + if (Creature* valroth = me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1640.8596f, -6030.834f, 134.82211f, 4.606426715850830078f, TEMPSUMMON_MANUAL_DESPAWN)) + { + _valrothGUID = valroth->GetGUID(); + valroth->AI()->Talk(SAY_VALROTH_WAVE1); + valroth->SetReactState(REACT_PASSIVE); + } + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.6724f, -6032.0527f, 134.82213f, 4.654973506927490234f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath(NPC_CRIMSON_ACOLYTE * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.0055f, -6031.893f, 134.82211f, 0.401425719261169433f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 1) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.7053f, -6031.7373f, 134.82213f, 2.443460941314697265f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 2) * 10, false); break; case 1: Talk(SAY_BREAKOUT4); - SummonAcolyte(3); - m_uiWave_Timer = 20000; + + if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID)) + valroth->AI()->Talk(SAY_VALROTH_WAVE2); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.7958f, -6030.307f, 134.82211f, 4.65355682373046875f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 3) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.7305f, -6030.751f, 134.82211f, 6.143558979034423828f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 4) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.4657f, -6030.404f, 134.82211f, 4.502949237823486328f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 5) * 10, false); break; case 2: Talk(SAY_BREAKOUT5); - SummonAcolyte(4); - m_uiWave_Timer = 20000; + + if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID)) + valroth->AI()->Talk(SAY_VALROTH_WAVE3); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.3405f, -6031.436f, 134.82211f, 4.612849712371826171f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 6) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.0404f, -6030.3843f, 134.82211f, 1.378810048103332519f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 7) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.1162f, -6029.7817f, 134.82211f, 5.707226753234863281f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 8) * 10, false); + + if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.9948f, -6029.8027f, 134.82211f, 1.605702877044677734f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 9) * 10, false); break; case 3: Talk(SAY_BREAKOUT6); - me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); - m_uiWave_Timer = 1000; - break; - case 4: + me->m_Events.AddEventAtOffset([this] { - Creature* temp = ObjectAccessor::GetCreature(*me, m_uiValrothGUID); + Talk(EMOTE_KOLTIRA_COLLAPSES, me); + me->KillSelf(); - if (!temp || !temp->IsAlive()) - { - Talk(SAY_BREAKOUT8); - m_uiWave_Timer = 5000; - } - else - { - // xinef: despawn check - Player* player = GetPlayerForEscort(); - if (!player || me->GetDistance(player) > 60.0f) - { - me->DespawnOrUnsummon(); - return; - } + if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID)) + valroth->DespawnOrUnsummon(); + }, 2min); - m_uiWave_Timer = 2500; - return; //return, we don't want m_uiWave to increment now - } - break; + if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID)) + { + valroth->AI()->Talk(SAY_VALROTH_AGGRO); + valroth->SetReactState(REACT_AGGRESSIVE); + valroth->GetMotionMaster()->MovePath(NPC_HIGH_INQUISITOR_VALROTH * 10, false); } - case 5: - Talk(SAY_BREAKOUT9); - me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); - // i do not know why the armor will also be removed - m_uiWave_Timer = 2500; + return; + default: break; - case 6: - Talk(SAY_BREAKOUT10); - SetEscortPaused(false); - break; - } + } - ++m_uiWave; - } - else - m_uiWave_Timer -= uiDiff; + context.Repeat(20s); + }); + + scheduler.Schedule(3s, [this](TaskContext) + { + DoCastSelf(SPELL_KOLTIRA_TRANSFORM); + me->LoadEquipment(); + }); + break; + case POINT_ANTI_MAGIC_ZONE: + me->SetStandState(UNIT_STAND_STATE_KNEEL); + Talk(SAY_BREAKOUT2); + DoCastSelf(SPELL_ANTI_MAGIC_ZONE); + break; } } + + void SummonedCreatureDies(Creature* summon, Unit*) override + { + if (summon->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH) + { + me->m_Events.KillAllEvents(false); + me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); + me->SetStandState(UNIT_STAND_STATE_STAND); + Talk(SAY_BREAKOUT8, 3s); + Talk(SAY_BREAKOUT9, 8s); + scheduler.Schedule(11s, [this](TaskContext) + { + Talk(SAY_BREAKOUT10); + SetInvincibility(true); + me->SetReactState(REACT_PASSIVE); + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + me->GetMotionMaster()->MovePath((me->GetEntry() + 1) * 10, false); + }); + } + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + } + + private: + ObjectGuid _valrothGUID; }; }; @@ -504,98 +517,6 @@ public: }; }; -//Koltira & Valroth- Breakout - -enum valroth -{ - //SAY_VALROTH1 = 0, Unused - SAY_VALROTH_AGGRO = 1, - SAY_VALROTH_RAND = 2, - SAY_VALROTH_DEATH = 3, - SPELL_RENEW = 38210, - SPELL_INQUISITOR_PENANCE = 52922, - SPELL_VALROTH_SMITE = 52926, - SPELL_SUMMON_VALROTH_REMAINS = 52929 -}; - -class npc_high_inquisitor_valroth : public CreatureScript -{ -public: - npc_high_inquisitor_valroth() : CreatureScript("npc_high_inquisitor_valroth") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_high_inquisitor_valrothAI(creature); - } - - struct npc_high_inquisitor_valrothAI : public ScriptedAI - { - npc_high_inquisitor_valrothAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 uiRenew_timer; - uint32 uiInquisitor_Penance_timer; - uint32 uiValroth_Smite_timer; - - void Reset() override - { - uiRenew_timer = 1000; - uiInquisitor_Penance_timer = 2000; - uiValroth_Smite_timer = 1000; - } - - void JustEngagedWith(Unit* who) override - { - Talk(SAY_VALROTH_AGGRO); - DoCast(who, SPELL_VALROTH_SMITE); - } - - void UpdateAI(uint32 diff) override - { - if (uiRenew_timer <= diff) - { - Shout(); - DoCast(me, SPELL_RENEW); - uiRenew_timer = urand(1000, 6000); - } - else uiRenew_timer -= diff; - - if (uiInquisitor_Penance_timer <= diff) - { - Shout(); - DoCastVictim(SPELL_INQUISITOR_PENANCE); - uiInquisitor_Penance_timer = urand(2000, 7000); - } - else uiInquisitor_Penance_timer -= diff; - - if (uiValroth_Smite_timer <= diff) - { - Shout(); - DoCastVictim(SPELL_VALROTH_SMITE); - uiValroth_Smite_timer = urand(1000, 6000); - } - else uiValroth_Smite_timer -= diff; - - DoMeleeAttackIfReady(); - } - - void Shout() - { - if (rand() % 100 < 15) - Talk(SAY_VALROTH_RAND); - } - - void JustDied(Unit* killer) override - { - Talk(SAY_VALROTH_DEATH); - - if (killer) - { - killer->CastSpell(me, SPELL_SUMMON_VALROTH_REMAINS, true); - } - } - }; -}; - /*###### ## npc_a_special_surprise ######*/ @@ -785,6 +706,5 @@ void AddSC_the_scarlet_enclave_c2() new npc_crusade_persuaded(); new npc_scarlet_courier(); new npc_koltira_deathweaver(); - new npc_high_inquisitor_valroth(); new npc_a_special_surprise(); } From 5a582370077632e8e0cffa3aad025ea9491c7875 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Jun 2025 17:33:24 +0000 Subject: [PATCH 27/50] chore(DB): import pending files Referenced commit(s): 711f674c8ad19c0714b5a576a5fdd67be1e292bc --- .../rev_1750043682130947900.sql => db_world/2025_06_21_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1750043682130947900.sql => db_world/2025_06_21_01.sql} (99%) diff --git a/data/sql/updates/pending_db_world/rev_1750043682130947900.sql b/data/sql/updates/db_world/2025_06_21_01.sql similarity index 99% rename from data/sql/updates/pending_db_world/rev_1750043682130947900.sql rename to data/sql/updates/db_world/2025_06_21_01.sql index ee27ec118..e7986e4be 100644 --- a/data/sql/updates/pending_db_world/rev_1750043682130947900.sql +++ b/data/sql/updates/db_world/2025_06_21_01.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_21_00 -> 2025_06_21_01 -- -- Pathing for Entry: 29007 SET @NPC := 29007; From 7c171ae4dcad80e1c4b43bcfe412fe517cf3aae4 Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Sat, 21 Jun 2025 21:44:01 +0300 Subject: [PATCH 28/50] fix(Scripts/ScarletEnclave): City guards should throw stuff at new DKs (#22317) --- .../rev_1749974778510353300.sql | 5 + src/server/game/Entities/Unit/Unit.cpp | 36 +++++++ src/server/game/Entities/Unit/Unit.h | 1 + .../ScarletEnclave/chapter5.cpp | 97 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1749974778510353300.sql diff --git a/data/sql/updates/pending_db_world/rev_1749974778510353300.sql b/data/sql/updates/pending_db_world/rev_1749974778510353300.sql new file mode 100644 index 000000000..4a0409e39 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1749974778510353300.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id` IN (58552,58533) AND `ScriptName`='spell_chapter5_return_to_capital'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(58552, 'spell_chapter5_return_to_capital'), +(58533, 'spell_chapter5_return_to_capital'); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 40b9f2e7a..72fb816a4 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -20083,6 +20083,24 @@ private: AuraType _auraType; }; +class ResetToHomeOrientation : public BasicEvent +{ +public: + ResetToHomeOrientation(Creature& self) : _self(self) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override + { + if (_self.IsInWorld() && _self.FindMap() && _self.IsAlive() && !_self.IsInCombat()) + { + _self.SetFacingTo(_self.GetHomePosition().GetOrientation()); + } + + return true; + } +private: + Creature& _self; +}; + void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, AuraType auraType, int32 addAmount, uint8 effectIndex) { AuraEffect* aurEff = nullptr; @@ -20329,6 +20347,24 @@ void Unit::SetFacingToObject(WorldObject* object) init.Launch(); } +void Unit::SetTimedFacingToObject(WorldObject* object, uint32 time) +{ + // never face when already moving + if (!IsStopped() || !time) + return; + + /// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is. + Movement::MoveSplineInit init(this); + init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ()); + init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming + init.Launch(); + + if (Creature* c = ToCreature()) + c->m_Events.AddEvent(new ResetToHomeOrientation(*c), c->m_Events.CalculateTime(time)); + else + LOG_ERROR("entities.unit", "Unit::SetTimedFacingToObject called on non-creature unit {}. This should never happen.", GetEntry()); +} + bool Unit::SetWalk(bool enable) { if (enable == IsWalking()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7fb43391e..1ce9ca0b5 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1893,6 +1893,7 @@ public: void SetInFront(WorldObject const* target); void SetFacingTo(float ori); void SetFacingToObject(WorldObject* object); + void SetTimedFacingToObject(WorldObject* object, uint32 time); // Reset to home orientation after given time bool isInAccessiblePlaceFor(Creature const* c) const; bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const; diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index 31233da0a..f16b774ac 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -1215,9 +1215,106 @@ class spell_chapter5_rebuke : public SpellScript } }; +// 58552 - Return to Orgrimmar +// 58533 - Return to Stormwind +enum ReturnToCapital +{ + SPELL_RETURN_TO_ORGRIMMAR_APPLE = 58509, + SPELL_RETURN_TO_ORGRIMMAR_BANANA = 58513, + SPELL_RETURN_TO_ORGRIMMAR_SPIT = 58520, + + EMOTE_THROW_APPLE = 2, + EMOTE_THROW_BANANA = 3, + EMOTE_THROW_SPIT = 4, + SAY_INSULT_TO_DK = 5, + + NPC_SW_GUARD = 68, + NPC_ROYAL_GUARD = 1756, + NPC_CITY_PATROLLER = 1976, + NPC_OG_GUARD = 3296, + NPC_KOR_ELITE = 14304, + + TEXT_BROADCAST_COWER = 31670 // "%s cowers in fear." +}; + +uint32 ReturnToCapitalSpells[3] = +{ + 58509, // Apple + 58513, // Banana + 58520 // Spit +}; + +class spell_chapter5_return_to_capital : public SpellScript +{ + PrepareSpellScript(spell_chapter5_return_to_capital); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_RETURN_TO_ORGRIMMAR_APPLE, SPELL_RETURN_TO_ORGRIMMAR_BANANA, SPELL_RETURN_TO_ORGRIMMAR_SPIT}); + } + + void HandleHit(SpellEffIndex /*effIndex*/) + { + Creature* creature = GetHitUnit()->ToCreature(); + Player* player = GetCaster()->ToPlayer(); + uint32 spellId = GetSpellInfo()->Id; + + if (!spellId || !creature || !player || player->IsGameMaster() || !player->IsAlive() || !creature->IsAlive() || creature->IsInCombat()) + return; + + if (creature->HasSpellCooldown(spellId)) + return; + + if (creature->GetEntry() == NPC_SW_GUARD || creature->GetEntry() == NPC_ROYAL_GUARD || creature->GetEntry() == NPC_CITY_PATROLLER || creature->GetEntry() == NPC_OG_GUARD || creature->GetEntry() == NPC_KOR_ELITE) + { + _emote = urand(2,4); + if (creature) + { + creature->PauseMovement(5000); + creature->SetTimedFacingToObject(player, 30000); + + if (roll_chance_i(30)) + { + creature->AI()->Talk(_emote, player); + creature->CastSpell(player, ReturnToCapitalSpells[_emote - 2]); + } + else + { + creature->AI()->Talk(SAY_INSULT_TO_DK, player); + creature->HandleEmoteCommand(RAND(EMOTE_ONESHOT_POINT,EMOTE_ONESHOT_RUDE)); + } + } + } + /*/// @todo: This needs to be further investigated as there are some "guard" npcs, that have civilian flags and non guard npcs should also insult the dk. + else + if (creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN) + { + creature->HandleEmoteCommand(EMOTE_STATE_COWER); // from sniff, emote 431 for a while, then reset (with "%s cowers in fear." text) + creature->PlayDirectSound(14556); // from sniff + if (player) + { + LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); + if (BroadcastText const* bct = sObjectMgr->GetBroadcastText(TEXT_BROADCAST_COWER)) + creature->TextEmote(bct->GetText(loc_idx, creature->getGender()), creature); + } + } + */ + + creature->AddSpellCooldown(spellId, 0, 30000); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_chapter5_return_to_capital::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } +private: + uint8 _emote; +}; + void AddSC_the_scarlet_enclave_c5() { new npc_highlord_darion_mograine(); RegisterSpellScript(spell_chapter5_light_of_dawn_aura); RegisterSpellScript(spell_chapter5_rebuke); + RegisterSpellScript(spell_chapter5_return_to_capital); } From d68b0913a19c0a63575732607aded30f15b371e0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Jun 2025 18:45:05 +0000 Subject: [PATCH 29/50] chore(DB): import pending files Referenced commit(s): 7c171ae4dcad80e1c4b43bcfe412fe517cf3aae4 --- .../rev_1749974778510353300.sql => db_world/2025_06_21_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1749974778510353300.sql => db_world/2025_06_21_02.sql} (86%) diff --git a/data/sql/updates/pending_db_world/rev_1749974778510353300.sql b/data/sql/updates/db_world/2025_06_21_02.sql similarity index 86% rename from data/sql/updates/pending_db_world/rev_1749974778510353300.sql rename to data/sql/updates/db_world/2025_06_21_02.sql index 4a0409e39..bee78a801 100644 --- a/data/sql/updates/pending_db_world/rev_1749974778510353300.sql +++ b/data/sql/updates/db_world/2025_06_21_02.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_21_01 -> 2025_06_21_02 -- DELETE FROM `spell_script_names` WHERE `spell_id` IN (58552,58533) AND `ScriptName`='spell_chapter5_return_to_capital'; INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES From f30a821b7f0c2a7d832eb36f3dad60d6b10e7718 Mon Sep 17 00:00:00 2001 From: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com> Date: Sat, 21 Jun 2025 23:45:59 +0200 Subject: [PATCH 30/50] fix (DB/Script/Scarlet Enclave) Corrects some spell timers and adds a new spell for Darion Mograine. (#22324) --- .../updates/pending_db_world/Defenders_cd.sql | 11 +++++++++++ .../EasternKingdoms/ScarletEnclave/chapter5.cpp | 16 +++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 data/sql/updates/pending_db_world/Defenders_cd.sql diff --git a/data/sql/updates/pending_db_world/Defenders_cd.sql b/data/sql/updates/pending_db_world/Defenders_cd.sql new file mode 100644 index 000000000..6ebe3df42 --- /dev/null +++ b/data/sql/updates/pending_db_world/Defenders_cd.sql @@ -0,0 +1,11 @@ + +-- Defender of the Light (update comments and edit Holy Wrath cd). +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 29174; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 29174); +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 +(29174, 0, 0, 0, 0, 0, 100, 0, 10000, 20000, 10000, 20000, 0, 0, 11, 53625, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 'Defender of the Light - In Combat - Cast \'Heroic Leap\''), +(29174, 0, 1, 0, 0, 0, 100, 0, 10000, 20000, 10000, 20000, 0, 0, 11, 53643, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Defender of the Light - In Combat - Cast \'Holy Strike\''), +(29174, 0, 2, 0, 0, 0, 100, 0, 10000, 30000, 45000, 60000, 0, 0, 11, 53638, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Defender of the Light - In Combat - Cast \'Holy Wrath\''), +(29174, 0, 3, 0, 0, 0, 100, 0, 10000, 20000, 10000, 20000, 0, 0, 11, 53629, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Defender of the Light - In Combat - Cast \'Uppercut\''), +(29174, 0, 4, 0, 74, 0, 100, 0, 0, 0, 5000, 10000, 20, 0, 11, 29427, 1, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 'Defender of the Light - On Friendly Below 20% Health - Cast \'Holy Light\''); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index f16b774ac..22c76c4d5 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -121,7 +121,7 @@ enum LightOfDawnEncounter EVENT_SPELL_DEATH_STRIKE, EVENT_SPELL_DEATH_EMBRACE, EVENT_SPELL_UNHOLY_BLIGHT, - EVENT_SPELL_TALK, + EVENT_SPELL_DARION_MOD_DAMAGE, // Positioning EVENT_FINISH_FIGHT_1, EVENT_FINISH_FIGHT_2, @@ -253,6 +253,7 @@ enum LightOfDawnSpells SPELL_DEATH_EMBRACE = 53635, SPELL_ICY_TOUCH1 = 49723, SPELL_UNHOLY_BLIGHT = 53640, + SPELL_DARION_MOD_DAMAGE = 53645, // Outro SPELL_THE_LIGHT_OF_DAWN = 53658, @@ -524,7 +525,7 @@ public: events.RescheduleEvent(EVENT_SPELL_DEATH_STRIKE, 8000); events.RescheduleEvent(EVENT_SPELL_DEATH_EMBRACE, 5000); events.RescheduleEvent(EVENT_SPELL_UNHOLY_BLIGHT, 10000); - events.RescheduleEvent(EVENT_SPELL_TALK, 10000); + events.RescheduleEvent(EVENT_SPELL_DARION_MOD_DAMAGE, 500); } void Reset() override @@ -1146,23 +1147,24 @@ public: { case EVENT_SPELL_ANTI_MAGIC_ZONE: DoCast(me, SPELL_ANTI_MAGIC_ZONE1); - events.RescheduleEvent(eventId, 25s, 30s); + events.RescheduleEvent(eventId, 30s, 45s); break; case EVENT_SPELL_DEATH_STRIKE: DoCastVictim(SPELL_DEATH_STRIKE); - events.RescheduleEvent(eventId, 5s, 10s); + events.RescheduleEvent(eventId, 5s, 35s); break; case EVENT_SPELL_DEATH_EMBRACE: DoCastVictim(SPELL_DEATH_EMBRACE); - events.RescheduleEvent(eventId, 15s, 20s); + events.RescheduleEvent(eventId, 45s, 60s); break; case EVENT_SPELL_UNHOLY_BLIGHT: DoCast(me, SPELL_UNHOLY_BLIGHT); events.RescheduleEvent(eventId, 60s); break; - case EVENT_SPELL_TALK: + case EVENT_SPELL_DARION_MOD_DAMAGE: + DoCast(me, SPELL_DARION_MOD_DAMAGE); Talk(SAY_LIGHT_OF_DAWN09); - events.RescheduleEvent(eventId, 15s, 20s); + events.RescheduleEvent(eventId, 15s, 25s); break; } From 90eb27cd1570113930bacc17fec8c5749acee235 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Jun 2025 21:47:00 +0000 Subject: [PATCH 31/50] chore(DB): import pending files Referenced commit(s): f30a821b7f0c2a7d832eb36f3dad60d6b10e7718 --- .../Defenders_cd.sql => db_world/2025_06_21_03.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/Defenders_cd.sql => db_world/2025_06_21_03.sql} (97%) diff --git a/data/sql/updates/pending_db_world/Defenders_cd.sql b/data/sql/updates/db_world/2025_06_21_03.sql similarity index 97% rename from data/sql/updates/pending_db_world/Defenders_cd.sql rename to data/sql/updates/db_world/2025_06_21_03.sql index 6ebe3df42..8736b1212 100644 --- a/data/sql/updates/pending_db_world/Defenders_cd.sql +++ b/data/sql/updates/db_world/2025_06_21_03.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_21_02 -> 2025_06_21_03 -- Defender of the Light (update comments and edit Holy Wrath cd). UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 29174; From 86f460c0ca4cd1e4d0b79bc2177bf0eafae9ba09 Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Sun, 22 Jun 2025 09:38:09 +0000 Subject: [PATCH 32/50] fix(Scripts/Spell): snapshot %dmg and crit when spreading or refreshing diseases with pestilence (#22306) --- .../game/Spells/Auras/SpellAuraEffects.h | 1 + src/server/scripts/Spells/spell_dk.cpp | 45 +++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 6f0c05a27..7fdf0df91 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -110,6 +110,7 @@ public: uint8 GetCasterLevel() const { return m_casterLevel; } bool CanApplyResilience() const { return m_applyResilience; } float GetPctMods() const { return m_pctMods; } + void SetPctMods(float pctMods) { m_pctMods = pctMods; } // xinef: stacking uint32 GetAuraGroup() const { return m_auraGroup; } diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index cd47823c1..8e27678c0 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -1727,6 +1727,16 @@ class spell_dk_pestilence : public SpellScript { PrepareSpellScript(spell_dk_pestilence); + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DK_GLYPH_OF_DISEASE, + SPELL_DK_BLOOD_PLAGUE, + SPELL_DK_FROST_FEVER + }); + } + void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); @@ -1743,11 +1753,38 @@ class spell_dk_pestilence : public SpellScript // And spread them on target // Blood Plague - if (target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) - caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); + if (Aura* disOld = target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) + if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0)) + { + float pctMods = effOld->GetPctMods(); + float crit = effOld->GetCritChance(); + caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); + + if (Aura* disNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) + if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0)) + { + effNew->SetPctMods(pctMods); + effNew->SetCritChance(crit); + effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster())); + } + } + // Frost Fever - if (target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) - caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); + if (Aura* disOld = target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) + if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0)) + { + float pctMods = effOld->GetPctMods(); + float crit = effOld->GetCritChance(); + caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); + + if (Aura* disNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) + if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0)) + { + effNew->SetPctMods(pctMods); + effNew->SetCritChance(crit); + effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster())); + } + } } } From 94f941731e30fe1276c378399a88eb4ccfe38cce Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Sun, 22 Jun 2025 15:01:53 +0000 Subject: [PATCH 33/50] fix (Core) update comments on unused SpellAttributes (#22343) --- src/server/shared/SharedDefines.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 6d5f6558b..8029bb6aa 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -391,8 +391,8 @@ enum SpellAttr0 : uint32 SPELL_ATTR0_HELD_ITEM_ONLY = 0x00000200, // TITLE Auto-target mainhand item (client only) DESCRIPTION Client will automatically select main-hand item as cast target SPELL_ATTR0_ON_NEXT_SWING = 0x00000400, // TITLE On next melee (type 2) DESCRIPTION Both "on next swing" attributes have identical handling in server & client SPELL_ATTR0_WEARER_CASTS_PROC_TRIGGER = 0x00000800, // TITLE Unknown attribute 11@Attr0 - SPELL_ATTR0_SERVER_ONLY = 0x00001000, // TITLE Only usable during daytime (unused) - SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP = 0x00002000, // TITLE Only usable during nighttime (unused) + SPELL_ATTR0_SERVER_ONLY = 0x00001000, // TITLE Unused attribute 12@Attr0 DESCRIPTION not set in 3.3.5a + SPELL_ATTR0_ALLOW_ITEM_SPELL_IN_PVP = 0x00002000, // TITLE Only usable during nighttime SPELL_ATTR0_ONLY_INDOORS = 0x00004000, // TITLE Only usable indoors SPELL_ATTR0_ONLY_OUTDOORS = 0x00008000, // TITLE Only usable outdoors SPELL_ATTR0_NOT_SHAPESHIFTED = 0x00010000, // TITLE Not usable while shapeshifted @@ -461,14 +461,14 @@ enum SpellAttr2 : uint32 SPELL_ATTR2_AUTO_REPEAT = 0x00000020, // TITLE Ranged auto-attack spell SPELL_ATTR2_CANNOT_CAST_ON_TAPPED = 0x00000040, // TITLE Cannot target others' tapped units DESCRIPTION Can only target untapped units, or those tapped by caster SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE = 0x00000080, // TITLE Unknown attribute 7@Attr2 - SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG = 0x00000100, // TITLE Unknown attribute 8@Attr2 DESCRIPTION not set in 3.0.3 + SPELL_ATTR2_INCLUDE_IN_ADVANCED_COMBAT_LOG = 0x00000100, // TITLE Unused attribute 8@Attr2 DESCRIPTION not set in 3.3.5a SPELL_ATTR2_ALWAYS_CAST_AS_UNIT = 0x00000200, // TITLE Unknown attribute 9@Attr2 SPELL_ATTR2_SPECIAL_TAMING_FLAG = 0x00000400, // TITLE Unknown attribute 10@Attr2 DESCRIPTION Related to taming? SPELL_ATTR2_NO_TARGET_PER_SECOND_COST = 0x00000800, // TITLE Health Funnel SPELL_ATTR2_CHAIN_FROM_CASTER = 0x00001000, // TITLE Unknown attribute 12@Attr2 DESCRIPTION Cleave, Heart Strike, Maul, Sunder Armor, Swipe SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY = 0x00002000, // TITLE Enchant persists when entering arena SPELL_ATTR2_ALLOW_WHILE_INVISIBLE = 0x00004000, // TITLE Unknown attribute 14@Attr2 - SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST = 0x00008000, // TITLE Unknown attribute 15@Attr2 DESCRIPTION not set in 3.0.3 + SPELL_ATTR2_DO_NOT_CONSUME_IF_GAINED_DURING_CAST = 0x00008000, // TITLE Unused attribute 15@Attr2 DESCRIPTION not set in 3.3.5a SPELL_ATTR2_NO_ACTIVE_PETS = 0x00010000, // TITLE Tame Beast SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS = 0x00020000, // TITLE Don't reset swing timer DESCRIPTION Does not reset melee/ranged autoattack timer on cast SPELL_ATTR2_NO_JUMP_WHILE_CAST_PENDING = 0x00040000, // TITLE Requires dead pet @@ -511,8 +511,8 @@ enum SpellAttr3 : uint32 SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death - SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unknown attribute 21@Attr3 - SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Requires equipped Wand (Mainline: Do Not Trigger Target Stand) + SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unused attribute 21@Attr3 DESCRIPTION Not set in 3.3.5a + SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Unused attribute 22@Attr3 DESCRIPTION Not set in 3.3.5a SPELL_ATTR3_NO_DAMAGE_HISTORY = 0x00800000, // TITLE Unknown attribute 23@Attr3 SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON = 0x01000000, // TITLE Requires offhand weapon SPELL_ATTR3_TREAT_AS_PERIODIC = 0x02000000, // TITLE Treat as periodic effect @@ -650,8 +650,8 @@ enum SpellAttr7 : uint32 SPELL_ATTR7_ALLIANCE_SPECIFIC_SPELL = 0x00000200, // TITLE Alliance only SPELL_ATTR7_DISPEL_REMOVES_CHARGES = 0x00000400, // TITLE Dispel/Spellsteal remove individual charges SPELL_ATTR7_CAN_CAUSE_INTERRUPT = 0x00000800, // TITLE Only interrupt non-player casting - SPELL_ATTR7_CAN_CAUSE_SILENCE = 0x00001000, // TITLE Unknown attribute 12@Attr7 DESCRIPTION Not set in 3.2.2a. - SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE = 0x00002000, // TITLE Unknown attribute 13@Attr7 DESCRIPTION Not set in 3.2.2a. + SPELL_ATTR7_CAN_CAUSE_SILENCE = 0x00001000, // TITLE Unused attribute 12@Attr7 DESCRIPTION Not set in 3.3.5a. + SPELL_ATTR7_NO_UI_NOT_INTERRUPTIBLE = 0x00002000, // TITLE Unused attribute 13@Attr7 DESCRIPTION Not set in 3.3.5a. SPELL_ATTR7_RECAST_ON_RESUMMON = 0x00004000, // TITLE Unknown attribute 14@Attr7 DESCRIPTION Only 52150 (Raise Dead - Pet) spell. SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START = 0x00008000, // TITLE Unknown attribute 15@Attr7 DESCRIPTION Exorcism - guaranteed crit vs families? SPELL_ATTR7_ONLY_IN_SPELLBOOK_UNTIL_LEARNED = 0x00010000, // TITLE Can restore secondary power DESCRIPTION Only spells with this attribute can replenish a non-active power type @@ -659,7 +659,7 @@ enum SpellAttr7 : uint32 SPELL_ATTR7_ATTACK_ON_CHARGE_TO_UNIT = 0x00040000, // TITLE Has charge effect SPELL_ATTR7_REPORT_SPELL_FAILURE_TO_UNIT_TARGET = 0x00080000, // TITLE Is zone teleport SPELL_ATTR7_NO_CLIENT_FAIL_WHILE_STUNNED_FLEEING_CONFUSED = 0x00100000, // TITLE Unknown attribute 20@Attr7 DESCRIPTION Invulnerability related? - SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, // TITLE Unknown attribute 21@Attr7 + SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, // TITLE Unused attribute 21@Attr7 DESCRPIPTION Not set in 3.3.5a SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT = 0x00400000, // TITLE Ignore cold weather flying restriction DESCRIPTION Set for loaner mounts, allows them to be used despite lacking required flight skill SPELL_ATTR7_NO_ATTACK_DODGE = 0x00800000, // TITLE Spell cannot be dodged 23@Attr7 DESCRIPTION Motivate, Mutilate, Shattering Throw SPELL_ATTR7_NO_ATTACK_PARRY = 0x01000000, // TITLE Spell cannot be parried 24@Attr7 DESCRIPTION Motivate, Mutilate, Perform Speech, Shattering Throw From 8200f3729e6e0996dc942b03f0b0b7e5cc99fd5f Mon Sep 17 00:00:00 2001 From: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Date: Mon, 23 Jun 2025 02:47:32 +0200 Subject: [PATCH 34/50] fix(Core/SAI): Exclude GMs for player target/event (#22345) --- src/server/game/AI/SmartScripts/SmartScript.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index cbccce1de..0389b79dd 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3707,10 +3707,12 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, if (!units.empty() && baseObject) for (WorldObject* unit : units) - if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist))) + if (IsPlayer(unit) && !unit->ToPlayer()->IsGameMaster() && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist))) targets.push_back(unit); + if (e.target.playerRange.maxCount) Acore::Containers::RandomResize(targets, e.target.playerRange.maxCount); + break; } case SMART_TARGET_PLAYER_DISTANCE: @@ -4664,12 +4666,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!targets.empty()) { for (WorldObject* target : targets) - { - if (IsPlayer(target)) + if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster()) playerCount++; - } - if (playerCount >= e.event.nearPlayer.minCount) - ProcessAction(e, unit); + + if (playerCount >= e.event.nearPlayer.minCount) + ProcessAction(e, unit); } RecalcTimer(e, e.event.nearPlayer.repeatMin, e.event.nearPlayer.repeatMax); break; @@ -4683,10 +4684,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!targets.empty()) { for (WorldObject* target : targets) - { - if (IsPlayer(target)) + if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster()) playerCount++; - } if (playerCount < e.event.nearPlayerNegation.maxCount) ProcessAction(e, unit); From 92094eec01f3618762997bd954114119f102349f Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Mon, 23 Jun 2025 01:51:58 +0000 Subject: [PATCH 35/50] fix(Core/Spell): implement SPELL_ATTR5_NOT_ON_PLAYER and SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC (#22332) --- src/server/game/AI/CoreAI/UnitAI.cpp | 42 ++++++++++++++++++++++++---- src/server/game/Spells/Spell.cpp | 2 ++ src/server/game/Spells/SpellInfo.cpp | 15 ++++++++-- src/server/shared/SharedDefines.h | 2 +- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 8c9b4b9bd..5ec499af0 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -191,8 +191,23 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) { - bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER); - target = SelectTarget(SelectTargetMethod::Random, 0, spellInfo->GetMaxRange(false), playerOnly); + DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0); + target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) { + if (target->IsPlayer()) + { + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return false; + } + else + { + if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)) + return false; + + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer()) + return false; + } + return targetSelector(target); + }); } break; } @@ -206,12 +221,27 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) { - bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER); float range = spellInfo->GetMaxRange(false); - DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId); - if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) - && targetSelector(me->GetVictim())) + DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId); + auto targetSelector = [&](Unit* target) { + if (target->IsPlayer()) + { + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return false; + } + else + { + if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)) + return false; + + if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer()) + return false; + } + return defaultTargetSelector(target); + }; + + if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->GetVictim())) target = me->GetVictim(); else target = SelectTarget(SelectTargetMethod::Random, 0, targetSelector); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 25505c3c4..eadb46eb3 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2147,6 +2147,8 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER; if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS)) retMask &= GRID_MAP_TYPE_MASK_PLAYER; + if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + retMask &= ~GRID_MAP_TYPE_MASK_PLAYER; if (condList) retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index e98c2f0a1..64a25a2b4 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1863,8 +1863,19 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta else return SPELL_CAST_OK; // corpseOwner and unit specific target checks - if (AttributesEx3 & SPELL_ATTR3_ONLY_ON_PLAYER && !unitTarget->ToPlayer()) - return SPELL_FAILED_TARGET_NOT_PLAYER; + if (unitTarget->IsPlayer()) + { + if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) + return SPELL_FAILED_TARGET_IS_PLAYER; + } + else + { + if (HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)) + return SPELL_FAILED_TARGET_NOT_PLAYER; + + if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && unitTarget->IsControlledByPlayer()) + return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED; + } if (!IsAllowingDeadTarget() && !unitTarget->IsAlive()) return SPELL_FAILED_TARGETS_DEAD; diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 8029bb6aa..ce3330770 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -571,7 +571,7 @@ enum SpellAttr5 : uint32 SPELL_ATTR5_TRIGGERS_CHANNELING = 0x00000010, // TITLE Unknown attribute 4@Attr5 SPELL_ATTR5_LIMIT_N = 0x00000020, // TITLE Single-target aura DESCRIPTION Remove previous application to another unit if applied SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK = 0x00000040, // TITLE Unknown attribute 6@Attr5 - SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Unknown attribute 7@Attr5 + SPELL_ATTR5_NOT_ON_PLAYER = 0x00000080, // TITLE Cannot target players SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC = 0x00000100, // TITLE Cannot target player controlled units but can target players SPELL_ATTR5_EXTRA_INITIAL_PERIOD = 0x00000200, // TITLE Immediately do periodic tick on apply SPELL_ATTR5_DO_NOT_DISPLAY_DURATION = 0x00000400, // TITLE Do not send aura duration to client From 8dbde7a588a6ba2190f703ce0f903bc950581562 Mon Sep 17 00:00:00 2001 From: Takenbacon Date: Mon, 23 Jun 2025 05:51:50 -0700 Subject: [PATCH 36/50] fix(Core/Grids): Crash fix (#22347) --- src/server/game/Grids/GridDefines.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 7eabee5cd..eebdb3fd3 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -172,8 +172,8 @@ namespace Acore template inline RET_TYPE Compute(float x, float y, float size) { - int gx = (int)(CENTER_VAL - x / size); - int gy = (int)(CENTER_VAL - y / size); + int gx = std::max(0, (CENTER_VAL - x / size)); + int gy = std::max(0, (CENTER_VAL - y / size)); return RET_TYPE(gx, gy); } From e77f5d63da0680e6afbcaf90562b892dac32eca5 Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Tue, 24 Jun 2025 20:03:45 +0000 Subject: [PATCH 37/50] fix(Core/AI): crashfix(#22352) (#22353) --- src/server/game/AI/CoreAI/UnitAI.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 5ec499af0..25d24a7cd 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -193,6 +193,9 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) { DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0); target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) { + if (!target) + return false; + if (target->IsPlayer()) { if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) @@ -225,6 +228,9 @@ SpellCastResult UnitAI::DoCast(uint32 spellId) DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId); auto targetSelector = [&](Unit* target) { + if (!target) + return false; + if (target->IsPlayer()) { if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER)) From f910147296e3be2816cecd0d7a96606ce0f7a572 Mon Sep 17 00:00:00 2001 From: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:17:59 -0400 Subject: [PATCH 38/50] fix(Core/Movement): Use attack speed for leash reset period and only extend timer if in melee range or can't move freely. (#22350) Co-authored-by: ratkosrb <35845488+ratkosrb@users.noreply.github.com> --- .../game/Entities/Creature/Creature.cpp | 12 ++++++++--- src/server/game/Entities/Creature/Creature.h | 2 ++ .../TargetedMovementGenerator.cpp | 21 +++++++++++-------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index b74f98447..7b2ef3e94 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -788,9 +788,7 @@ void Creature::Update(uint32 diff) m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3); } else - { m_moveBackwardsMovementTime -= diff; - } // Circling the target if (diff >= m_moveCircleMovementTime) @@ -799,9 +797,17 @@ void Creature::Update(uint32 diff) m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2); } else - { m_moveCircleMovementTime -= diff; + + // Periodically check if able to move, if not, extend leash timer + if (diff >= m_extendLeashTime) + { + if (!CanFreeMove()) + UpdateLeashExtensionTime(); + m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL; } + else + m_extendLeashTime -= diff; } // Call for assistance if not disabled diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 092cec299..c66b63e8f 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -396,8 +396,10 @@ public: bool IsFreeToMove(); static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000; static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000; + static constexpr uint32 EXTEND_LEASH_CHECK_INTERVAL = 3000; uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL; uint32 m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL; + uint32 m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL; [[nodiscard]] bool HasSwimmingFlagOutOfCombat() const { diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 96ac2f1f5..7dec2d8ce 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -153,18 +153,20 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) MovementInform(owner); } - if (owner->movespline->Finalized()) - { // Mobs should chase you infinitely if you stop and wait every few seconds. - i_leashExtensionTimer.Update(time_diff); - if (i_leashExtensionTimer.Passed()) - { - i_leashExtensionTimer.Reset(5000); - if (cOwner) + if (cOwner) + { + if (owner->movespline->Finalized() && cOwner->IsWithinMeleeRange(target)) + { // Mobs should chase you infinitely if you stop and wait every few seconds. + i_leashExtensionTimer.Update(time_diff); + if (i_leashExtensionTimer.Passed()) + { + i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK)); cOwner->UpdateLeashExtensionTime(); + } } + else if (i_recalculateTravel) + i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK)); } - else if (i_recalculateTravel) - i_leashExtensionTimer.Reset(5000); // if the target moved, we have to consider whether to adjust if (!_lastTargetPosition || target->GetPosition() != _lastTargetPosition.value() || mutualChase != _mutualChase || !owner->IsWithinLOSInMap(target)) @@ -298,6 +300,7 @@ void ChaseMovementGenerator::DoInitialize(Creature* owner) i_path = nullptr; _lastTargetPosition.reset(); i_recheckDistance.Reset(0); + i_leashExtensionTimer.Reset(owner->GetAttackTime(BASE_ATTACK)); owner->SetWalk(false); owner->AddUnitState(UNIT_STATE_CHASE); } From 0810fa076aa031c9026c899916c30b8c1028ec31 Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Tue, 24 Jun 2025 21:09:38 +0000 Subject: [PATCH 39/50] refactor(Core/AI): rename FarthestTargetSelector to RangeSelector (#22026) --- src/server/game/AI/CoreAI/UnitAI.h | 5 +++-- src/server/game/AI/SmartScripts/SmartScript.cpp | 2 +- .../EasternKingdoms/Karazhan/boss_servant_quarters.cpp | 2 +- .../scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 61d560746..17533d4e4 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -165,9 +165,10 @@ struct PowerUsersSelector : public Acore::unary_function } }; -struct FarthestTargetSelector : public Acore::unary_function +// Simple selector based on range and Los +struct RangeSelector : public Acore::unary_function { - FarthestTargetSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {} + RangeSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {} bool operator()(Unit const* target) const { diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 0389b79dd..730d188a8 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3515,7 +3515,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, case SMART_TARGET_FARTHEST: if (me) { - if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist))) + if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist))) targets.push_back(u); } break; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp index 640201037..ceec78719 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp @@ -74,7 +74,7 @@ struct boss_servant_quarters : public BossAI context.Repeat(12s, 18s); }).Schedule(10s, [this](TaskContext context) { - if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true))) + if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, 40.0f, false, true))) { me->CastSpell(target, SPELL_DIVE); } diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp index 04be10538..863954f0f 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp @@ -213,7 +213,7 @@ struct npc_dark_fiend : public ScriptedAI Unit* target = nullptr; if (InstanceScript* instance = me->GetInstanceScript()) if (Creature* muru = instance->GetCreature(DATA_MURU)) - target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, FarthestTargetSelector(me, 50.0f, true, true)); + target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, RangeSelector(me, 50.0f, true, true)); if (target) { From 36c4de6590f119d5e092b6c36437e2dbda65fb49 Mon Sep 17 00:00:00 2001 From: Vanna White <43800467+wetbrownsauce@users.noreply.github.com> Date: Thu, 26 Jun 2025 05:12:13 -0600 Subject: [PATCH 40/50] fix(CORE/SAI): Properly Implement START_CLOSEST_WAYPOINT (#22256) Co-authored-by: wetbrownsauce --- src/server/game/AI/SmartScripts/SmartScript.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 730d188a8..a620b28d9 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2511,7 +2511,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; }); float distanceToClosest = std::numeric_limits::max(); - WayPoint* closestWp = nullptr; + uint32 closestWpId = 0; for (WorldObject* target : targets) { @@ -2525,23 +2525,24 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!path || path->empty()) continue; - auto itrWp = path->find(0); + //waypoint pointid always starts at 1, never 0! + auto itrWp = path->find(1); if (itrWp != path->end()) { - if (WayPoint* wp = itrWp->second) + if (WayPoint* wpData = itrWp->second) { - float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z); + float distToThisPath = creature->GetExactDistSq(wpData->x, wpData->y, wpData->z); if (distToThisPath < distanceToClosest) { distanceToClosest = distToThisPath; - closestWp = wp; + closestWpId = wp; } } } } - if (closestWp) - CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true); + if (closestWpId) + CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWpId, true); } } } From 67aa3e8e9c462763e7a1067c3f355042823dfbd0 Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Thu, 26 Jun 2025 20:39:48 +0000 Subject: [PATCH 41/50] fix(Script/SWP): unify events that interact with Anveena in P5 Kil'Jaeden (#22366) --- .../EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp index b5aa813db..2858a5cf6 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp @@ -381,14 +381,8 @@ struct boss_kiljaeden : public BossAI if (Creature* anveena = instance->GetCreature(DATA_ANVEENA)) { anveena->RemoveAllAuras(); - anveena->DespawnOrUnsummon(3500); - } - }, 34s); - - me->m_Events.AddEventAtOffset([&] { - if (Creature* anveena = instance->GetCreature(DATA_ANVEENA)) - { anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true); + anveena->DespawnOrUnsummon(1500); DoCastSelf(SPELL_CUSTOM_08_STATE, true); me->SetUnitFlag(UNIT_FLAG_PACIFIED); scheduler.CancelAll(); From e4583eb06f009ca74b859d67fd8af53cb808e02b Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Thu, 26 Jun 2025 21:25:30 -0300 Subject: [PATCH 42/50] =?UTF-8?q?fix(DB/Creature):=20Bound=20Air,=20Fire?= =?UTF-8?q?=20and=20Water=20Elemental=20damage=20and=20immu=E2=80=A6=20(#2?= =?UTF-8?q?2300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../updates/pending_db_world/rev_1749525191796010700.sql | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1749525191796010700.sql diff --git a/data/sql/updates/pending_db_world/rev_1749525191796010700.sql b/data/sql/updates/pending_db_world/rev_1749525191796010700.sql new file mode 100644 index 000000000..a423fcc6a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1749525191796010700.sql @@ -0,0 +1,6 @@ + -- Bound Fire Elemental +UPDATE `creature_template` SET `dmgschool` = 2, `spell_school_immune_mask` = 4 WHERE `entry` IN (30416, 31453); + -- Bound Water Elemental +UPDATE `creature_template` SET `dmgschool` = 4, `spell_school_immune_mask` = 16 WHERE `entry` IN (30419, 31454); + -- Bound Air Elemental +UPDATE `creature_template` SET `dmgschool` = 3, `spell_school_immune_mask` = 8 WHERE `entry` IN (30418, 31452); From e8429688f1aeb65597b2ce90a9b711f9d8cd5fdc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Jun 2025 00:26:27 +0000 Subject: [PATCH 43/50] chore(DB): import pending files Referenced commit(s): e4583eb06f009ca74b859d67fd8af53cb808e02b --- .../rev_1749525191796010700.sql => db_world/2025_06_27_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1749525191796010700.sql => db_world/2025_06_27_00.sql} (90%) diff --git a/data/sql/updates/pending_db_world/rev_1749525191796010700.sql b/data/sql/updates/db_world/2025_06_27_00.sql similarity index 90% rename from data/sql/updates/pending_db_world/rev_1749525191796010700.sql rename to data/sql/updates/db_world/2025_06_27_00.sql index a423fcc6a..7469ad759 100644 --- a/data/sql/updates/pending_db_world/rev_1749525191796010700.sql +++ b/data/sql/updates/db_world/2025_06_27_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_21_03 -> 2025_06_27_00 -- Bound Fire Elemental UPDATE `creature_template` SET `dmgschool` = 2, `spell_school_immune_mask` = 4 WHERE `entry` IN (30416, 31453); -- Bound Water Elemental From ec23669a29f06b03d73dd8307b8660a1931d063c Mon Sep 17 00:00:00 2001 From: Tereneckla Date: Fri, 27 Jun 2025 08:39:26 +0000 Subject: [PATCH 44/50] feature(Scripts/Commands) choose Xth spawn of entry for go creature/gameobject id (#22363) --- .../rev_1750935609519453293.sql | 8 ++ src/server/game/Miscellaneous/Language.h | 3 +- src/server/scripts/Commands/cs_go.cpp | 82 +++++++++++++++++-- 3 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1750935609519453293.sql diff --git a/data/sql/updates/pending_db_world/rev_1750935609519453293.sql b/data/sql/updates/pending_db_world/rev_1750935609519453293.sql new file mode 100644 index 000000000..b9e47eb5a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1750935609519453293.sql @@ -0,0 +1,8 @@ +-- +DELETE FROM `acore_string` WHERE `entry` = 288; +INSERT INTO `acore_string` (`entry`,`content_default`) VALUES (288,'Cannot go to spawn {} as only {} exist'); + +UPDATE `command` SET `help`='Syntax: .go creature id #creature_entry [#spawn] Teleports you to first (if no #spawn provided) spawn the given creature entry. ' WHERE `name` = 'go creature id'; + +DELETE FROM `command` WHERE `name` = 'go gameobject id'; +INSERT INTO `command` VALUES('go gameobject id',1,'Syntax: .go gameobject id #gameobject_entry [#spawn] Teleports you to first (if no #spawn provided) spawn the given gameobject entry.'); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 7de625355..b99ed999b 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -331,7 +331,8 @@ enum AcoreStrings LANG_COMMAND_WHISPERON = 285, LANG_COMMAND_WHISPEROFF = 286, LANG_COMMAND_CREATGUIDNOTFOUND = 287, - // TICKET STRINGS NEED REWRITE // 288-296 FREE + LANG_COMMAND_GONOTENOUGHSPAWNS = 288, + // TICKET STRINGS NEED REWRITE // 289-296 FREE // END LANG_COMMAND_WANDER_DISTANCE = 297, diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index e195fdfc5..0e6bca422 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -86,16 +86,35 @@ public: return true; } - static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant, uint32> cId) + static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant, uint32> cId, Optional _pos) { - CreatureData const* spawnpoint = GetCreatureData(handler, *cId); + uint32 pos = 1; + if (_pos) + { + pos = *_pos; + if (pos < 1) + { + handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos); + return false; + } + } - if (!spawnpoint) + std::vector spawnpoints = GetCreatureDataList(*cId); + + if (spawnpoints.empty()) { handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND); return false; } + if (spawnpoints.size() < pos) + { + handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size()); + return false; + } + + CreatureData const* spawnpoint = spawnpoints[--pos]; + return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid); } @@ -153,16 +172,35 @@ public: return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid); } - static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId) + static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId, Optional _pos) { - GameObjectData const* spawnpoint = GetGameObjectData(handler, goId); + uint32 pos = 1; + if (_pos) + { + pos = *_pos; + if (pos < 1) + { + handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos); + return false; + } + } - if (!spawnpoint) + std::vector spawnpoints = GetGameObjectDataList(goId); + + if (spawnpoints.empty()) { handler->SendErrorMessage(LANG_COMMAND_GOOBJNOTFOUND); return false; } + if (spawnpoints.size() < pos) + { + handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size()); + return false; + } + + GameObjectData const* spawnpoint = spawnpoints[--pos]; + return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid); } @@ -509,6 +547,22 @@ public: return spawnpoint; } + static std::vector GetCreatureDataList(uint32 entry) + { + std::vector spawnpoints; + for (auto const& pair : sObjectMgr->GetAllCreatureData()) + { + if (pair.second.id1 != entry) + { + continue; + } + + spawnpoints.emplace_back(&pair.second); + } + + return spawnpoints; + } + static GameObjectData const* GetGameObjectData(ChatHandler* handler, uint32 entry) { GameObjectData const* spawnpoint = nullptr; @@ -532,6 +586,22 @@ public: return spawnpoint; } + + static std::vector GetGameObjectDataList(uint32 entry) + { + std::vector spawnpoints; + for (auto const& pair : sObjectMgr->GetAllGOData()) + { + if (pair.second.id != entry) + { + continue; + } + + spawnpoints.emplace_back(&pair.second); + } + + return spawnpoints; + } }; void AddSC_go_commandscript() From 69645f37d4a47ec36fbb802b56776752a10b14d8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Jun 2025 08:40:30 +0000 Subject: [PATCH 45/50] chore(DB): import pending files Referenced commit(s): ec23669a29f06b03d73dd8307b8660a1931d063c --- .../rev_1750935609519453293.sql => db_world/2025_06_27_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1750935609519453293.sql => db_world/2025_06_27_01.sql} (93%) diff --git a/data/sql/updates/pending_db_world/rev_1750935609519453293.sql b/data/sql/updates/db_world/2025_06_27_01.sql similarity index 93% rename from data/sql/updates/pending_db_world/rev_1750935609519453293.sql rename to data/sql/updates/db_world/2025_06_27_01.sql index b9e47eb5a..68185b5da 100644 --- a/data/sql/updates/pending_db_world/rev_1750935609519453293.sql +++ b/data/sql/updates/db_world/2025_06_27_01.sql @@ -1,3 +1,4 @@ +-- DB update 2025_06_27_00 -> 2025_06_27_01 -- DELETE FROM `acore_string` WHERE `entry` = 288; INSERT INTO `acore_string` (`entry`,`content_default`) VALUES (288,'Cannot go to spawn {} as only {} exist'); From f01e5d157c0e4b8b6d27ffda6f3776570da9997a Mon Sep 17 00:00:00 2001 From: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Date: Fri, 27 Jun 2025 04:43:05 -0400 Subject: [PATCH 46/50] refactor(Core/Scripting): Forward-declare AuctionEntry as a struct rather than a class. (#22282) --- src/server/game/Scripting/ScriptObjectFwd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Scripting/ScriptObjectFwd.h b/src/server/game/Scripting/ScriptObjectFwd.h index 03494cbb8..dc8036fb6 100644 --- a/src/server/game/Scripting/ScriptObjectFwd.h +++ b/src/server/game/Scripting/ScriptObjectFwd.h @@ -24,7 +24,6 @@ class AchievementGlobalMgr; class AchievementMgr; class ArenaTeam; -class AuctionEntry; class AuctionHouseMgr; class AuctionHouseObject; class Aura; @@ -98,6 +97,7 @@ enum WeatherState : uint32; struct AchievementCriteriaEntry; struct AchievementEntry; struct AreaTrigger; +struct AuctionEntry; struct CompletedAchievementData; struct Condition; struct ConditionSourceInfo; From 5311717a89f3d1382d89c952bd29641d3e1f05cd Mon Sep 17 00:00:00 2001 From: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:14:04 +0200 Subject: [PATCH 47/50] =?UTF-8?q?fix(Player/Skills):=20Improve=20skill=20v?= =?UTF-8?q?alidation=20and=20logging=20in=20Player::=5F=E2=80=A6=20(#22369?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/game/Entities/Player/Player.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 397af904b..799701736 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13631,7 +13631,11 @@ void Player::_LoadSkills(PreparedQueryResult result) SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass()); if (!rcEntry) { - LOG_ERROR("entities.player", "Character {} has skill {} that does not exist.", GetGUID().ToString(), skill); + LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) that is invalid for the race/class combination (Race: {}, Class: {}). Will be deleted.", + GetName(), GetGUID().GetCounter(), skill, getRace(), getClass()); + + // Mark skill for deletion in the database + mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(0, SKILL_DELETED))); continue; } @@ -13652,7 +13656,8 @@ void Player::_LoadSkills(PreparedQueryResult result) if (value == 0) { - LOG_ERROR("entities.player", "Character {} has skill {} with value 0. Will be deleted.", GetGUID().ToString(), skill); + LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) with value 0. Will be deleted.", + GetName(), GetGUID().GetCounter(), skill); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL); From 989b64cb3d9ec66c7e6e7b549ecfdf2b1eb325d6 Mon Sep 17 00:00:00 2001 From: SHIHUANG214 Date: Fri, 27 Jun 2025 21:30:21 +0800 Subject: [PATCH 48/50] feat(Script/Commands): allow to pass email in account create (#22310) Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> --- data/sql/updates/pending_db_world/command.sql | 1 + .../database/Database/Implementation/LoginDatabase.cpp | 2 +- src/server/game/Accounts/AccountMgr.cpp | 8 +++++++- src/server/game/Accounts/AccountMgr.h | 2 +- src/server/scripts/Commands/cs_account.cpp | 7 ++++++- 5 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 data/sql/updates/pending_db_world/command.sql diff --git a/data/sql/updates/pending_db_world/command.sql b/data/sql/updates/pending_db_world/command.sql new file mode 100644 index 000000000..78fd5fab2 --- /dev/null +++ b/data/sql/updates/pending_db_world/command.sql @@ -0,0 +1 @@ +UPDATE `command` SET `help`='Syntax: .account create $account $password $email\r\n\r\nCreate account and set password to it.\r\n$email is optional, can be left blank.' WHERE `name`='account create'; diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 5b001b98c..a772890b5 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -78,7 +78,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, reg_mail, email, joindate) VALUES(?, ?, ?, ?, ?, ?, NOW())", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 2eefbc3ee..daa82f804 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -27,7 +27,7 @@ namespace AccountMgr { - AccountOpResult CreateAccount(std::string username, std::string password) + AccountOpResult CreateAccount(std::string username, std::string password, std::string email /*= ""*/) { if (utf8length(username) > MAX_ACCOUNT_STR) return AOR_NAME_TOO_LONG; // username's too long @@ -35,8 +35,12 @@ namespace AccountMgr if (utf8length(password) > MAX_PASS_STR) return AOR_PASS_TOO_LONG; // password's too long + if (utf8length(email) > MAX_EMAIL_STR) + return AOR_EMAIL_TOO_LONG; // email is too long + Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); if (GetId(username)) return AOR_NAME_ALREADY_EXIST; // username does already exist @@ -48,6 +52,8 @@ namespace AccountMgr stmt->SetData(1, salt); stmt->SetData(2, verifier); stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION))); + stmt->SetData(4, email); + stmt->SetData(5, email); LoginDatabase.Execute(stmt); diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 15af979a6..57b6c7432 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -38,7 +38,7 @@ enum AccountOpResult namespace AccountMgr { - AccountOpResult CreateAccount(std::string username, std::string password); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); AccountOpResult DeleteAccount(uint32 accountId); AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index b69083cb2..22859f019 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -271,10 +271,15 @@ public: ///- %Parse the command line arguments char* accountName = strtok((char*)args, " "); char* password = strtok(nullptr, " "); + char* email = strtok(nullptr, " "); + if (!accountName || !password) return false; - AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password)); + // if email is not specified, use empty string + std::string emailStr = email ? email : ""; + + AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password), emailStr); switch (result) { case AOR_OK: From 732b916a2a6244c4d66709241623ecea6b4b3395 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Jun 2025 13:31:23 +0000 Subject: [PATCH 49/50] chore(DB): import pending files Referenced commit(s): 989b64cb3d9ec66c7e6e7b549ecfdf2b1eb325d6 --- .../{pending_db_world/command.sql => db_world/2025_06_27_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/command.sql => db_world/2025_06_27_02.sql} (81%) diff --git a/data/sql/updates/pending_db_world/command.sql b/data/sql/updates/db_world/2025_06_27_02.sql similarity index 81% rename from data/sql/updates/pending_db_world/command.sql rename to data/sql/updates/db_world/2025_06_27_02.sql index 78fd5fab2..3a34d2643 100644 --- a/data/sql/updates/pending_db_world/command.sql +++ b/data/sql/updates/db_world/2025_06_27_02.sql @@ -1 +1,2 @@ +-- DB update 2025_06_27_01 -> 2025_06_27_02 UPDATE `command` SET `help`='Syntax: .account create $account $password $email\r\n\r\nCreate account and set password to it.\r\n$email is optional, can be left blank.' WHERE `name`='account create'; From d6cf473882f4a8c1f182f3e2da9ddc63e41f87bf Mon Sep 17 00:00:00 2001 From: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com> Date: Fri, 27 Jun 2025 20:07:54 +0200 Subject: [PATCH 50/50] fix (Core/SmartScript) Improve SMART_ACTION_START_CLOSEST_WAYPOINT. (#22364) Co-authored-by: Yehonal --- .../game/AI/SmartScripts/SmartScript.cpp | 14 +++++------ .../game/AI/SmartScripts/SmartScriptMgr.cpp | 23 ++++++++++++------- .../game/AI/SmartScripts/SmartScriptMgr.h | 7 ++++-- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index a620b28d9..b312e1af3 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2506,10 +2506,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_START_CLOSEST_WAYPOINT: { - std::vector waypoints; - std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), - std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; }); - float distanceToClosest = std::numeric_limits::max(); uint32 closestWpId = 0; @@ -2519,13 +2515,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { if (IsSmart(creature)) { - for (uint32 wp : waypoints) + for (uint32 wp = e.action.startClosestWaypoint.pathId1; wp <= e.action.startClosestWaypoint.pathId2; ++wp) { WPPath* path = sSmartWaypointMgr->GetPath(wp); if (!path || path->empty()) continue; - //waypoint pointid always starts at 1, never 0! auto itrWp = path->find(1); if (itrWp != path->end()) { @@ -2542,7 +2537,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } if (closestWpId) - CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWpId, true); + { + bool repeat = e.action.startClosestWaypoint.repeat; + bool run = e.action.startClosestWaypoint.run; + + CAST_AI(SmartAI, creature->AI())->StartPath(repeat, closestWpId, run); + } } } } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 834e48007..0040e0bd3 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -806,7 +806,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_REMOVE_POWER: return sizeof(SmartAction::power); case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop); case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart); - case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList); + case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::startClosestWaypoint); case SMART_ACTION_RISE_UP: return sizeof(SmartAction::moveRandom); case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound); case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay); @@ -1536,15 +1536,22 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) break; } case SMART_ACTION_START_CLOSEST_WAYPOINT: + { + if (e.action.startClosestWaypoint.pathId1 == 0 || e.action.startClosestWaypoint.pathId2 == 0 || e.action.startClosestWaypoint.pathId2 < e.action.startClosestWaypoint.pathId1) { - if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; })) - { - LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id", - e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); - return false; - } - break; + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid pathId1 or pathId2, it must be greater than 0 and pathId1 > pathId2", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; } + if (e.action.startClosestWaypoint.repeat > 1 || e.action.startClosestWaypoint.run > 1) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid run ({}) or repeat ({}) parameter, must be 0 or 1.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), + e.action.startClosestWaypoint.repeat, e.action.startClosestWaypoint.run); + return false; + } + break; + } case SMART_ACTION_INVOKER_CAST: if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type)) { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 994129ecf..4f29d9c51 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1284,8 +1284,11 @@ struct SmartAction struct { - std::array wps; - } closestWaypointFromList; + uint32 pathId1; + uint32 pathId2; + uint32 repeat; + uint32 run; + } startClosestWaypoint; struct {