summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/ee_cc.yml5
-rw-r--r--data/sql/updates/db_world/2025_11_29_00.sql (renamed from data/sql/updates/pending_db_world/rev_1764224411866335544.sql)1
-rw-r--r--data/sql/updates/db_world/2025_11_29_01.sql8
-rw-r--r--data/sql/updates/db_world/2025_11_29_02.sql5
-rw-r--r--data/sql/updates/db_world/2025_11_29_03.sql3
-rw-r--r--data/sql/updates/db_world/2025_11_30_00.sql8
-rw-r--r--data/sql/updates/db_world/2025_11_30_01.sql3
-rw-r--r--data/sql/updates/db_world/2025_11_30_02.sql6
-rw-r--r--data/sql/updates/db_world/2025_11_30_03.sql8
-rw-r--r--data/sql/updates/db_world/2025_11_30_04.sql4
-rw-r--r--data/sql/updates/db_world/2025_11_30_05.sql4
-rw-r--r--data/sql/updates/db_world/2025_11_30_06.sql8
-rw-r--r--data/sql/updates/db_world/2025_11_30_07.sql90
-rw-r--r--data/sql/updates/db_world/2025_11_30_08.sql18
-rw-r--r--data/sql/updates/db_world/2025_12_01_00.sql3
-rw-r--r--data/sql/updates/db_world/2025_12_01_01.sql124
-rw-r--r--src/common/Utilities/Systemd.cpp59
-rw-r--r--src/common/Utilities/Systemd.h31
-rw-r--r--src/server/apps/worldserver/Main.cpp4
-rw-r--r--src/server/apps/worldserver/worldserver.conf.dist14
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Entities/Player/PlayerUpdates.cpp2
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp9
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp25
-rw-r--r--src/server/game/Spells/SpellInfoCorrections.cpp8
-rw-r--r--src/server/scripts/Northrend/zone_crystalsong_forest.cpp135
-rw-r--r--src/server/scripts/Northrend/zone_howling_fjord.cpp237
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp11
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp24
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp23
-rw-r--r--src/server/shared/Network/AsyncAcceptor.h52
-rw-r--r--src/server/shared/Network/SocketMgr.h4
35 files changed, 726 insertions, 220 deletions
diff --git a/.github/ISSUE_TEMPLATE/ee_cc.yml b/.github/ISSUE_TEMPLATE/ee_cc.yml
index 4ed34e08e0..ad7d6744a6 100644
--- a/.github/ISSUE_TEMPLATE/ee_cc.yml
+++ b/.github/ISSUE_TEMPLATE/ee_cc.yml
@@ -8,5 +8,10 @@ body:
label: Triage
description: |
Paste the issue from ChromieCraft here.
+ value: |
+ Issue linked from CC:
+ Triage Notes:
+ Original Post Below:
+ ---
validations:
required: true
diff --git a/data/sql/updates/pending_db_world/rev_1764224411866335544.sql b/data/sql/updates/db_world/2025_11_29_00.sql
index cee78d2912..bc7f243229 100644
--- a/data/sql/updates/pending_db_world/rev_1764224411866335544.sql
+++ b/data/sql/updates/db_world/2025_11_29_00.sql
@@ -1,3 +1,4 @@
+-- DB update 2025_11_28_08 -> 2025_11_29_00
-- Add creature_text for Eck the Ferocious "grows increasingly crazed" emote
DELETE FROM `creature_text` WHERE `CreatureID` = 29932 AND `GroupID` = 1;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`)
diff --git a/data/sql/updates/db_world/2025_11_29_01.sql b/data/sql/updates/db_world/2025_11_29_01.sql
new file mode 100644
index 0000000000..54434ca272
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_29_01.sql
@@ -0,0 +1,8 @@
+-- DB update 2025_11_29_00 -> 2025_11_29_01
+--
+SET @REPTRASH := 1;
+SET @REPREGULAR := 18;
+SET @REPBOSS := 275;
+UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPTRASH, `RewOnKillRepValue2` = @REPTRASH WHERE `creature_id` IN (30902, 30903);
+UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPREGULAR, `RewOnKillRepValue2` = @REPREGULAR WHERE `creature_id` IN (30901, 30904, 30905, 30915, 30916, 30906, 30913, 30907, 30908, 30909, 30910, 30911, 30912, 30914);
+UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPBOSS, `RewOnKillRepValue2` = @REPBOSS WHERE `creature_id` IN (31558, 31559, 31560, 31561);
diff --git a/data/sql/updates/db_world/2025_11_29_02.sql b/data/sql/updates/db_world/2025_11_29_02.sql
new file mode 100644
index 0000000000..c4da8275c2
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_29_02.sql
@@ -0,0 +1,5 @@
+-- DB update 2025_11_29_01 -> 2025_11_29_02
+--
+UPDATE `quest_template` SET `RewardNextQuest` = 0 WHERE (`ID` = 11287);
+UPDATE `quest_template_addon` SET `NextQuestID` = 0 WHERE (`ID` = 11287);
+UPDATE `quest_template_addon` SET `ExclusiveGroup` = 11287 WHERE `ID` IN (11287, 11286);
diff --git a/data/sql/updates/db_world/2025_11_29_03.sql b/data/sql/updates/db_world/2025_11_29_03.sql
new file mode 100644
index 0000000000..f11598497c
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_29_03.sql
@@ -0,0 +1,3 @@
+-- DB update 2025_11_29_02 -> 2025_11_29_03
+UPDATE `quest_template_addon` SET `PrevQuestID` = 13348 WHERE `ID` = 13359;
+UPDATE `quest_template_addon` SET `PrevQuestID` = 13396 WHERE `ID` = 13398;
diff --git a/data/sql/updates/db_world/2025_11_30_00.sql b/data/sql/updates/db_world/2025_11_30_00.sql
new file mode 100644
index 0000000000..2c17d4fd58
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_00.sql
@@ -0,0 +1,8 @@
+-- DB update 2025_11_29_03 -> 2025_11_30_00
+--
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 1889 AND `source_type` = 0 AND `id` IN (0, 1, 2, 3);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(1889, 0, 0, 0, 1, 0, 100, 0, 1000, 1000, 1000, 1000, 0, 0, 11, 12544, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dalaran Wizard - Out of Combat - Cast \'Frost Armor\''),
+(1889, 0, 1, 0, 0, 0, 100, 0, 0, 0, 3400, 5400, 0, 0, 11, 20792, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Dalaran Wizard - In Combat - Cast \'Frostbolt\''),
+(1889, 0, 2, 0, 106, 0, 100, 0, 12500, 45000, 15000, 45000, 0, 10, 11, 11831, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dalaran Wizard - On Hostile in Range - Cast \'Frost Nova\''),
+(1889, 0, 3, 0, 0, 0, 100, 1, 3000, 5000, 14000, 20000, 0, 0, 11, 4980, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dalaran Wizard - In Combat - Cast \'Quick Frost Ward\' (No Repeat)');
diff --git a/data/sql/updates/db_world/2025_11_30_01.sql b/data/sql/updates/db_world/2025_11_30_01.sql
new file mode 100644
index 0000000000..1d3b995119
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_01.sql
@@ -0,0 +1,3 @@
+-- DB update 2025_11_30_00 -> 2025_11_30_01
+-- Burning to Help doesn't require Sharpening Your Talons
+UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE `ID` = 12683;
diff --git a/data/sql/updates/db_world/2025_11_30_02.sql b/data/sql/updates/db_world/2025_11_30_02.sql
new file mode 100644
index 0000000000..86ab760949
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_02.sql
@@ -0,0 +1,6 @@
+-- DB update 2025_11_30_01 -> 2025_11_30_02
+
+-- Event occours only if a player dismount.
+DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 6) AND (`SourceEntry` = 27587) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 32) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 16) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(22, 6, 27587, 0, 0, 32, 0, 16, 0, 0, 0, 0, 0, '', 'Event occours only if a player dismount.');
diff --git a/data/sql/updates/db_world/2025_11_30_03.sql b/data/sql/updates/db_world/2025_11_30_03.sql
new file mode 100644
index 0000000000..a59af90568
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_03.sql
@@ -0,0 +1,8 @@
+-- DB update 2025_11_30_02 -> 2025_11_30_03
+
+-- Add SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 26523;
+
+DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 26523);
+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
+(26523, 0, 0, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 6000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Forsaken Blight Spreader - On Passenger Removed - Despawn In 6000 ms');
diff --git a/data/sql/updates/db_world/2025_11_30_04.sql b/data/sql/updates/db_world/2025_11_30_04.sql
new file mode 100644
index 0000000000..f2462e6997
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_04.sql
@@ -0,0 +1,4 @@
+-- DB update 2025_11_30_03 -> 2025_11_30_04
+--
+UPDATE `creature_template` SET `lootid` = 29605 WHERE `entry` = 30291;
+DELETE FROM `creature_loot_template` WHERE `Entry` = 30291;
diff --git a/data/sql/updates/db_world/2025_11_30_05.sql b/data/sql/updates/db_world/2025_11_30_05.sql
new file mode 100644
index 0000000000..a8f2539156
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_05.sql
@@ -0,0 +1,4 @@
+-- DB update 2025_11_30_04 -> 2025_11_30_05
+--
+-- Remove the RewardNextQuest, previously: 12070 (Rallying the Troops), link from 12249 (Ursoc, the Bear God)
+UPDATE `quest_template` SET `RewardNextQuest` = 0 WHERE (`ID` = 12249);
diff --git a/data/sql/updates/db_world/2025_11_30_06.sql b/data/sql/updates/db_world/2025_11_30_06.sql
new file mode 100644
index 0000000000..83b9493be3
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_06.sql
@@ -0,0 +1,8 @@
+-- DB update 2025_11_30_05 -> 2025_11_30_06
+--
+-- Judgment Day Comes! should not be available if Honor Above All Else is taken/complete/rewarded
+-- Uses CONDITION_QUESTSTATE (47) with state_mask 74 (2+8+64 = Completed+InProgress+Rewarded)
+DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 19) AND (`SourceEntry` IN (13226, 13227)) AND (`ConditionTypeOrReference` = 47) AND (`ConditionValue1` = 13036);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(19, 0, 13226, 0, 0, 47, 0, 13036, 74, 0, 1, 0, 0, '', 'Judgment Day Comes! - NOT have Honor Above All Else (taken/complete/rewarded)'),
+(19, 0, 13227, 0, 0, 47, 0, 13036, 74, 0, 1, 0, 0, '', 'Judgment Day Comes! - NOT have Honor Above All Else (taken/complete/rewarded)');
diff --git a/data/sql/updates/db_world/2025_11_30_07.sql b/data/sql/updates/db_world/2025_11_30_07.sql
new file mode 100644
index 0000000000..fa6fe98c34
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_07.sql
@@ -0,0 +1,90 @@
+-- DB update 2025_11_30_06 -> 2025_11_30_07
+--
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=-43351 AND `spell_effect`=50167 AND `type`=0;
+
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 43365 AND `ScriptName` = 'spell_the_cleansing_shrine_cast');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 43351 AND (`ScriptName` = 'spell_the_cleansing_cleansing_soul' OR `ScriptName` = 'spell_q11322_q11317_the_cleansing'));
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50217 AND `ScriptName` = 'spell_the_cleansing_mirror_image_script_effect');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50238 AND `ScriptName` = 'spell_the_cleansing_on_death_cast_on_master');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 39823 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 39825 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40201 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40203 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40204 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40205 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40206 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40207 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40208 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40210 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40213 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40217 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40218 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40233 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40252 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 40352 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50014 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50023 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50219 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50221 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50222 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 50223 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 53374 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 60807 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+DELETE FROM `spell_script_names` WHERE (`spell_id` = 60811 AND `ScriptName` = 'spell_gen_whisper_to_controller');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(43365, 'spell_the_cleansing_shrine_cast'),
+(43351, 'spell_the_cleansing_cleansing_soul'),
+(50217, 'spell_the_cleansing_mirror_image_script_effect'),
+(50238, 'spell_the_cleansing_on_death_cast_on_master'),
+(39823, 'spell_gen_whisper_to_controller'),
+(39825, 'spell_gen_whisper_to_controller'),
+(40201, 'spell_gen_whisper_to_controller'),
+(40203, 'spell_gen_whisper_to_controller'),
+(40204, 'spell_gen_whisper_to_controller'),
+(40205, 'spell_gen_whisper_to_controller'),
+(40206, 'spell_gen_whisper_to_controller'),
+(40207, 'spell_gen_whisper_to_controller'),
+(40208, 'spell_gen_whisper_to_controller'),
+(40210, 'spell_gen_whisper_to_controller'),
+(40213, 'spell_gen_whisper_to_controller'),
+(40217, 'spell_gen_whisper_to_controller'),
+(40218, 'spell_gen_whisper_to_controller'),
+(40233, 'spell_gen_whisper_to_controller'),
+(40252, 'spell_gen_whisper_to_controller'),
+(40352, 'spell_gen_whisper_to_controller'),
+(50014, 'spell_gen_whisper_to_controller'),
+(50023, 'spell_gen_whisper_to_controller'),
+(50219, 'spell_gen_whisper_to_controller'),
+(50221, 'spell_gen_whisper_to_controller'),
+(50222, 'spell_gen_whisper_to_controller'),
+(50223, 'spell_gen_whisper_to_controller'),
+(53374, 'spell_gen_whisper_to_controller'),
+(60807, 'spell_gen_whisper_to_controller'),
+(60811, 'spell_gen_whisper_to_controller');
+
+DELETE FROM `creature_text` WHERE `CreatureID` = 27959;
+
+UPDATE `creature_template` SET `ScriptName` = '', `AIName` = 'SmartAI' WHERE `entry` = 27959;
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 27959 AND `source_type` = 0;
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 2795900 AND `source_type` = 9;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`event_param5`,`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
+(27959, 0, 0, 0, 37, 0, 100, 0, 0, 0, 0, 0, 0, 116, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - On Initialize - Set Corpse Delay to 2s'),
+(27959, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 80, 2795900, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - On Respawn - Run Script'),
+(27959, 0, 2, 0, 2, 0, 100, 1, 0, 50, 0, 0, 0, 11, 50222, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Between 0-50% Health - Cast \'The Cleansing: Your Inner Turmoil`s Whisper to Controller - On Health 50%\' (No Repeat)'),
+(27959, 0, 3, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 50223, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - On Just Died - Cast \'The Cleansing: Your Inner Turmoil`s Whisper to Controller - On Death\''),
+(27959, 0, 4, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 50238, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - On Just Died - Cast \'The Cleansing: Your Inner Turmoil`s On Death Cast on Master\''),
+-- It has SPELL_ATTR3_DEATH_PERSISTENT but actually is removed after death, maybe not manually
+-- Kinda odd because it makes creature invisible, but Copy Weapon auras are not removed, so only weapons are visible without body
+(27959, 0, 5, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 28, 50218, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - On Just Died - Remove Aura \'The Cleansing: Your Inner Turmoil`s Mirror Image Aura\''),
+(2795900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 11, 50217, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Cast \'The Cleansing: Script Effect Player Cast Mirror Image\''),
+(2795900, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 11, 41408, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Cast \'Shadowform\''),
+(2795900, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Set Orientation Owner Or Summoner'),
+(2795900, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 11, 50219, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Cast \'The Cleansing: Your Inner Turmoil`s Whisper to Controller - Spawn 01\''),
+(2795900, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Play Emote 1'),
+(2795900, 9, 5, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Set Orientation Owner Or Summoner'),
+(2795900, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 11, 50221, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Cast \'The Cleansing: Your Inner Turmoil`s Whisper to Controller - Spawn 02\''),
+(2795900, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 5, 25, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Play Emote 25'),
+-- Yes, again
+(2795900, 9, 8, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 11, 50217, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Cast \'The Cleansing: Script Effect Player Cast Mirror Image\''),
+(2795900, 9, 9, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 19, 512, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Remove Flags Immune To NPC\'s'),
+(2795900, 9, 10, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Your Inner Turmoil - Actionlist - Start Attacking');
diff --git a/data/sql/updates/db_world/2025_11_30_08.sql b/data/sql/updates/db_world/2025_11_30_08.sql
new file mode 100644
index 0000000000..babbf5e14b
--- /dev/null
+++ b/data/sql/updates/db_world/2025_11_30_08.sql
@@ -0,0 +1,18 @@
+-- DB update 2025_11_30_07 -> 2025_11_30_08
+SET @ITEM = 6995;
+SET @ENTRY = 1055;
+
+-- Creates a reference loot for "Corrupted Kor Gem"
+DELETE FROM `reference_loot_template` WHERE `Entry` = @ENTRY AND `Item` = @ITEM;
+INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, @ITEM, 0, 100, 1, 1, 1, 1, 1, 'Corrupted Kor Gem');
+
+-- Deletes "Corrupted Kor Gem" from every creature's loot
+DELETE FROM `creature_loot_template` WHERE `item` = @ITEM;
+
+-- Adds reference loot for "Corrupted Kor Gem" for each creature below
+DELETE FROM `creature_loot_template` WHERE `Reference` = @ENTRY AND `Entry` IN (4802, 4803, 4805);
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(4802, @ITEM, @ENTRY, 80, 0, 1, 0, 1, 1, 'Blackfathom Tide Priestess - Corrupted Kor Gem'),
+(4803, @ITEM, @ENTRY, 80, 0, 1, 0, 1, 1, 'Blackfathom Oracle - Corrupted Kor Gem'),
+(4805, @ITEM, @ENTRY, 80, 0, 1, 0, 1, 1, 'Blackfathom Sea Witch - Corrupted Kor Gem');
diff --git a/data/sql/updates/db_world/2025_12_01_00.sql b/data/sql/updates/db_world/2025_12_01_00.sql
new file mode 100644
index 0000000000..cdc6629f00
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_01_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2025_11_30_08 -> 2025_12_01_00
+--
+UPDATE `spell_group_stack_rules` SET `stack_rule` = 1 WHERE `group_id` = 1087;
diff --git a/data/sql/updates/db_world/2025_12_01_01.sql b/data/sql/updates/db_world/2025_12_01_01.sql
new file mode 100644
index 0000000000..cdbff3fc43
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_01_01.sql
@@ -0,0 +1,124 @@
+-- DB update 2025_12_01_00 -> 2025_12_01_01
+--
+SET @CGUID:=126834;
+
+-- Remove old '[DND]' bunnies
+DELETE FROM `creature` WHERE `id1` IN (30655, 30640, 30832, 30646, 30651, 30707, 30649, 30749, 30700, 30699, 30690, 31246, 31353, 30589, 30588, 30476, 30559);
+DELETE FROM `creature` WHERE `id1` = 15214 AND `guid` IN (122568, 122569, 122570);
+DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+29;
+INSERT INTO `creature` (`guid`, `id1`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `MovementType`) VALUES
+(@CGUID+0, 30640, 623, 1, 1, 35.03846, 36.06336, 25.11708, 5.288348, 120, 0, 0), -- 30640 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+1, 30640, 623, 1, 1, 6.909693, 9.529325, 20.54005, 2.303835, 120, 0, 0), -- 30640 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+2, 30640, 623, 1, 1, -27.16368, 2.981263, 20.54094, 0.122173, 120, 0, 0), -- 30640 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+3, 30640, 623, 1, 1, -56.31194, 12.39219, 31.00466, 3.281219, 120, 0, 0), -- 30640 (Area: 4537) (possible waypoints or random movement)
+(@CGUID+4, 30646, 623, 1, 1, -30.25571, 31.80029, 12.35424, 1.605703, 120, 0, 0), -- 30646 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+5, 30646, 623, 1, 1, -5.325279, 31.62501, 12.34004, 1.500983, 120, 0, 0), -- 30646 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+6, 30651, 623, 1, 1, -40.68238, 29.21558, 12.33503, 1.919862, 120, 0, 0), -- 30651 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+7, 30651, 623, 1, 1, -17.81335, 32.07878, 12.3449, 1.553343, 120, 0, 0), -- 30651 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+8, 30651, 623, 1, 1, 5.88316, 30.50419, 12.34755, 1.32645, 120, 0, 0), -- 30651 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+9, 30655, 623, 1, 1, 6.662919, 19.23895, 10.05156, 0.5061455, 120, 0, 0), -- 30655 (Area: 4509)
+(@CGUID+10, 30655, 623, 1, 1, -43.53964, 18.66365, 9.692578, 3.246312, 120, 0, 0), -- 30655 (Area: 4509) (possible waypoints or random movement)
+(@CGUID+11, 30559, 623, 1, 1, 38.16154, -0.040522, 40.16801, 4.223697, 120, 0, 0), -- 30559 (Area: 4508) (possible waypoints or random movement)
+(@CGUID+12, 30476, 623, 1, 1, 31.41805, 0.126893, 41.69821, 0.05235988, 120, 0, 0), -- 30476 (Area: 4508) (Auras: 56852 - 56852) (possible waypoints or random movement)
+(@CGUID+13, 31353, 623, 1, 1, -21.7234, 19.33753, 9.687197, 1.64061, 120, 0, 0), -- 31353 (Area: 4509) (Auras: 57726 - 57726)
+(@CGUID+14, 30690, 622, 1, 1, 15.24723, 32.37709, 10.63188, 1.553343, 120, 0, 0), -- 30690 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+15, 30690, 622, 1, 1, -11.22309, 32.91199, 10.55865, 1.58825, 120, 0, 0), -- 30690 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+16, 30649, 622, 1, 1, 4.109683, 19.52689, 34.74765, 3.752458, 120, 0, 0), -- 30649 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+17, 30649, 622, 1, 1, -32.53434, 24.30232, 33.9708, 3.211406, 120, 0, 0), -- 30649 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+18, 30649, 622, 1, 1, 50.99569, 46.95655, 23.41373, 2.583087, 120, 0, 0), -- 30649 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+19, 30649, 622, 1, 1, 2.006737, 15.73845, 9.250069, 3.368485, 120, 0, 0), -- 30649 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+20, 30699, 622, 1, 1, 1.853844, 32.8888, 10.02361, 1.58825, 120, 0, 0), -- 30699 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+21, 30700, 622, 1, 1, -35.66628, 29.43331, 1.87925, 1.745329, 120, 0, 0), -- 30700 (Area: 0) (possible waypoints or random movement)
+(@CGUID+22, 30700, 622, 1, 1, 7.417077, 32.82674, 38.35604, 1.553343, 120, 0, 0), -- 30700 (Area: 0) (possible waypoints or random movement)
+(@CGUID+23, 30700, 622, 1, 1, -55.9708, 28.44186, 18.02501, 2.268928, 120, 0, 0), -- 30700 (Area: 0) (possible waypoints or random movement)
+(@CGUID+24, 30700, 622, 1, 1, 38.76255, 30.09343, 2.308181, 1.134464, 120, 0, 0), -- 30700 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+25, 30707, 622, 1, 1, 19.47087, 27.5296, 10.64527, 1.396263, 120, 0, 0), -- 30707 (Area: 4533) (possible waypoints or random movement)
+(@CGUID+26, 30707, 622, 1, 1, -15.3085, 30.59285, 11.11614, 2.635447, 120, 0, 0), -- 30707 (Area: 0) (possible waypoints or random movement)
+(@CGUID+27, 31353, 622, 1, 1, -7.999845, 17.85185, 35.04856, 2.460914, 120, 0, 0), -- 31353 (Area: 0) (possible waypoints or random movement)
+(@CGUID+28, 30588, 622, 1, 1, -18.10283, -0.042108, 45.31725, 1.762783, 120, 0, 0), -- 30588 (Area: 4533) (Auras: 57424 - 57424) (possible waypoints or random movement)
+(@CGUID+29, 30589, 622, 1, 1, -11.83204, -0.019289, 43.11467, 4.153883, 120, 0, 0); -- 30589 (Area: 4533) (possible waypoints or random movement)
+
+UPDATE `creature_template` SET `flags_extra`= `flags_extra` | 128 WHERE `entry` IN (30690, 30699);
+
+DELETE FROM `creature_addon` WHERE `guid` IN (122568, 122569, 122758, 122777, 124002, 124113);
+
+-- Match existing (A) entry, 'To Icecrown - Airship (H) - Aura - Approach'
+UPDATE `creature_template_addon` SET `auras` = '57424' WHERE (`entry` = 30588);
+
+DELETE FROM `creature_template_movement` WHERE (`CreatureId` IN (30476, 30588));
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
+(30476, 0, 0, 1, 0, 0, 0, 0),
+(30588, 0, 0, 1, 0, 0, 0, 0);
+
+UPDATE `creature_template_addon` SET `auras` = '' WHERE (`entry` IN (30470, 30585));
+DELETE FROM `creature_template_movement` WHERE (`CreatureId` IN (30470, 30585));
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
+(30470, 0, 0, 1, 0, 0, 0, 0),
+(30585, 0, 0, 1, 0, 0, 0, 0);
+
+-- teleport target condition
+DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` IN (56905, 56917, 57420, 57417)) AND (`SourceId` = 0) AND (`ElseGroup` IN (0, 1)) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` IN (30476, 30559, 30588, 30589)) AND (`ConditionValue3` = 0);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 1, 56905, 0, 0, 31, 0, 3, 30476, 0, 0, 0, 0, '', 'target must be [DND] Icecrown Flight To Airship Bunny (A)'),
+(13, 1, 56917, 0, 0, 31, 0, 3, 30559, 0, 0, 0, 0, '', 'target must be [DND] Icecrown Flight To Airship Bunny (A) Teleport Target'),
+(13, 1, 57420, 0, 0, 31, 0, 3, 30588, 0, 0, 0, 0, '', 'target must be [DND] Icecrown Flight To Airship Bunny (H)'),
+(13, 1, 57417, 0, 0, 31, 0, 3, 30589, 0, 0, 0, 0, '', 'target must be [DND] Icecrown Flight To Airship Bunny (H) Teleport Target');
+
+-- dismount trigger condition
+DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 56921) AND (`SourceId` = 0) AND (`ElseGroup` IN (0, 1)) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 3) AND (`ConditionValue2` IN (30470, 30585)) AND (`ConditionValue3` = 0);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(17, 0, 56921, 0, 0, 31, 1, 3, 30470, 0, 0, 0, 0, '', 'target must be Skybreaker Cloudbuster'),
+(17, 0, 56921, 0, 1, 31, 1, 3, 30585, 0, 0, 0, 0, '', 'target must be Hammerhead');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (30476, 30588);
+DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (30476, 30588));
+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
+(30476, 0, 0, 1, 8, 0, 100, 0, 56905, 0, 0, 0, 0, 0, 11, 57554, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Icecrown Flight To Airship Bunny (A) - On Spellhit \'To Icecrown - Player - Aura (A) - Dismount Trigger\' - Cast \'To Icecrown Airship - Teleport to Airship (A) Force Player to Cast\''),
+(30476, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 56921, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Icecrown Flight To Airship Bunny (A) - On Spellhit \'To Icecrown - Player - Aura (A) - Dismount Trigger\' - Cast \'To Icecrown - Aura - Dismount Response\''),
+(30588, 0, 0, 1, 8, 0, 100, 0, 57420, 0, 0, 0, 0, 0, 11, 57556, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Icecrown Flight To Airship Bunny (H) - On Spellhit \'To Icecrown - Player - Aura (A) - Dismount Trigger\' - Cast \'To Icecrown Airship - Teleport to Airship (H) Force Player to Cast\''),
+(30588, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 56921, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Icecrown Flight To Airship Bunny (H) - On Spellhit \'To Icecrown - Player - Aura (A) - Dismount Trigger\' - Cast \'To Icecrown - Aura - Dismount Response\'');
+
+DELETE FROM `waypoints` WHERE `entry` IN (30470, 30585) AND `pointid` BETWEEN 1 AND 18;
+INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES
+(30470, 1, 5818.54, 483.97, 660.0, 'Skybreaker Cloudbuster'),
+(30470, 2, 5810.04, 486.907, 660.167, 'Skybreaker Cloudbuster'),
+(30470, 3, 5827.64, 482.851, 669.25, 'Skybreaker Cloudbuster'),
+(30470, 4, 5845.60, 505.766, 677.9, 'Skybreaker Cloudbuster'),
+(30470, 5, 5865.83, 544.756, 689.667, 'Skybreaker Cloudbuster'),
+(30470, 6, 5897.43, 586.118, 689.667, 'Skybreaker Cloudbuster'),
+(30470, 7, 5936.38, 642.625, 682.418, 'Skybreaker Cloudbuster'),
+(30470, 8, 5954.68, 688.565, 678.141, 'Skybreaker Cloudbuster'),
+(30470, 9, 5987.02, 725.128, 673.53, 'Skybreaker Cloudbuster'),
+(30470, 10, 6055.09, 766.575, 663.057, 'Skybreaker Cloudbuster'),
+(30470, 11, 6077.21, 796.139, 663.057, 'Skybreaker Cloudbuster'),
+(30470, 12, 6089.87, 824.184, 658.753, 'Skybreaker Cloudbuster'),
+(30470, 13, 6119.88, 881.953, 657.474, 'Skybreaker Cloudbuster'),
+(30470, 14, 6187.39, 959.597, 663.057, 'Skybreaker Cloudbuster'),
+(30470, 15, 6346.12, 1060.05, 654.669, 'Skybreaker Cloudbuster'),
+(30470, 16, 6466.61, 1107.18, 653.78, 'Skybreaker Cloudbuster'),
+(30470, 17, 6626.67, 1136.81, 647.084, 'Skybreaker Cloudbuster'),
+(30470, 18, 6733.84, 1153.34, 663.057, 'Skybreaker Cloudbuster'),
+(30585, 1, 5836.95, 475.408, 660.167, 'Hammerhead'),
+(30585, 2, 5835.36, 490.093, 669.25, 'Hammerhead'),
+(30585, 3, 5845.6, 505.766, 677.9, 'Hammerhead'),
+(30585, 4, 5865.83, 544.756, 689.667, 'Hammerhead'),
+(30585, 5, 5897.43, 586.118, 689.667, 'Hammerhead'),
+(30585, 6, 5936.38, 642.625, 682.418, 'Hammerhead'),
+(30585, 7, 5954.68, 688.565, 678.141, 'Hammerhead'),
+(30585, 8, 5987.02, 725.128, 673.53, 'Hammerhead'),
+(30585, 9, 6055.09, 766.575, 663.057, 'Hammerhead'),
+(30585, 10, 6077.21, 796.139, 663.057, 'Hammerhead'),
+(30585, 11, 6089.87, 824.184, 663.057, 'Hammerhead'),
+(30585, 12, 6133.36, 911.233, 642.309, 'Hammerhead'),
+(30585, 13, 6187.39, 959.597, 625.03, 'Hammerhead'),
+(30585, 14, 6346.12, 1060.05, 631.336, 'Hammerhead'),
+(30585, 15, 6466.61, 1107.18, 640.891, 'Hammerhead'),
+(30585, 16, 6626.67, 1136.81, 639.669, 'Hammerhead'),
+(30585, 17, 6733.84, 1153.34, 637.03, 'Hammerhead'),
+(30585, 18, 6835.57, 1203.64, 642.974, 'Hammerhead');
+
+-- TP To Dalaran after 5 minutes
+-- Location copied from 30719 'Teleport to Dalaran'
+DELETE FROM `spell_target_position` WHERE `ID` = 57461 AND `EffectIndex` = 0;
+INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES
+(57461, 0, 571, 5807.75, 588.347, 661.505, 1.663, 0);
diff --git a/src/common/Utilities/Systemd.cpp b/src/common/Utilities/Systemd.cpp
new file mode 100644
index 0000000000..f7c39cfb17
--- /dev/null
+++ b/src/common/Utilities/Systemd.cpp
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information.
+ *
+ * Portions of this file are derived from systemd, licensed under:
+ * - GPL-2.0-or-later (if the original systemd file was GPL-2.0+)
+ * OR
+ * - LGPL-2.1-or-later, relicensed under GPL-2.0-or-later as permitted by LGPL-2.1+
+ *
+ * Original systemd copyright:
+ * Copyright (c) the systemd contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(__linux__)
+#include "Log.h"
+#include "StringConvert.h"
+#include <cstdlib>
+#include <unistd.h>
+#include <string>
+
+int get_listen_fd()
+{
+ char* const listen_pid = std::getenv("LISTEN_PID");
+ char* const listen_fds = std::getenv("LISTEN_FDS");
+ if (!listen_pid || !listen_fds)
+ return 0;
+
+ pid_t pid = Acore::StringTo<int>(listen_pid).value_or(0);
+ if (pid != getpid())
+ return 0;
+
+ int fds = Acore::StringTo<int>(listen_fds).value_or(0);
+ if (fds <= 0)
+ return 0;
+
+ if (fds > 1)
+ LOG_WARN("network", "Multiple file descriptors received from systemd socket activation, only the first will be used");
+
+ return 3;
+}
+#else
+// On non-Linux systems, just return 0 (no socket activation)
+int get_listen_fd()
+{
+ return 0;
+}
+#endif
diff --git a/src/common/Utilities/Systemd.h b/src/common/Utilities/Systemd.h
new file mode 100644
index 0000000000..312345cea1
--- /dev/null
+++ b/src/common/Utilities/Systemd.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information.
+ *
+ * Portions of this file are derived from systemd, licensed under:
+ * - GPL-2.0-or-later (if the original systemd file was GPL-2.0+)
+ * OR
+ * - LGPL-2.1-or-later, relicensed under GPL-2.0-or-later as permitted by LGPL-2.1+
+ *
+ * Original systemd copyright:
+ * Copyright (c) the systemd contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SYSTEMD_H_
+#define _SYSTEMD_H_
+
+int get_listen_fd();
+
+#endif
diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp
index d1c10131b1..511c17e367 100644
--- a/src/server/apps/worldserver/Main.cpp
+++ b/src/server/apps/worldserver/Main.cpp
@@ -48,6 +48,7 @@
#include "SecretMgr.h"
#include "SharedDefines.h"
#include "SteadyTimer.h"
+#include "Systemd.h"
#include "World.h"
#include "WorldSessionMgr.h"
#include "WorldSocket.h"
@@ -406,7 +407,8 @@ int main(int argc, char** argv)
sScriptMgr->OnShutdown();
// set server offline
- LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
+ if (!sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false))
+ LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
LOG_INFO("server.worldserver", "Halting process...");
diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist
index 07945f07f3..089c1911a5 100644
--- a/src/server/apps/worldserver/worldserver.conf.dist
+++ b/src/server/apps/worldserver/worldserver.conf.dist
@@ -398,6 +398,20 @@ Network.TcpNodelay = 1
Network.EnableProxyProtocol = 0
#
+# Network.UseSocketActivation
+# Description: Enable systemd socket activation support for the worldserver.
+# When enabled and the process is started by systemd socket activation,
+# the server will use the socket passed by systemd instead of
+# creating and binding its own listening socket. Disabled by default.
+#
+# When enabled the realm is not automatically set as offline on shutdown.
+#
+# Example: 1 - (Enabled)
+# Default: 0 - (Disabled)
+
+Network.UseSocketActivation = 0
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 8891c8788e..5bcd49fcf3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7647,7 +7647,7 @@ void Player::_ApplyAllItemMods()
if (!proto)
continue;
- ApplyItemDependentAuras(m_items[i], false);
+ ApplyItemDependentAuras(m_items[i], true);
_ApplyItemBonuses(proto, i, true);
WeaponAttackType const attackType = Player::GetAttackBySlot(i);
diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp
index 1d3b5788b3..9a4427ce49 100644
--- a/src/server/game/Entities/Player/PlayerUpdates.cpp
+++ b/src/server/game/Entities/Player/PlayerUpdates.cpp
@@ -701,7 +701,7 @@ void Player::UpdateRating(CombatRating cr)
void Player::UpdateAllRatings()
{
- for (uint cr = 0; cr < MAX_COMBAT_RATING; ++cr)
+ for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index 4e2fd4532a..24c025ac6d 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -157,7 +157,7 @@ bool Player::UpdateStats(Stats stat)
mask |= (*i)->GetMiscValue();
if (mask)
{
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (mask & (1 << rating))
ApplyRatingMod(CombatRating(rating), 0, true);
}
@@ -272,7 +272,7 @@ void Player::UpdateArmor()
float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
- value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
+ value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 817bc25b77..623886eb78 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -628,7 +628,7 @@ void Unit::UpdateSplinePosition()
//if (HasUnitState(UNIT_STATE_CANNOT_TURN))
// loc.orientation = GetOrientation();
- if (IsPlayer())
+ if (IsPlayer() || IsPet())
UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
else
ToCreature()->SetPosition(loc.x, loc.y, loc.z, loc.orientation);
@@ -13465,7 +13465,12 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
if (mechanicMask)
{
- TakenTotalMod *= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, mechanicMask);
+ TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
+ {
+ if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
+ return true;
+ return false;
+ });
}
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 8370ebae57..934bb1c70c 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -219,7 +219,7 @@ enum WeaponAttackType : uint8
MAX_ATTACK
};
-enum CombatRating
+enum CombatRating : uint8
{
CR_WEAPON_SKILL = 0,
CR_DEFENSE_SKILL = 1,
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index a878194589..fb40ce36ac 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -299,6 +299,8 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
plMover->UpdatePosition(dest, true);
+ plMover->SetFallInformation(GameTime::GetGameTime().count(), dest.GetPositionZ());
+
// xinef: teleport pets if they are not unsummoned
if (Pet* pet = plMover->GetPet())
{
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index dcef617a65..7ffb4065f8 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -726,9 +726,12 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
std::list<AuraApplication*> effectApplications;
GetApplicationList(effectApplications);
- for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
- if ((*apptItr)->HasEffect(GetEffIndex()))
- HandleEffect(*apptItr, handleMask, false);
+ for (AuraApplication* aurApp : effectApplications)
+ if (aurApp->HasEffect(GetEffIndex()))
+ {
+ aurApp->GetTarget()->_RegisterAuraEffect(this, false);
+ HandleEffect(aurApp, handleMask, false);
+ }
if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT)
{
@@ -739,9 +742,15 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
CalculateSpellMod();
}
- for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
- if ((*apptItr)->HasEffect(GetEffIndex()))
- HandleEffect(*apptItr, handleMask, true);
+ for (AuraApplication* aurApp : effectApplications)
+ if (aurApp->HasEffect(GetEffIndex()))
+ {
+ if (aurApp->GetRemoveMode() != AURA_REMOVE_NONE)
+ continue;
+
+ aurApp->GetTarget()->_RegisterAuraEffect(this, true);
+ HandleEffect(aurApp, handleMask, true);
+ }
}
void AuraEffect::HandleEffect(AuraApplication* aurApp, uint8 mode, bool apply)
@@ -5105,7 +5114,7 @@ void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool
if (!target->IsPlayer())
return;
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (GetMiscValue() & (1 << rating))
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply);
}
@@ -5121,7 +5130,7 @@ void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mo
return;
// Just recalculate ratings
- for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
+ for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (GetMiscValue() & (1 << rating))
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply);
}
diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp
index ca45356219..0615f39c00 100644
--- a/src/server/game/Spells/SpellInfoCorrections.cpp
+++ b/src/server/game/Spells/SpellInfoCorrections.cpp
@@ -5162,6 +5162,14 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->ProcCharges = 1;
});
+ ApplySpellFix({
+ 56917, // To Icecrown Airship - Teleport to Airship (A)
+ 57417, // To Icecrown Airship - Teleport to Airship (H)
+ }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
+ });
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
index bdf394cad9..645d3c0224 100644
--- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
+++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp
@@ -15,52 +15,100 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "CombatAI.h"
#include "CreatureScript.h"
-#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
-#include "SmartScriptMgr.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
#include "Transport.h"
#include "Vehicle.h"
enum ePreparationsForWar
{
- NPC_HAMMERHEAD = 30585,
- NPC_CLOUDBUSTER = 30470,
- TRANSPORT_ORGRIMS_HAMMER = 192241,
- TRANSPORT_THE_SKYBREAKER = 192242
+ NPC_CLOUDBUSTER = 30470,
+ NPC_HAMMERHEAD = 30585,
+ TRANSPORT_ORGRIMS_HAMMER = 192241,
+ TRANSPORT_THE_SKYBREAKER = 192242,
+ SEAT_PLAYER = 0,
+ SPELL_FLIGHT = 48602,
+ SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A = 56904,
+ SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H = 57419,
+ SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN = 57460,
+ SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA = 57498,
+ POINT_END = 16,
+ SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE = 56921, // unhandled - vehicle casts 50630 on self
+ SPELL_EJECT_ALL_PASSENGERS = 50630,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST = 57554,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST = 57556,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A = 56917,
+ SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H = 57417,
};
-struct npc_preparations_for_war_vehicle : public NullCreatureAI
+struct npc_preparations_for_war_vehicle : public VehicleAI
{
- npc_preparations_for_war_vehicle(Creature* creature) : NullCreatureAI(creature) { }
-
- uint8 pointId;
- uint32 searchForShipTimer;
- uint32 transportEntry;
+ explicit npc_preparations_for_war_vehicle(Creature* creature) : VehicleAI(creature), searchForShipTimer(0), transportEntry(me->GetEntry() == NPC_CLOUDBUSTER ? TRANSPORT_THE_SKYBREAKER : TRANSPORT_ORGRIMS_HAMMER)
+ {
+ if (transportEntry == TRANSPORT_THE_SKYBREAKER)
+ {
+ // 30476 - [DND] Icecrown Flight To Airship Bunny (A)
+ passenger_x = 31.41805;
+ passenger_y = 0.126893;
+ passenger_z = 41.69821;
+ }
+ else // TRANSPORT_ORGRIMS_HAMMER
+ {
+ // 30588 - [DND] Icecrown Flight To Airship Bunny (H)
+ passenger_x = -18.10283;
+ passenger_y = -0.042108;
+ passenger_z = 45.31725;
+ }
+ }
- void InitializeAI() override
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
- me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
+ if (apply)
+ {
+ DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN, true);
+ DoCastSelf(SPELL_FLIGHT, true);
+ DoCastSelf(me->GetEntry() == NPC_CLOUDBUSTER ? SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A : SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H , true);
+ DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA, true);
+ me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
+ }
+ else
+ who->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
+ }
- NullCreatureAI::InitializeAI();
- pointId = 0;
- searchForShipTimer = 0;
- transportEntry = (me->GetEntry() == NPC_HAMMERHEAD ? TRANSPORT_ORGRIMS_HAMMER : TRANSPORT_THE_SKYBREAKER);
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == ESCORT_MOTION_TYPE && id == POINT_END)
+ searchForShipTimer = 3000;
}
- void MovementInform(uint32 type, uint32 /*id*/) override
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
- if (type == ESCORT_MOTION_TYPE)
- if (++pointId == 17) // path size
- searchForShipTimer = 3000;
+ switch (spell->Id)
+ {
+ case SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE:
+ break;
+ case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST:
+ case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST:
+ {
+ uint32 teleportSpell = (spell->Id == SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST)
+ ? SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A
+ : SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H;
+ DoCastSelf(teleportSpell, true); // hack: cast on self to avoid visual glitch on player when ejecting and teleporting on transport
+ DoCastSelf(SPELL_EJECT_ALL_PASSENGERS, true);
+ me->DespawnOrUnsummon(0s);
+ break;
+ }
+ default:
+ break;
+ }
}
void UpdateAI(uint32 diff) override
{
- // horde 7.55f, -0.09, 34.44, 3.13, +20
- // ally 45.18f, 0.03, 40.09, 3.14 +5
-
if (searchForShipTimer)
{
searchForShipTimer += diff;
@@ -68,37 +116,14 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
{
searchForShipTimer = 1;
TransportsContainer const& transports = me->GetMap()->GetAllTransports();
- for (TransportsContainer::const_iterator itr = transports.begin(); itr != transports.end(); ++itr)
+ for (auto const transport : transports)
{
- if ((*itr)->GetEntry() == transportEntry)
+ if (transport->GetEntry() == transportEntry)
{
- float x, y, z;
- if (transportEntry == TRANSPORT_ORGRIMS_HAMMER)
- {
- x = 7.55f;
- y = -0.09f;
- z = 54.44f;
- }
- else
- {
- x = 45.18f;
- y = 0.03f;
- z = 45.09f;
- }
+ float x = passenger_x, y = passenger_y, z = passenger_z;
+ transport->CalculatePassengerPosition(x, y, z);
- (*itr)->CalculatePassengerPosition(x, y, z);
-
- if (me->GetDistance2d(x, y) < 10.0f)
- {
- me->DespawnOrUnsummon(1s);
- if (Vehicle* vehicle = me->GetVehicleKit())
- if (Unit* passenger = vehicle->GetPassenger(0))
- {
- passenger->NearTeleportTo(x, y, z - (transportEntry == TRANSPORT_ORGRIMS_HAMMER ? 19.0f : 4.0f), M_PI);
- passenger->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
- }
- }
- else
+ if (me->GetDistance2d(x, y) > 20.0f) // dismount trigger (56905, 57420) range is 30
me->GetMotionMaster()->MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.f, 0.f, false, false);
break;
}
@@ -106,6 +131,10 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
}
}
}
+private:
+ float passenger_x, passenger_y, passenger_z;
+ uint32 searchForShipTimer;
+ uint32 transportEntry;
};
/*******************************************************
diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp
index fc28598ec2..928a0a71e8 100644
--- a/src/server/scripts/Northrend/zone_howling_fjord.cpp
+++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp
@@ -66,109 +66,6 @@ public:
}
};
-// The cleansing
-enum TurmoilTexts
-{
- SAY_TURMOIL_0 = 0,
- SAY_TURMOIL_1 = 1,
- SAY_TURMOIL_HALF_HP = 2,
- SAY_TURMOIL_DEATH = 3,
-};
-
-class npc_your_inner_turmoil : public CreatureScript
-{
-public:
- npc_your_inner_turmoil() : CreatureScript("npc_your_inner_turmoil") { }
-
- struct npc_your_inner_turmoilAI : public ScriptedAI
- {
- npc_your_inner_turmoilAI(Creature* creature) : ScriptedAI(creature) {}
-
- uint32 timer;
- short phase;
- bool health50;
-
- void Reset() override
- {
- timer = 0;
- phase = 0;
- health50 = false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (timer >= 6000 && phase < 2)
- {
- phase++;
- setphase(phase);
- timer = 0;
- }
-
- timer += diff;
-
- DoMeleeAttackIfReady();
- }
-
- void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
- {
- if (HealthBelowPct(50) && !health50)
- {
- if (TempSummon const* tempSummon = me->ToTempSummon())
- {
- if (WorldObject* summoner = tempSummon->GetSummonerUnit())
- {
- Talk(SAY_TURMOIL_HALF_HP, summoner);
- }
- }
-
- health50 = true;
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (TempSummon const* tempSummon = me->ToTempSummon())
- {
- if (WorldObject* summoner = tempSummon->GetSummonerUnit())
- {
- Talk(SAY_TURMOIL_DEATH, summoner);
- }
- }
- }
-
- void setphase(short newPhase)
- {
- Unit* summoner = me->ToTempSummon() ? me->ToTempSummon()->GetSummonerUnit() : nullptr;
- if (!summoner || !summoner->IsPlayer())
- return;
-
- switch (newPhase)
- {
- case 1:
- Talk(SAY_TURMOIL_0, summoner->ToPlayer());
- return;
- case 2:
- {
- Talk(SAY_TURMOIL_1, summoner->ToPlayer());
- me->SetLevel(summoner->GetLevel());
- me->SetFaction(FACTION_MONSTER);
- if (me->GetExactDist(summoner) < 50.0f)
- {
- me->UpdatePosition(summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ(), 0.0f, true);
- summoner->CastSpell(me, 50218, true); // clone caster
- AttackStart(summoner);
- }
- }
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_your_inner_turmoilAI(creature);
- }
-};
-
/*######
## npc_apothecary_hanes
######*/
@@ -457,13 +354,145 @@ class spell_hawk_hunting : public SpellScript
}
};
+/*######
+## Quest 11317, 11322: The Cleansing
+######*/
+
+enum TheCleansing
+{
+ SPELL_CLEANSING_SOUL = 43351,
+ SPELL_SUMMON_INNER_TURMOIL = 50167,
+ SPELL_RECENT_MEDITATION = 61720,
+ SPELL_MIRROR_IMAGE_AURA = 50218,
+
+ QUEST_THE_CLEANSING_H = 11317,
+ QUEST_THE_CLEANSING_A = 11322
+};
+
+// 43365 - The Cleansing: Shrine Cast
+class spell_the_cleansing_shrine_cast : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_shrine_cast);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_RECENT_MEDITATION, SPELL_CLEANSING_SOUL }) &&
+ sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_H) &&
+ sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_A);
+ }
+
+ SpellCastResult CheckCast()
+ {
+ // Error is correct for quest check but may be not correct for aura and this may be a wrong place to send error
+ if (Player* target = GetExplTargetUnit()->ToPlayer())
+ {
+ if (target->HasAura(SPELL_RECENT_MEDITATION) || (!(target->GetQuestStatus(QUEST_THE_CLEANSING_H) == QUEST_STATUS_INCOMPLETE ||
+ target->GetQuestStatus(QUEST_THE_CLEANSING_A) == QUEST_STATUS_INCOMPLETE)))
+ {
+ Spell::SendCastResult(target, GetSpellInfo(), 0, SPELL_FAILED_FIZZLE);
+ return SPELL_FAILED_FIZZLE;
+ }
+ }
+ return SPELL_CAST_OK;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_CLEANSING_SOUL, true);
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_the_cleansing_shrine_cast::CheckCast);
+ OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_shrine_cast::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 43351 - Cleansing Soul
+class spell_the_cleansing_cleansing_soul : public AuraScript
+{
+ PrepareAuraScript(spell_the_cleansing_cleansing_soul);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_SUMMON_INNER_TURMOIL, SPELL_RECENT_MEDITATION });
+ }
+
+ void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->SetStandState(UNIT_STAND_STATE_SIT);
+ }
+
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->SetStandState(UNIT_STAND_STATE_STAND);
+ target->CastSpell(target, SPELL_SUMMON_INNER_TURMOIL, true);
+ target->CastSpell(target, SPELL_RECENT_MEDITATION, true);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_the_cleansing_cleansing_soul::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_the_cleansing_cleansing_soul::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 50217 - The Cleansing: Script Effect Player Cast Mirror Image
+class spell_the_cleansing_mirror_image_script_effect : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_mirror_image_script_effect);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_MIRROR_IMAGE_AURA });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_MIRROR_IMAGE_AURA, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_mirror_image_script_effect::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 50238 - The Cleansing: Your Inner Turmoil's On Death Cast on Master
+class spell_the_cleansing_on_death_cast_on_master : public SpellScript
+{
+ PrepareSpellScript(spell_the_cleansing_on_death_cast_on_master);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (TempSummon* casterSummon = caster->ToTempSummon())
+ if (Unit* summoner = casterSummon->GetSummonerUnit())
+ summoner->CastSpell(summoner, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_the_cleansing_on_death_cast_on_master::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
void AddSC_howling_fjord()
{
new npc_attracted_reef_bull();
- new npc_your_inner_turmoil();
new npc_apothecary_hanes();
new npc_plaguehound_tracker();
new npc_razael_and_lyana();
RegisterCreatureAI(npc_rodin_lightning_enabler);
RegisterSpellScript(spell_hawk_hunting);
+ RegisterSpellScript(spell_the_cleansing_shrine_cast);
+ RegisterSpellScript(spell_the_cleansing_cleansing_soul);
+ RegisterSpellScript(spell_the_cleansing_mirror_image_script_effect);
+ RegisterSpellScript(spell_the_cleansing_on_death_cast_on_master);
}
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index c6f90e153e..85a12610da 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -443,15 +443,16 @@ class spell_dru_enrage : public AuraScript
void RecalculateBaseArmor()
{
+ // Recalculate modifies the list while we're iterating through it, so let's copy it instead
Unit::AuraEffectList const& auras = GetTarget()->GetAuraEffectsByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
- for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
+ std::vector<AuraEffect*> aurEffs(auras.begin(), auras.end());
+
+ for (AuraEffect* aurEff : aurEffs)
{
- SpellInfo const* spellInfo = (*i)->GetSpellInfo();
+ SpellInfo const* spellInfo = aurEff->GetSpellInfo();
// Dire- / Bear Form (Passive)
if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags.HasFlag(0x0, 0x0, 0x2))
- {
- (*i)->RecalculateAmount();
- }
+ aurEff->RecalculateAmount();
}
}
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index f36f2d2234..38f669693f 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -5673,6 +5673,29 @@ class spell_gen_bm_on : public SpellScript
}
};
+class spell_gen_whisper_to_controller : public SpellScript
+{
+ PrepareSpellScript(spell_gen_whisper_to_controller);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return sObjectMgr->GetBroadcastText(uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()));
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (TempSummon* casterSummon = caster->ToTempSummon())
+ if (Player* target = casterSummon->GetSummonerUnit()->ToPlayer())
+ casterSummon->Unit::Whisper(uint32(GetEffectValue()), target, false);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_whisper_to_controller::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5846,4 +5869,5 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_invis_on);
RegisterSpellScript(spell_gen_bm_on);
RegisterSpellScript(spell_gen_bm_off);
+ RegisterSpellScript(spell_gen_whisper_to_controller);
}
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index 870cc73850..4e1b563333 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -247,28 +247,6 @@ class spell_q10525_vision_guide : public AuraScript
}
};
-class spell_q11322_q11317_the_cleansing : public AuraScript
-{
- PrepareAuraScript(spell_q11322_q11317_the_cleansing)
-
- void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* ar = GetCaster();
- if (ar && ar->ToPlayer())
- {
- if (ar->ToPlayer()->GetQuestStatus(11317) == QUEST_STATUS_INCOMPLETE || ar->ToPlayer()->GetQuestStatus(11322) == QUEST_STATUS_INCOMPLETE)
- ar->SummonCreature(27959, 3032.0f, -5095.0f, 723.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
-
- ar->SetStandState(UNIT_STAND_STATE_SIT);
- }
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_q11322_q11317_the_cleansing::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
-};
-
class spell_q10714_on_spirits_wings : public SpellScript
{
PrepareSpellScript(spell_q10714_on_spirits_wings);
@@ -2499,7 +2477,6 @@ void AddSC_quest_spell_scripts()
RegisterSpellScript(spell_q12014_steady_as_a_rock);
RegisterSpellAndAuraScriptPair(spell_q11026_a11051_banish_the_demons, spell_q11026_a11051_banish_the_demons_aura);
RegisterSpellScript(spell_q10525_vision_guide);
- RegisterSpellScript(spell_q11322_q11317_the_cleansing);
RegisterSpellScript(spell_q10714_on_spirits_wings);
RegisterSpellScript(spell_q10720_the_smallest_creature);
RegisterSpellScript(spell_q13086_last_line_of_defence);
diff --git a/src/server/shared/Network/AsyncAcceptor.h b/src/server/shared/Network/AsyncAcceptor.h
index f91c2ca37e..71c58ed937 100644
--- a/src/server/shared/Network/AsyncAcceptor.h
+++ b/src/server/shared/Network/AsyncAcceptor.h
@@ -20,6 +20,7 @@
#include "IpAddress.h"
#include "Log.h"
+#include "Systemd.h"
#include <atomic>
#include <boost/asio/ip/tcp.hpp>
#include <functional>
@@ -33,10 +34,20 @@ class AsyncAcceptor
public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
- AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
+ AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, bool supportSocketActivation = false) :
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
- _socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); })
+ _socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); }),
+ _supportSocketActivation(supportSocketActivation)
{
+ int const listen_fd = get_listen_fd();
+ if (_supportSocketActivation && listen_fd > 0)
+ {
+ LOG_DEBUG("network", "Using socket from systemd socket activation");
+ boost::system::error_code errorCode;
+ _acceptor.assign(boost::asio::ip::tcp::v4(), listen_fd, errorCode);
+ if (errorCode)
+ LOG_WARN("network", "Failed to assign socket {}", errorCode.message());
+ }
}
template<class T>
@@ -72,27 +83,31 @@ public:
bool Bind()
{
boost::system::error_code errorCode;
- _acceptor.open(_endpoint.protocol(), errorCode);
- if (errorCode)
+ // with socket activation the acceptor is already open and bound
+ if (!_acceptor.is_open())
{
- LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
- return false;
- }
+ _acceptor.open(_endpoint.protocol(), errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
+ return false;
+ }
#if AC_PLATFORM != AC_PLATFORM_WINDOWS
- _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
- if (errorCode)
- {
- LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
- return false;
- }
+ _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
+ return false;
+ }
#endif
- _acceptor.bind(_endpoint, errorCode);
- if (errorCode)
- {
- LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
- return false;
+ _acceptor.bind(_endpoint, errorCode);
+ if (errorCode)
+ {
+ LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
+ return false;
+ }
}
_acceptor.listen(ACORE_MAX_LISTEN_CONNECTIONS, errorCode);
@@ -124,6 +139,7 @@ private:
tcp::socket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
+ bool _supportSocketActivation;
};
template<class T>
diff --git a/src/server/shared/Network/SocketMgr.h b/src/server/shared/Network/SocketMgr.h
index dc0c5e6f5f..085e4e2380 100644
--- a/src/server/shared/Network/SocketMgr.h
+++ b/src/server/shared/Network/SocketMgr.h
@@ -19,6 +19,7 @@
#define SocketMgr_h__
#include "AsyncAcceptor.h"
+#include "Config.h"
#include "Errors.h"
#include "NetworkThread.h"
#include <boost/asio/ip/tcp.hpp>
@@ -42,7 +43,8 @@ public:
std::unique_ptr<AsyncAcceptor> acceptor;
try
{
- acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port);
+ bool supportSocketActivation = sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false);
+ acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port, supportSocketActivation);
}
catch (boost::system::system_error const& err)
{