diff --git a/.github/SECURITY.md b/.github/SECURITY.md
index b55b3cc60..13faf3a07 100644
--- a/.github/SECURITY.md
+++ b/.github/SECURITY.md
@@ -55,15 +55,15 @@ Versions of Ubuntu:
| Ubuntu version | Supported |
| -------------- | ------------------ |
| 20.04 | :white_check_mark: |
-| 18.04 | :white_check_mark: |
+| 18.04 and lower| :red_circle: |
Versions of macOS:
-| macOS Version | Supported |
-| ------------- | ------------------ |
-| 12 | :white_check_mark: |
-| 11 | :white_check_mark: |
-| 10.15 | :white_check_mark: |
+| macOS Version | Supported |
+| -------------- | ------------------ |
+| 12 | :white_check_mark: |
+| 11 | :white_check_mark: |
+| 10.15 and lower| :red_circle: |
**Note**: We do NOT support any repacks that may or may not have been made based on AzerothCore. Nor do we support any of the releases that are made under AzerothCore.
diff --git a/.github/workflows/core_matrix_build.yml b/.github/workflows/core_matrix_build.yml
index 95732a403..5852c6c17 100644
--- a/.github/workflows/core_matrix_build.yml
+++ b/.github/workflows/core_matrix_build.yml
@@ -4,7 +4,7 @@ on:
branches:
- 'master'
pull_request:
- types: ['labeled', 'labeled', 'opened', 'synchronize', 'reopened']
+ types: ['labeled', 'opened', 'synchronize', 'reopened']
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
@@ -21,10 +21,6 @@ jobs:
compiler: clang12
- os: ubuntu-20.04
compiler: clang11
- - os: ubuntu-18.04
- compiler: clang10
- - os: ubuntu-18.04
- compiler: gcc8
- os: ubuntu-20.04
compiler: gcc # default in 20.04 is gcc 9
- os: ubuntu-20.04
diff --git a/.github/workflows/core_modules_build.yml b/.github/workflows/core_modules_build.yml
index 6db57dcfc..7003d96f9 100644
--- a/.github/workflows/core_modules_build.yml
+++ b/.github/workflows/core_modules_build.yml
@@ -4,7 +4,7 @@ on:
branches:
- 'master'
pull_request:
- types: ['labeled', 'labeled', 'opened', 'synchronize', 'reopened']
+ types: ['labeled', 'opened', 'synchronize', 'reopened']
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml
index 872f6c36f..7ccbf23f9 100644
--- a/.github/workflows/docker_build.yml
+++ b/.github/workflows/docker_build.yml
@@ -4,7 +4,7 @@ on:
branches:
- 'master'
pull_request:
- types: ['labeled', 'labeled', 'opened', 'synchronize', 'reopened']
+ types: ['labeled', 'opened', 'synchronize', 'reopened']
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml
index 92ebfbf6a..5d58a15e6 100644
--- a/.github/workflows/macos_build.yml
+++ b/.github/workflows/macos_build.yml
@@ -4,7 +4,7 @@ on:
branches:
- 'master'
pull_request:
- types: ['labeled', 'labeled', 'opened', 'synchronize', 'reopened']
+ types: ['labeled', 'opened', 'synchronize', 'reopened']
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
@@ -16,7 +16,6 @@ jobs:
fail-fast: false
matrix:
os:
- - macos-10.15
- macos-11
- macos-12
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml
index 43792b754..a57f6d532 100644
--- a/.github/workflows/windows_build.yml
+++ b/.github/workflows/windows_build.yml
@@ -4,7 +4,7 @@ on:
branches:
- 'master'
pull_request:
- types: ['labeled', 'labeled', 'opened', 'synchronize', 'reopened']
+ types: ['labeled', 'opened', 'synchronize', 'reopened']
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref }}, ${{ github.workflow }})
@@ -24,7 +24,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Configure OS
- run: choco install --no-progress openssl boost-msvc-14.3
+ run: |
+ choco install --no-progress openssl
+ choco install --no-progress boost-msvc-14.3 --version=1.79.0
- name: Build
shell: bash
run: |
diff --git a/data/sql/updates/db_characters/2022_08_02_00.sql b/data/sql/updates/db_characters/2022_08_02_00.sql
new file mode 100644
index 000000000..177cfe81f
--- /dev/null
+++ b/data/sql/updates/db_characters/2022_08_02_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_05_24_00 -> 2022_08_02_00
+--
+UPDATE `characters` SET `taxi_path`=CONCAT('0 ', `taxi_path`) WHERE LENGTH(`taxi_path`) > 0;
diff --git a/data/sql/updates/db_characters/2022_08_07_00.sql b/data/sql/updates/db_characters/2022_08_07_00.sql
new file mode 100644
index 000000000..343f886f9
--- /dev/null
+++ b/data/sql/updates/db_characters/2022_08_07_00.sql
@@ -0,0 +1,6 @@
+-- DB update 2022_08_02_00 -> 2022_08_07_00
+--
+ALTER TABLE `character_entry_point`
+ADD COLUMN `taxiPath0` INT UNSIGNED DEFAULT 0 NOT NULL AFTER `joinMapId`,
+ADD COLUMN `taxiPath1` INT UNSIGNED DEFAULT 0 NOT NULL AFTER `taxiPath0`,
+DROP COLUMN `taxiPath`;
diff --git a/data/sql/updates/db_world/2022_07_29_00.sql b/data/sql/updates/db_world/2022_07_29_00.sql
new file mode 100644
index 000000000..bf158f6a4
--- /dev/null
+++ b/data/sql/updates/db_world/2022_07_29_00.sql
@@ -0,0 +1,8 @@
+-- DB update 2022_07_27_04 -> 2022_07_29_00
+--
+UPDATE `creature_template` SET `skinloot` = 14887 WHERE (`entry` IN (14887, 14888, 14889, 14890));
+
+DELETE FROM `skinning_loot_template` WHERE (`Entry` = 14887) AND (`Item` IN (15412, 20381));
+INSERT INTO `skinning_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(14887, 15412, 0, 60, 0, 1, 1, 5, 8, ''),
+(14887, 20381, 0, 40, 0, 1, 1, 3, 5, '');
diff --git a/data/sql/updates/db_world/2022_07_31_00.sql b/data/sql/updates/db_world/2022_07_31_00.sql
new file mode 100644
index 000000000..dc9d0ed5d
--- /dev/null
+++ b/data/sql/updates/db_world/2022_07_31_00.sql
@@ -0,0 +1,7 @@
+-- DB update 2022_07_29_00 -> 2022_07_31_00
+-- Chief Hawkwind
+UPDATE `creature_template` SET `gossip_menu_id`=0, `npcflag`=`npcflag`&~1 WHERE `entry`=2981;
+
+DELETE FROM `quest_greeting` WHERE `ID`=2981;
+INSERT INTO `quest_greeting` (`ID`, `Type`, `GreetEmoteType`, `GreetEmoteDelay`, `Greeting`, `VerifiedBuild`) VALUES
+(2981,0,0,0,"Hail, $c. In my years I have seen many eager tauren who wish to prove their worth to the tribe. It should not be forgotten that eagerness is no substitute for wisdom and experience.",0);
diff --git a/data/sql/updates/db_world/2022_07_31_01.sql b/data/sql/updates/db_world/2022_07_31_01.sql
new file mode 100644
index 000000000..bb4e25120
--- /dev/null
+++ b/data/sql/updates/db_world/2022_07_31_01.sql
@@ -0,0 +1,4 @@
+-- DB update 2022_07_31_00 -> 2022_07_31_01
+--
+/* Movetype and wander distance corrections for Entranceway */
+UPDATE `creature` SET `wander_distance`=2, `MovementType`=1 WHERE `guid` IN (49739, 49740);
diff --git a/data/sql/updates/db_world/2022_07_31_02.sql b/data/sql/updates/db_world/2022_07_31_02.sql
new file mode 100644
index 000000000..d008e7c48
--- /dev/null
+++ b/data/sql/updates/db_world/2022_07_31_02.sql
@@ -0,0 +1,60 @@
+-- DB update 2022_07_31_01 -> 2022_07_31_02
+--
+-- Kum'isha the Collector
+UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=7363;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=7363 AND `source_type`=0;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=736300 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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(7363,0,0,0,20,0,100,0,2521,0,0,0,80,736300,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Quest 'To Serve Kum'isha' Finished - Run Script"),
+(736300,9,0,0,0,0,100,0,0,0,0,0,83,3,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Remove Npc Flag Questgiver+Gossip"),
+(736300,9,1,0,0,0,100,0,0,0,0,0,66,0,0,0,0,0,0,8,0,0,0,0,0,0,1.03552,"Kum'isha the Collector - On Script - Set Orientation"),
+(736300,9,2,0,0,0,100,0,1000,1000,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Say Line 0"),
+(736300,9,3,0,0,0,100,0,0,0,0,0,12,7364,8,0,0,0,0,8,0,0,0,-11359.4,-2977.5,-0.447796,4.13626,"Kum'isha the Collector - On Script - Summon Creature 'Flawless Draenethyst Sphere'"),
+(736300,9,4,0,0,0,100,0,4000,4000,0,0,11,65633,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Cast 'Arcane Cast Visual'"),
+(736300,9,5,0,0,0,100,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Say Line 1"),
+(736300,9,6,0,0,0,100,0,3000,3000,0,0,50,137167,26,0,0,0,0,8,0,0,0,-11359.4,-2977.5,-0.447796,0.185707,"Kum'isha the Collector - On Script - Summon Gameobject 'Nether Rift'"),
+(736300,9,7,0,0,0,100,0,2000,2000,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Say Line 2"),
+(736300,9,8,0,0,0,100,0,0,0,0,0,107,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Summon Group"),
+(736300,9,9,0,0,0,100,0,10000,10000,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Say Line 3"),
+(736300,9,10,0,0,0,100,0,15000,15000,0,0,86,58538,0,19,7364,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Cross Cast 'Arcane Explosion Visual'"),
+(736300,9,11,0,0,0,100,0,500,500,0,0,41,0,0,0,0,0,0,19,7364,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Despawn Creature 'Flawless Draenethyst Sphere'"),
+(736300,9,12,0,0,0,100,0,3000,3000,0,0,1,4,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Say Line 4"),
+(736300,9,13,0,0,0,100,0,0,0,0,0,82,3,0,0,0,0,0,1,0,0,0,0,0,0,0,"Kum'isha the Collector - On Script - Add Npc Flag Questgiver+Gossip"),
+(736300,9,14,0,0,0,100,0,5000,5000,0,0,66,0,0,0,0,0,0,8,0,0,0,0,0,0,2.79076,"Kum'isha the Collector - On Script - Set Orientation");
+
+DELETE FROM `creature_summon_groups` WHERE `summonerId`=7363;
+INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`) VALUES
+(7363,0,1,7401,-11303.2,-2989.65,5.53587,2.83237,8,300000),
+(7363,0,1,7401,-11309.1,-2972.41,8.33972,3.24362,8,300000),
+(7363,0,1,7401,-11317.0,-2978.34,5.48171,3.21221,8,300000),
+(7363,0,1,7401,-11328.8,-2979.58,6.07384,3.19257,8,300000),
+(7363,0,1,7401,-11321.9,-2974.86,7.56403,3.30645,8,300000);
+
+DELETE FROM `creature_text` WHERE `CreatureID`=7363;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(7363,0,0,"%s releases the flawless draenethyst sphere, allowing it to hover before him.",16,0,100,0,0,0,3441,0,"Kum'isha the Collector"),
+(7363,1,0,"%s chants in an unknown tongue.",16,0,100,0,0,0,3442,0,"Kum'isha the Collector"),
+(7363,2,0,"Success, the rift is open!! My brethren, rise and return home! The Outland awaits!",14,0,100,0,0,0,3475,0,"Kum'isha the Collector"),
+(7363,3,0,"Hurry brothers! You must go now! I do not know how much longer the rift will remain open!",12,0,100,0,0,0,3476,0,"Kum'isha the Collector"),
+(7363,4,0,"And now you know why I live in a crater.",12,0,100,0,0,0,3477,0,"Kum'isha the Collector");
+
+DELETE FROM `gossip_menu` WHERE `MenuID`=752 AND `TextID`=1303;
+INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
+(752,1303);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=752;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(14,752,1303,0,0,8,0,2521,0,0,0,0,0,"","Show gossip text 1303 if quest 'To Serve Kum'isha' is rewarded");
+
+-- Draenei Refugee
+UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=7401;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=7401 AND `source_type`=0;
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(7401,0,0,0,54,0,100,0,0,0,0,0,53,0,7401,0,0,0,0,1,0,0,0,0,0,0,0,"Draenei Refugee - Just Summoned - Start Waypoint"),
+(7401,0,1,0,58,0,100,0,0,0,0,0,11,51347,0,0,0,0,0,1,0,0,0,0,0,0,0,"Draenei Refugee - On Waypoint Ended - Cast 'Teleport Visual Only'"),
+(7401,0,2,0,58,0,100,0,0,0,0,0,41,1000,0,0,0,0,0,1,0,0,0,0,0,0,0,"Draenei Refugee - On Waypoint Ended - Despawn after 1 second");
+
+DELETE FROM `waypoints` WHERE `entry`=7401;
+INSERT INTO `waypoints` (`entry`,`pointid`,`position_x`,`position_y`,`position_z`,`point_comment`) VALUES
+(7401,1,-11336.5,-2981.66,2.98413,""),
+(7401,2,-11359.4,-2977.5,-0.447796,"");
diff --git a/data/sql/updates/db_world/2022_08_01_00.sql b/data/sql/updates/db_world/2022_08_01_00.sql
new file mode 100644
index 000000000..df3cd6dd4
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_00.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_07_31_02 -> 2022_08_01_00
+--
+
+UPDATE `creature` SET `position_z`=94.3 WHERE `guid`=34977;
+
diff --git a/data/sql/updates/db_world/2022_08_01_01.sql b/data/sql/updates/db_world/2022_08_01_01.sql
new file mode 100644
index 000000000..32fd72b92
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_01.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_00 -> 2022_08_01_01
+--
+UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id1` IN (11406, 14724, 16013, 22026);
diff --git a/data/sql/updates/db_world/2022_08_01_02.sql b/data/sql/updates/db_world/2022_08_01_02.sql
new file mode 100644
index 000000000..7db25b8a9
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_02.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_01 -> 2022_08_01_02
+-- trainer can learn skills
+UPDATE `creature_template` SET `npcflag`=`npcflag`|1 WHERE `entry` IN (18753,18752,18771);
diff --git a/data/sql/updates/db_world/2022_08_01_03.sql b/data/sql/updates/db_world/2022_08_01_03.sql
new file mode 100644
index 000000000..2956174fe
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_03.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_02 -> 2022_08_01_03
+-- Ghost Mushroom Position
+UPDATE `gameobject` SET `position_x` = 328.167, `position_y` = -3705.581, `position_z` = 107.007 WHERE `guid` = 16425;
diff --git a/data/sql/updates/db_world/2022_08_01_04.sql b/data/sql/updates/db_world/2022_08_01_04.sql
new file mode 100644
index 000000000..7d8c32ac5
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_04.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_03 -> 2022_08_01_04
+-- Marin Noggenfogger
+UPDATE `gossip_menu_option` SET `OptionText`="Yes! I want more of that fabulous Noggenfogger Elixir!", `OptionBroadcastTextID`=3793 WHERE `MenuID`=922 AND `OptionID`=0;
diff --git a/data/sql/updates/db_world/2022_08_01_05.sql b/data/sql/updates/db_world/2022_08_01_05.sql
new file mode 100644
index 000000000..cbfea8e89
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_05.sql
@@ -0,0 +1,15 @@
+-- DB update 2022_08_01_04 -> 2022_08_01_05
+-- Sprinkle
+DELETE FROM `creature_text` WHERE `CreatureID`=7583 AND `GroupID`=3;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(7583,3,0,"Just sit tight while I get this prepared for you!",12,0,100,0,0,0,3661,0,"Sprinkle");
+
+DELETE FROM `smart_scripts` WHERE `entryorguid`=7583 AND `source_type`=0 AND `id`=2;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=758302 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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(7583,0,2,0,20,0,100,0,2641,0,0,0,80,758302,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Quest 'Sprinkle's Secret Ingredient' Finished - Run Script"),
+(758302,9,0,0,0,0,100,0,0,0,0,0,83,2,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Script - Remove Npc Flag Questgiver"),
+(758302,9,1,0,0,0,100,0,0,0,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Script - Say Line 3"),
+(758302,9,2,0,0,0,100,0,1000,1000,0,0,17,69,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Script - Set Emote State 'Usestanding'"),
+(758302,9,3,0,0,0,100,0,6000,6000,0,0,17,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Script - Set Emote State 'None'"),
+(758302,9,4,0,0,0,100,0,0,0,0,0,82,2,0,0,0,0,0,1,0,0,0,0,0,0,0,"Sprinkle - On Script - Add Npc Flag Questgiver");
diff --git a/data/sql/updates/db_world/2022_08_01_06.sql b/data/sql/updates/db_world/2022_08_01_06.sql
new file mode 100644
index 000000000..0f8b595c8
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_06.sql
@@ -0,0 +1,14 @@
+-- DB update 2022_08_01_05 -> 2022_08_01_06
+-- Wooden Outhouse
+DELETE FROM `smart_scripts` WHERE `entryorguid`=173265 AND `source_type`=1 AND `id`=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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(173265,1,4,0,62,0,100,0,2387,0,0,0,0,70,60,0,0,0,0,0,14,47578,173266,0,0,0,0,0,"Wooden Outhouse - On Gossip Option Selected - Respawn Gameobject 'Goodsteel Ledger'");
+
+DELETE FROM `gossip_menu_option` WHERE `MenuID`=2387;
+INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `VerifiedBuild`) VALUES
+(2387,0,0,"Um... sorry to bother you, but could I see Goodsteel's ledger again... if you're not using it.",5410,1,1,2386,0,0);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=2387;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(15,2387,0,0,0,9,0,4450,0,0,0,0,0,"","Show gossip option if quest 'Ledger from Tanaris' is taken"),
+(15,2387,0,0,0,2,0,11727,1,1,1,0,0,"","Show gossip option if player does not have item 'Goodsteel Ledger'");
diff --git a/data/sql/updates/db_world/2022_08_01_07.sql b/data/sql/updates/db_world/2022_08_01_07.sql
new file mode 100644
index 000000000..62644b4ae
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_07.sql
@@ -0,0 +1,139 @@
+-- DB update 2022_08_01_06 -> 2022_08_01_07
+--
+/* Maintenance on ZG Before Bats Part 2: Pooling Part 1 */
+DELETE FROM `creature` WHERE `guid` BETWEEN 91480 AND 91484;
+
+/* Crocolisk Packs: This method can be exported into all Crocolisk Packs, it requires 25 creature entries and 6 pools.
+50% Chance to spawn 5, 10% chance for each location to spawn empty creating a 4 pack
+
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(@GUID+, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+*/
+
+SET @GUID :=61271;
+DELETE FROM `creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+24;
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+-- 5 Pack
+(@GUID+0, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+1, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+2, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+3, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+4, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+-- 4 Pack Missing First
+(@GUID+5, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+6, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+7, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+8, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+-- 4 Pack Missing Second
+(@GUID+9, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+10, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+11, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+12, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+-- 4 Pack Missing Third
+(@GUID+13, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+14, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+15, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+16, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+-- 4 Pack Missing Fourth
+(@GUID+17, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+18, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+19, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+20, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903, -1502.04, 14.7285, 0.400987, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+-- 4 Pack Missing Final
+(@GUID+21, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11903.1, -1490.94, 12.5739, 1.91973, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+22, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11895.3, -1503.19, 15.1803, 5.42918, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+23, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11892.8, -1498.98, 13.7794, 4.75143, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0),
+(@GUID+24, 15043, 0, 0, 309, 0, 0, 1, 1, 0, -11912.7, -1494.4, 12.0913, 3.05153, 7200, 0, 0, 9156, 0, 0, 0, 0, 0, '', 0);
+
+SET @POOL :=469;
+DELETE FROM `pool_template` WHERE `entry` BETWEEN @POOL+0 AND @POOL+6;
+DELETE FROM `pool_creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+24;
+
+INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES
+(@POOL+0, 1, 'ZG Before Bats 4-5 Pack Pool of Zulian Crocs Pool of Pools'),
+(@POOL+1, 5, 'ZG Before Bats 5 Pack of Zulian Crocs 15043 50% 1/6'),
+(@POOL+2, 4, 'ZG Before Bats 4 Pack of Zulian Crocs 15043 10% 2/6'),
+(@POOL+3, 4, 'ZG Before Bats 4 Pack of Zulian Crocs 15043 10% 3/6'),
+(@POOL+4, 4, 'ZG Before Bats 4 Pack of Zulian Crocs 15043 10% 4/6'),
+(@POOL+5, 4, 'ZG Before Bats 4 Pack of Zulian Crocs 15043 10% 5/6'),
+(@POOL+6, 4, 'ZG Before Bats 4 Pack of Zulian Crocs 15043 10% 6/6');
+
+DELETE FROM `pool_pool` WHERE `pool_id` BETWEEN @POOL+0 AND @POOL+6;
+DELETE FROM `pool_pool` WHERE `mother_pool` BETWEEN @POOL+0 AND @POOL+6;
+INSERT INTO `pool_pool` (`pool_id`, `mother_pool`, `chance`, `description`) VALUES
+(@POOL+1, @POOL+0, 50, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1'),
+(@POOL+2, @POOL+0, 10, 'ZG Before Bats 4 Pack of Zulian Crocs 1/5'),
+(@POOL+3, @POOL+0, 10, 'ZG Before Bats 4 Pack of Zulian Crocs 2/5'),
+(@POOL+4, @POOL+0, 10, 'ZG Before Bats 4 Pack of Zulian Crocs 3/5'),
+(@POOL+5, @POOL+0, 10, 'ZG Before Bats 4 Pack of Zulian Crocs 4/5'),
+(@POOL+6, @POOL+0, 10, 'ZG Before Bats 4 Pack of Zulian Crocs 5/5');
+
+INSERT INTO `pool_creature` (`guid`, `pool_entry`, `description`) VALUES
+--
+(@GUID+0, @POOL+1, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1 Croc 1'),
+(@GUID+1, @POOL+1, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1 Croc 2'),
+(@GUID+2, @POOL+1, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1 Croc 3'),
+(@GUID+3, @POOL+1, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1 Croc 4'),
+(@GUID+4, @POOL+1, 'ZG Before Bats 5 Pack of Zulian Crocs 1/1 Croc 5'),
+--
+(@GUID+5, @POOL+2, 'ZG Before Bats 4 Pack of Zulian Crocs 1/5 Croc 1'),
+(@GUID+6, @POOL+2, 'ZG Before Bats 4 Pack of Zulian Crocs 1/5 Croc 2'),
+(@GUID+7, @POOL+2, 'ZG Before Bats 4 Pack of Zulian Crocs 1/5 Croc 3'),
+(@GUID+8, @POOL+2, 'ZG Before Bats 4 Pack of Zulian Crocs 1/5 Croc 4'),
+--
+(@GUID+9, @POOL+3, 'ZG Before Bats 4 Pack of Zulian Crocs 2/5 Croc 1'),
+(@GUID+10, @POOL+3, 'ZG Before Bats 4 Pack of Zulian Crocs 2/5 Croc 2'),
+(@GUID+11, @POOL+3, 'ZG Before Bats 4 Pack of Zulian Crocs 2/5 Croc 3'),
+(@GUID+12, @POOL+3, 'ZG Before Bats 4 Pack of Zulian Crocs 2/5 Croc 4'),
+--
+(@GUID+13, @POOL+4, 'ZG Before Bats 4 Pack of Zulian Crocs 3/5 Croc 1'),
+(@GUID+14, @POOL+4, 'ZG Before Bats 4 Pack of Zulian Crocs 3/5 Croc 2'),
+(@GUID+15, @POOL+4, 'ZG Before Bats 4 Pack of Zulian Crocs 3/5 Croc 3'),
+(@GUID+16, @POOL+4, 'ZG Before Bats 4 Pack of Zulian Crocs 3/5 Croc 4'),
+--
+(@GUID+17, @POOL+5, 'ZG Before Bats 4 Pack of Zulian Crocs 4/5 Croc 1'),
+(@GUID+18, @POOL+5, 'ZG Before Bats 4 Pack of Zulian Crocs 4/5 Croc 2'),
+(@GUID+19, @POOL+5, 'ZG Before Bats 4 Pack of Zulian Crocs 4/5 Croc 3'),
+(@GUID+20, @POOL+5, 'ZG Before Bats 4 Pack of Zulian Crocs 4/5 Croc 4'),
+--
+(@GUID+21, @POOL+6, 'ZG Before Bats 4 Pack of Zulian Crocs 5/5 Croc 1'),
+(@GUID+22, @POOL+6, 'ZG Before Bats 4 Pack of Zulian Crocs 5/5 Croc 2'),
+(@GUID+23, @POOL+6, 'ZG Before Bats 4 Pack of Zulian Crocs 5/5 Croc 3'),
+(@GUID+24, @POOL+6, 'ZG Before Bats 4 Pack of Zulian Crocs 5/5 Croc 4');
+
+DELETE FROM `creature_formations` WHERE `memberGUID` BETWEEN @GUID+0 AND @GUID+24;
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(@GUID+0, @GUID+0, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+1, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+2, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+3, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+4, 0, 0, 3, 0, 0),
+--
+(@GUID+5, @GUID+5, 0, 0, 3, 0, 0),
+(@GUID+5, @GUID+6, 0, 0, 3, 0, 0),
+(@GUID+5, @GUID+7, 0, 0, 3, 0, 0),
+(@GUID+5, @GUID+8, 0, 0, 3, 0, 0),
+--
+(@GUID+9, @GUID+9, 0, 0, 3, 0, 0),
+(@GUID+9, @GUID+10, 0, 0, 3, 0, 0),
+(@GUID+9, @GUID+11, 0, 0, 3, 0, 0),
+(@GUID+9, @GUID+12, 0, 0, 3, 0, 0),
+--
+(@GUID+13, @GUID+13, 0, 0, 3, 0, 0),
+(@GUID+13, @GUID+14, 0, 0, 3, 0, 0),
+(@GUID+13, @GUID+15, 0, 0, 3, 0, 0),
+(@GUID+13, @GUID+16, 0, 0, 3, 0, 0),
+--
+(@GUID+17, @GUID+17, 0, 0, 3, 0, 0),
+(@GUID+17, @GUID+18, 0, 0, 3, 0, 0),
+(@GUID+17, @GUID+19, 0, 0, 3, 0, 0),
+(@GUID+17, @GUID+20, 0, 0, 3, 0, 0),
+--
+(@GUID+21, @GUID+21, 0, 0, 3, 0, 0),
+(@GUID+21, @GUID+22, 0, 0, 3, 0, 0),
+(@GUID+21, @GUID+23, 0, 0, 3, 0, 0),
+(@GUID+21, @GUID+24, 0, 0, 3, 0, 0);
diff --git a/data/sql/updates/db_world/2022_08_01_08.sql b/data/sql/updates/db_world/2022_08_01_08.sql
new file mode 100644
index 000000000..8e5a967e0
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_08.sql
@@ -0,0 +1,97 @@
+-- DB update 2022_08_01_07 -> 2022_08_01_08
+
+SET @GUID :=86939;
+DELETE FROM `creature_formations` WHERE `memberGUID` BETWEEN @GUID+0 AND @GUID+71;
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(@GUID+0, @GUID+0, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+1, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+2, 0, 0, 3, 0, 0),
+
+(@GUID+3, @GUID+3, 0, 0, 3, 0, 0),
+(@GUID+3, @GUID+4, 0, 0, 3, 0, 0),
+(@GUID+3, @GUID+5, 0, 0, 3, 0, 0),
+
+(@GUID+6, @GUID+6, 0, 0, 3, 0, 0),
+(@GUID+6, @GUID+7, 0, 0, 3, 0, 0),
+(@GUID+6, @GUID+8, 0, 0, 3, 0, 0),
+
+(@GUID+9, @GUID+9, 0, 0, 3, 0, 0),
+(@GUID+9, @GUID+10, 0, 0, 3, 0, 0),
+(@GUID+9, @GUID+11, 0, 0, 3, 0, 0),
+
+(@GUID+12, @GUID+12, 0, 0, 3, 0, 0),
+(@GUID+12, @GUID+13, 0, 0, 3, 0, 0),
+(@GUID+12, @GUID+14, 0, 0, 3, 0, 0),
+
+(@GUID+15, @GUID+15, 0, 0, 3, 0, 0),
+(@GUID+15, @GUID+16, 0, 0, 3, 0, 0),
+(@GUID+15, @GUID+17, 0, 0, 3, 0, 0),
+
+(@GUID+18, @GUID+18, 0, 0, 3, 0, 0),
+(@GUID+18, @GUID+19, 0, 0, 3, 0, 0),
+(@GUID+18, @GUID+20, 0, 0, 3, 0, 0),
+
+(@GUID+21, @GUID+21, 0, 0, 3, 0, 0),
+(@GUID+21, @GUID+22, 0, 0, 3, 0, 0),
+(@GUID+21, @GUID+23, 0, 0, 3, 0, 0),
+
+(@GUID+24, @GUID+24, 0, 0, 3, 0, 0),
+(@GUID+24, @GUID+25, 0, 0, 3, 0, 0),
+(@GUID+24, @GUID+26, 0, 0, 3, 0, 0),
+(@GUID+24, @GUID+27, 0, 0, 3, 0, 0),
+
+(@GUID+28, @GUID+28, 0, 0, 3, 0, 0),
+(@GUID+28, @GUID+29, 0, 0, 3, 0, 0),
+(@GUID+28, @GUID+30, 0, 0, 3, 0, 0),
+(@GUID+28, @GUID+31, 0, 0, 3, 0, 0),
+
+(@GUID+32, @GUID+32, 0, 0, 3, 0, 0),
+(@GUID+32, @GUID+33, 0, 0, 3, 0, 0),
+(@GUID+32, @GUID+34, 0, 0, 3, 0, 0),
+(@GUID+32, @GUID+35, 0, 0, 3, 0, 0),
+
+(@GUID+36, @GUID+36, 0, 0, 3, 0, 0),
+(@GUID+36, @GUID+37, 0, 0, 3, 0, 0),
+(@GUID+36, @GUID+38, 0, 0, 3, 0, 0),
+(@GUID+36, @GUID+39, 0, 0, 3, 0, 0),
+
+(@GUID+40, @GUID+40, 0, 0, 3, 0, 0),
+(@GUID+40, @GUID+41, 0, 0, 3, 0, 0),
+(@GUID+40, @GUID+42, 0, 0, 3, 0, 0),
+(@GUID+40, @GUID+43, 0, 0, 3, 0, 0),
+
+(@GUID+44, @GUID+44, 0, 0, 3, 0, 0),
+(@GUID+44, @GUID+45, 0, 0, 3, 0, 0),
+(@GUID+44, @GUID+46, 0, 0, 3, 0, 0),
+(@GUID+44, @GUID+47, 0, 0, 3, 0, 0),
+
+(@GUID+48, @GUID+48, 0, 0, 3, 0, 0),
+(@GUID+48, @GUID+49, 0, 0, 3, 0, 0),
+(@GUID+48, @GUID+50, 0, 0, 3, 0, 0),
+(@GUID+48, @GUID+51, 0, 0, 3, 0, 0),
+
+(@GUID+52, @GUID+52, 0, 0, 3, 0, 0),
+(@GUID+52, @GUID+53, 0, 0, 3, 0, 0),
+(@GUID+52, @GUID+54, 0, 0, 3, 0, 0),
+(@GUID+52, @GUID+55, 0, 0, 3, 0, 0),
+
+(@GUID+56, @GUID+56, 0, 0, 3, 0, 0),
+(@GUID+56, @GUID+57, 0, 0, 3, 0, 0),
+(@GUID+56, @GUID+58, 0, 0, 3, 0, 0),
+(@GUID+56, @GUID+59, 0, 0, 3, 0, 0),
+
+(@GUID+60, @GUID+60, 0, 0, 3, 0, 0),
+(@GUID+60, @GUID+61, 0, 0, 3, 0, 0),
+(@GUID+60, @GUID+62, 0, 0, 3, 0, 0),
+(@GUID+60, @GUID+63, 0, 0, 3, 0, 0),
+
+(@GUID+64, @GUID+64, 0, 0, 3, 0, 0),
+(@GUID+64, @GUID+65, 0, 0, 3, 0, 0),
+(@GUID+64, @GUID+66, 0, 0, 3, 0, 0),
+(@GUID+64, @GUID+67, 0, 0, 3, 0, 0),
+
+(@GUID+68, @GUID+68, 0, 0, 3, 0, 0),
+(@GUID+68, @GUID+69, 0, 0, 3, 0, 0),
+(@GUID+68, @GUID+70, 0, 0, 3, 0, 0),
+(@GUID+68, @GUID+71, 0, 0, 3, 0, 0);
+
diff --git a/data/sql/updates/db_world/2022_08_01_09.sql b/data/sql/updates/db_world/2022_08_01_09.sql
new file mode 100644
index 000000000..e59e3359c
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_09.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_01_08 -> 2022_08_01_09
+--
+UPDATE `creature` SET `wander_distance`=16, `MovementType`=1 WHERE `guid`=21773;
+UPDATE `creature` SET `wander_distance`=18, `MovementType`=1 WHERE `guid`=21774;
+UPDATE `creature` SET `wander_distance`=15, `MovementType`=1 WHERE `guid`=21775;
diff --git a/data/sql/updates/db_world/2022_08_01_10.sql b/data/sql/updates/db_world/2022_08_01_10.sql
new file mode 100644
index 000000000..e27a8b215
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_10.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_09 -> 2022_08_01_10
+-- Undertaker Mordo https://classic.wowhead.com/npc=1568/undertaker-mordo
+UPDATE `creature` SET `position_x` = 1671.89,`position_y` = 1678.29,`position_z` = 120.802, `orientation` = 0.0349066 WHERE `id1` = 1568;
diff --git a/data/sql/updates/db_world/2022_08_01_11.sql b/data/sql/updates/db_world/2022_08_01_11.sql
new file mode 100644
index 000000000..3664b560b
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_11.sql
@@ -0,0 +1,121 @@
+-- DB update 2022_08_01_10 -> 2022_08_01_11
+--
+-- Maintenance on ZG Before Bats Part 4: Pooling Part 3 Standing Bats Pack
+-- Old Locations Pre-work
+DELETE FROM `creature` WHERE `guid` IN (49190, 49191, 49192, 49193);
+DELETE FROM `creature_addon` WHERE `guid` IN (49190, 49191, 49192, 49193);
+
+/* Bat Pack in ZG Bat Rider (14750) should shift spawn positions with 11368 and they agro together as one
+
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(@GUID+, , 0, 0, 309, 0, 0, 1, 1, 0, -11985.9, -1475.85, 79.7788, 1.59486, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+, , 0, 0, 309, 0, 0, 1, 1, 0, -11978.2, -1464.7, 80.1628, 1.46608, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+, , 0, 0, 309, 0, 0, 1, 1, 0, -11988.6, -1467.06, 80.3768, 1.98968, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+, , 0, 0, 309, 0, 0, 1, 1, 0, -11981.1, -1475.36, 79.7364, 0.874606, 7200, 2, 0, 31440, 0, 1, 0, 0, 0, '', 0);
+
+This ZG Bat Rider had a row in creautre_addon--I could not find it anywhere in the sniff so it is not included, however noting it here for historical purposes:
+
+INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
+(XRIDERX, 0, 0, 0, 4097, 0, 0, NULL);
+
+*/
+
+-- Setup and auto-cleanup for pooling, creatures, and formations
+SET @GUID :=56934;
+SET @POOL :=479;
+DELETE FROM `pool_template` WHERE `entry` BETWEEN @POOL+0 AND @POOL+4;
+DELETE FROM `pool_creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+15;
+DELETE FROM `pool_pool` WHERE `pool_id` BETWEEN @POOL+0 AND @POOL+4;
+DELETE FROM `pool_pool` WHERE `mother_pool` BETWEEN @POOL+0 AND @POOL+4;
+DELETE FROM `creature_formations` WHERE `memberGUID` BETWEEN @GUID+0 AND @GUID+15;
+DELETE FROM `creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+15;
+
+-- Insert Creatures
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(@GUID+0, 14750, 0, 0, 309, 0, 0, 1, 1, 0, -11985.9, -1475.85, 79.7788, 1.59486, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+1, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11978.2, -1464.7, 80.1628, 1.46608, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+2, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11988.6, -1467.06, 80.3768, 1.98968, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+3, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11981.1, -1475.36, 79.7364, 0.874606, 7200, 2, 0, 31440, 0, 1, 0, 0, 0, '', 0),
+
+(@GUID+4, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11985.9, -1475.85, 79.7788, 1.59486, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+5, 14750, 0, 0, 309, 0, 0, 1, 1, 0, -11978.2, -1464.7, 80.1628, 1.46608, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+6, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11988.6, -1467.06, 80.3768, 1.98968, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+7, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11981.1, -1475.36, 79.7364, 0.874606, 7200, 2, 0, 31440, 0, 1, 0, 0, 0, '', 0),
+
+(@GUID+8, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11985.9, -1475.85, 79.7788, 1.59486, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+9, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11978.2, -1464.7, 80.1628, 1.46608, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+10, 14750, 0, 0, 309, 0, 0, 1, 1, 0, -11988.6, -1467.06, 80.3768, 1.98968, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+11, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11981.1, -1475.36, 79.7364, 0.874606, 7200, 2, 0, 31440, 0, 1, 0, 0, 0, '', 0),
+
+(@GUID+12, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11985.9, -1475.85, 79.7788, 1.59486, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+13, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11978.2, -1464.7, 80.1628, 1.46608, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+14, 11368, 0, 0, 309, 0, 0, 1, 1, 0, -11988.6, -1467.06, 80.3768, 1.98968, 7200, 2, 0, 5341, 0, 1, 0, 0, 0, '', 0),
+(@GUID+15, 14750, 0, 0, 309, 0, 0, 1, 1, 0, -11981.1, -1475.36, 79.7364, 0.874606, 7200, 2, 0, 31440, 0, 1, 0, 0, 0, '', 0);
+
+-- Insert Pooling
+
+INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES
+(@POOL+0, 1, 'ZG Before Bats Bat Pack Rider Location Shuffle'),
+(@POOL+1, 4, 'ZG Before Bats Bat Pack Loc 1/4'),
+(@POOL+2, 4, 'ZG Before Bats Bat Pack Loc 2/4'),
+(@POOL+3, 4, 'ZG Before Bats Bat Pack Loc 3/4'),
+(@POOL+4, 4, 'ZG Before Bats Bat Pack Loc 4/4');
+
+INSERT INTO `pool_pool` (`pool_id`, `mother_pool`, `chance`, `description`) VALUES
+(@POOL+1, @POOL+0, 25, 'ZG Before Bats Bat Pack Loc 1'),
+(@POOL+2, @POOL+0, 25, 'ZG Before Bats Bat Pack Loc 2'),
+(@POOL+3, @POOL+0, 25, 'ZG Before Bats Bat Pack Loc 3'),
+(@POOL+4, @POOL+0, 25, 'ZG Before Bats Bat Pack Loc 4');
+
+INSERT INTO `pool_creature` (`guid`, `pool_entry`, `description`) VALUES
+
+(@GUID+0, @POOL+1, 'ZG Before Bats Bat Pack Loc 1 Rider'),
+(@GUID+1, @POOL+1, 'ZG Before Bats Bat Pack Loc 1 Bat'),
+(@GUID+2, @POOL+1, 'ZG Before Bats Bat Pack Loc 1 Bat'),
+(@GUID+3, @POOL+1, 'ZG Before Bats Bat Pack Loc 1 Bat'),
+
+(@GUID+4, @POOL+2, 'ZG Before Bats Bat Pack Loc 2 Bat'),
+(@GUID+5, @POOL+2, 'ZG Before Bats Bat Pack Loc 2 Rider'),
+(@GUID+6, @POOL+2, 'ZG Before Bats Bat Pack Loc 2 Bat'),
+(@GUID+7, @POOL+2, 'ZG Before Bats Bat Pack Loc 2 Bat'),
+
+(@GUID+8, @POOL+3, 'ZG Before Bats Bat Pack Loc 3 Bat'),
+(@GUID+9, @POOL+3, 'ZG Before Bats Bat Pack Loc 3 Bat'),
+(@GUID+10, @POOL+3, 'ZG Before Bats Bat Pack Loc 3 Rider'),
+(@GUID+11, @POOL+3, 'ZG Before Bats Bat Pack Loc 3 Bat'),
+
+(@GUID+12, @POOL+4, 'ZG Before Bats Bat Pack Loc 4 Bat'),
+(@GUID+13, @POOL+4, 'ZG Before Bats Bat Pack Loc 4 Bat'),
+(@GUID+14, @POOL+4, 'ZG Before Bats Bat Pack Loc 4 Bat'),
+(@GUID+15, @POOL+4, 'ZG Before Bats Bat Pack Loc 4 Rider');
+
+-- Insert Formations
+
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(@GUID+0, @GUID+0, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+1, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+2, 0, 0, 3, 0, 0),
+(@GUID+0, @GUID+3, 0, 0, 3, 0, 0),
+
+(@GUID+4, @GUID+4, 0, 0, 3, 0, 0),
+(@GUID+4, @GUID+5, 0, 0, 3, 0, 0),
+(@GUID+4, @GUID+6, 0, 0, 3, 0, 0),
+(@GUID+4, @GUID+7, 0, 0, 3, 0, 0),
+
+(@GUID+8, @GUID+8, 0, 0, 3, 0, 0),
+(@GUID+8, @GUID+9, 0, 0, 3, 0, 0),
+(@GUID+8, @GUID+10, 0, 0, 3, 0, 0),
+(@GUID+8, @GUID+11, 0, 0, 3, 0, 0),
+
+(@GUID+12, @GUID+12, 0, 0, 3, 0, 0),
+(@GUID+12, @GUID+13, 0, 0, 3, 0, 0),
+(@GUID+12, @GUID+14, 0, 0, 3, 0, 0),
+(@GUID+12, @GUID+15, 0, 0, 3, 0, 0);
+
+-- Maintenance on ZG Before Bats Part 5: Agro linking via creature_formations
+DELETE FROM `creature_formations` WHERE `memberGUID` IN (49753, 49754, 49096, 49097);
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(49753, 49753, 0, 0, 3, 0, 0),
+(49753, 49754, 0, 0, 3, 0, 0),
+(49753, 49096, 0, 0, 3, 0, 0),
+(49753, 49097, 0, 0, 3, 0, 0);
diff --git a/data/sql/updates/db_world/2022_08_01_12.sql b/data/sql/updates/db_world/2022_08_01_12.sql
new file mode 100644
index 000000000..a07f650b6
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_12.sql
@@ -0,0 +1,11 @@
+-- DB update 2022_08_01_11 -> 2022_08_01_12
+--
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 11831;
+
+DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 11831);
+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
+(11831, 0, 0, 0, 4, 0, 30, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hakkari Witch Doctor - On Aggro - Say Line 0'),
+(11831, 0, 1, 0, 0, 0, 100, 0, 3000, 8000, 5000, 8000, 0, 11, 24053, 4, 32, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hakkari Witch Doctor - In Combat - Cast \'Hex\''),
+(11831, 0, 2, 0, 0, 0, 100, 0, 1000, 3000, 3000, 5000, 0, 11, 17289, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hakkari Witch Doctor - In Combat - Cast \'Shadow Shock\''),
+(11831, 0, 3, 0, 0, 0, 100, 0, 5000, 15000, 5000, 10000, 0, 11, 24054, 1, 32, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hakkari Witch Doctor - In Combat - Cast \'Shrink\''),
+(11831, 0, 4, 0, 0, 0, 100, 1, 7500, 125000, 0, 0, 0, 11, 24052, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hakkari Witch Doctor - In Combat - Cast \'Summon Voodoo Spirit\' (No Repeat)');
diff --git a/data/sql/updates/db_world/2022_08_01_13.sql b/data/sql/updates/db_world/2022_08_01_13.sql
new file mode 100644
index 000000000..fe6baf573
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_13.sql
@@ -0,0 +1,9 @@
+-- DB update 2022_08_01_12 -> 2022_08_01_13
+DELETE FROM `creature` WHERE `guid` IN (161044, 161045, 161046);
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(161044, 1128, 0, 0, 0, 0, 0, 1, 1, 0, -4310.01, -1447.54, 400.56363, 3.93681, 120, 19, 0, 122, 0, 1, 0, 0, 0, '', 0),
+(161045, 1128, 0, 0, 0, 0, 0, 1, 1, 0, -4293.55, -1431.15, 390.08798, 2.1588, 120, 13, 0, 144, 0, 1, 0, 0, 0, '', 0),
+(161046, 1129, 0, 0, 0, 0, 0, 1, 1, 0, -4300.36, -1420.53, 391.496, 5.16617, 120, 0, 0, 144, 0, 0, 0, 0, 0, '', 0);
+
+DELETE FROM `creature_addon` WHERE `guid` = 161046;
+INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES (161046, 0, 0, 1, 0, 0, 0, NULL);
diff --git a/data/sql/updates/db_world/2022_08_01_14.sql b/data/sql/updates/db_world/2022_08_01_14.sql
new file mode 100644
index 000000000..140dd97e4
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_14.sql
@@ -0,0 +1,4 @@
+-- DB update 2022_08_01_13 -> 2022_08_01_14
+--
+UPDATE `creature_template` SET `unit_flags`=`unit_flags`|33554432 WHERE `entry`=14459;
+
diff --git a/data/sql/updates/db_world/2022_08_01_15.sql b/data/sql/updates/db_world/2022_08_01_15.sql
new file mode 100644
index 000000000..612ae20ee
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_15.sql
@@ -0,0 +1,7 @@
+-- DB update 2022_08_01_14 -> 2022_08_01_15
+--
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger` = 25654 AND `spell_effect` = 6608;
+INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
+(25654, 6608, 1, 'Hive\'Zara Tail Lasher: On Tail Lash - Apply Dropped Weapon');
+
+UPDATE `smart_scripts` SET `event_param3`=10900, `event_param4`=23100 WHERE `entryorguid`=15336 AND `source_type`=0 AND `id`=4 AND `link`=0;
diff --git a/data/sql/updates/db_world/2022_08_01_16.sql b/data/sql/updates/db_world/2022_08_01_16.sql
new file mode 100644
index 000000000..05ad28c8d
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_16.sql
@@ -0,0 +1,36 @@
+-- DB update 2022_08_01_15 -> 2022_08_01_16
+--
+-- Maintenance on ZG Before Bats Part 3: Pooling Part 2 Troll Pack before Bat Area
+-- Formations shouldn't be needed on this pack (they agro properly without)
+
+-- Pool Troll pack before Bat area (49120, 49121, 49122) with it's counterpart, (created as 12814, 12815, 12816)
+DELETE FROM `creature` WHERE `guid` BETWEEN 12814 AND 12816;
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(12814, 11831, 0, 0, 309, 0, 0, 1, 1, 1, -12007.2, -1492.45, 82.0241, 1.39626, 7200, 0, 0, 0, 0, 0, 0, 0, 0, '', 0),
+(12815, 11831, 0, 0, 309, 0, 0, 1, 1, 1, -12008.5, -1484.79, 79.1498, 4.87654, 7200, 0, 0, 0, 0, 0, 0, 0, 0, '', 0),
+(12816, 11351, 0, 0, 309, 0, 0, 1, 1, 1, -12004.5, -1483.46, 79.5746, 4.71553, 7200, 0, 0, 0, 0, 0, 0, 0, 0, '', 0);
+
+DELETE FROM `pool_template` WHERE `entry` BETWEEN 476 AND 478;
+DELETE FROM `pool_pool` WHERE `pool_id` BETWEEN 476 AND 478;
+DELETE FROM `pool_pool` WHERE `mother_pool` BETWEEN 476 AND 478;
+DELETE FROM `pool_creature` WHERE `pool_entry` BETWEEN 476 AND 478;
+DELETE FROM `pool_creature` WHERE `guid` IN (49120, 49121, 49122, 12814, 12815, 12816);
+
+
+INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES
+(476, 1, 'ZG Before Bats Troll 3-Pack'),
+(477, 3, 'ZG Before Bats Troll 3-Pack with 2x entry 11831 50% 1/2'),
+(478, 3, 'ZG Before Bats Troll 3-Pack with 2x entry 11351 50% 2/2');
+
+INSERT INTO `pool_pool` (`pool_id`, `mother_pool`, `chance`, `description`) VALUES
+(477, 476, 50, 'ZG Before Bats Troll 3-Pack with 2x entry 11831'),
+(478, 476, 50, 'ZG Before Bats Troll 3-Pack with 2x entry 11351');
+
+INSERT INTO `pool_creature` (`guid`, `pool_entry`, `description`) VALUES
+(12814, 477, 'ZG Before Bats Troll 3-Pack entry 11831'),
+(12815, 477, 'ZG Before Bats Troll 3-Pack entry 11831'),
+(12816, 477, 'ZG Before Bats Troll 3-Pack entry 11351'),
+
+(49120, 478, 'ZG Before Bats Troll 3-Pack entry 11351'),
+(49121, 478, 'ZG Before Bats Troll 3-Pack entry 11351'),
+(49122, 478, 'ZG Before Bats Troll 3-Pack entry 11831');
diff --git a/data/sql/updates/db_world/2022_08_01_17.sql b/data/sql/updates/db_world/2022_08_01_17.sql
new file mode 100644
index 000000000..5546977e4
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_17.sql
@@ -0,0 +1,22 @@
+-- DB update 2022_08_01_16 -> 2022_08_01_17
+--
+DELETE FROM `creature_text` WHERE `CreatureID` = 15320 AND `GroupID` = 0;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration` ,`Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(15320, 0, 0, '%s counterattacks with retaliation.', 16, 0, 100, 0, 0, 0, 11018, 0, 'Hive\'Zara Soldier - On Retaliation');
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15320) AND (`source_type` = 0) AND (`id` IN (0, 1, 2));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(15320, 0, 0, 2, 2, 0, 100, 1, 0, 30, 0, 0, 0, 11, 22857, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Soldier - Between 0-30% Health - Cast \'Retaliation\' (No Repeat)'),
+(15320, 0, 1, 0, 9, 0, 100, 0, 0, 30, 10000, 18200, 0, 11, 25497, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Soldier - Within 0-30 Range - Cast \'Venom Spit\''),
+(15320, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Soldier - Between 0-30% Health - Say Line 0 (No Repeat)');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15344;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15344) AND (`source_type` = 0) AND (`id` IN (0));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(15344, 0, 0, 0, 0, 0, 100, 0, 4850, 18250, 4850, 18250, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Swarmguard Needler - In Combat - Cast \'Cleave\'');
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15387) AND (`source_type` = 0) AND (`id` IN (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`, `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
+(15387, 0, 2, 0, 0, 0, 100, 0, 3600, 14600, 3600, 14600, 0, 11, 10966, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Warrior - In Combat - Cast \'Uppercut\''),
+(15387, 0, 3, 0, 0, 0, 100, 0, 40000, 70000, 40000, 70000, 0, 11, 15588, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Warrior - In Combat - Cast \'Thunderclap\'');
diff --git a/data/sql/updates/db_world/2022_08_01_18.sql b/data/sql/updates/db_world/2022_08_01_18.sql
new file mode 100644
index 000000000..43752e8b2
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_01_18.sql
@@ -0,0 +1,9 @@
+-- DB update 2022_08_01_17 -> 2022_08_01_18
+--
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_crystal_weakness';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(25177, 'spell_crystal_weakness'),
+(25178, 'spell_crystal_weakness'),
+(25180, 'spell_crystal_weakness'),
+(25181, 'spell_crystal_weakness'),
+(25183, 'spell_crystal_weakness');
diff --git a/data/sql/updates/db_world/2022_08_05_00.sql b/data/sql/updates/db_world/2022_08_05_00.sql
new file mode 100644
index 000000000..f68faea28
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_05_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_01_18 -> 2022_08_05_00
+--
+UPDATE `smart_scripts` SET `action_param1` = 0 WHERE `entryorguid` = 2700300 AND `source_type` = 9 AND `id` = 1;
diff --git a/data/sql/updates/db_world/2022_08_06_00.sql b/data/sql/updates/db_world/2022_08_06_00.sql
new file mode 100644
index 000000000..281f834fe
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_06_00.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_05_00 -> 2022_08_06_00
+--
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=28757;
+INSERT INTO `spell_linked_spell` VALUES
+(28757,28758,0,'Stalker\'s Ally');
diff --git a/data/sql/updates/db_world/2022_08_06_01.sql b/data/sql/updates/db_world/2022_08_06_01.sql
new file mode 100644
index 000000000..f5375864f
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_06_01.sql
@@ -0,0 +1,85 @@
+-- DB update 2022_08_06_00 -> 2022_08_06_01
+--
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15391;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15391) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15391, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15391, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 14000, 15000, 0, 11, 19134, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Cast \'Frightening Shout\' (Normal Dungeon)'),
+(15391, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Increment Phase (Normal Dungeon)'),
+(15391, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15391, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15391, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15391, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Qeez - On Aggro - Set Instance Data 1 to 8');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15392;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15392) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15392, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15392, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 14000, 15000, 0, 11, 25471, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Cast \'Attack Order\' (Normal Dungeon)'),
+(15392, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Increment Phase (Normal Dungeon)'),
+(15392, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15392, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15392, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15392, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Tuubid - On Aggro - Set Instance Data 1 to 9');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15389;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15389) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15389, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15389, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 14000, 15000, 0, 11, 26550, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Cast \'Lightning Cloud\' (Normal Dungeon)'),
+(15389, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Increment Phase (Normal Dungeon)'),
+(15389, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15389, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15389, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15389, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Drenn - On Aggro - Set Instance Data 1 to 10');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15390;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15390) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15390, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15390, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 14000, 15000, 0, 11, 25425, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Cast \'Shockwave\' (Normal Dungeon)'),
+(15390, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Increment Phase (Normal Dungeon)'),
+(15390, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15390, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15390, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15390, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Captain Xurrem - On Aggro - Set Instance Data 1 to 11');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15386;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15386) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15386, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15386, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 8000, 9000, 0, 11, 25282, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Cast \'Shield of Rajaxx\' (Normal Dungeon)'),
+(15386, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Increment Phase (Normal Dungeon)'),
+(15386, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15386, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15386, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15386, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Yeggeth - On Aggro - Set Instance Data 1 to 12');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15388;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15388) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15388, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15388, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 14000, 15000, 0, 11, 25322, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Cast \'Sweeping Slam\' (Normal Dungeon)'),
+(15388, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Increment Phase (Normal Dungeon)'),
+(15388, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15388, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15388, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15388, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Major Pakkon - On Aggro - Set Instance Data 1 to 13');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15385;
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15385) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5, 6));
+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
+(15385, 0, 0, 0, 0, 0, 100, 2, 10000, 11000, 8000, 9000, 0, 11, 24317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Cast \'Sunder Armor\' (Normal Dungeon)'),
+(15385, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 8000, 9000, 0, 11, 25462, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Cast \'Enlarge\' (Normal Dungeon)'),
+(15385, 0, 2, 0, 0, 0, 100, 514, 13000, 17000, 14000, 18000, 0, 23, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Increment Phase (Normal Dungeon)'),
+(15385, 0, 3, 0, 0, 1, 100, 2, 1000, 1000, 1000, 1000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15385, 0, 4, 0, 0, 1, 100, 2, 2000, 2000, 2000, 2000, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Cast \'Cleave\' (Phase 1) (Normal Dungeon)'),
+(15385, 0, 5, 0, 0, 1, 100, 514, 3000, 3000, 3000, 3000, 0, 23, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Decrement Phase (Phase 1) (Normal Dungeon)'),
+(15385, 0, 6, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 34, 1, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - On Aggro - Set Instance Data 1 to 14');
diff --git a/data/sql/updates/db_world/2022_08_07_00.sql b/data/sql/updates/db_world/2022_08_07_00.sql
new file mode 100644
index 000000000..2259de526
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_06_01 -> 2022_08_07_00
+--
+UPDATE `gameobject_template` SET `data3`=8000 WHERE `entry`=180619;
diff --git a/data/sql/updates/db_world/2022_08_07_01.sql b/data/sql/updates/db_world/2022_08_07_01.sql
new file mode 100644
index 000000000..c8d0469dc
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_01.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_07_00 -> 2022_08_07_01
+--
+UPDATE `smart_scripts` SET `event_type`=0, `event_param1`=7000, `event_param2`=10000 WHERE `entryorguid`=15336 AND `source_type`=0 AND `id`=4 AND `link`=0;
+UPDATE `smart_scripts` SET `event_type`=0, `event_param1`=10000, `event_param2`=16000, `event_param3`=21800, `event_param4`=34400 WHERE `entryorguid`=15319 AND `source_type`=0 AND `id`=0 AND `link`=0;
+UPDATE `smart_scripts` SET `event_param1`=12000, `event_param2`=15000, `event_param3`=26700, `event_param4`=36500 WHERE `entryorguid`=15319 AND `source_type`=0 AND `id`=1 AND `link`=0;
diff --git a/data/sql/updates/db_world/2022_08_07_02.sql b/data/sql/updates/db_world/2022_08_07_02.sql
new file mode 100644
index 000000000..d507e5ee6
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_02.sql
@@ -0,0 +1,40 @@
+-- DB update 2022_08_07_01 -> 2022_08_07_02
+--
+DELETE FROM `creature_formations` WHERE `leaderguid` IN (144466, 144476, 144473, 144469, 144481, 144470, 144452, 144456, 144454);
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(144466, 144466, 0, 0, 3, 0, 0),
+(144466, 144474, 0, 0, 3, 0, 0),
+(144466, 144475, 0, 0, 3, 0, 0),
+(144476, 144476, 0, 0, 3, 0, 0),
+(144476, 144467, 0, 0, 3, 0, 0),
+(144476, 144468, 0, 0, 3, 0, 0),
+(144473, 144473, 0, 0, 3, 0, 0),
+(144473, 144464, 0, 0, 3, 0, 0),
+(144473, 144465, 0, 0, 3, 0, 0),
+(144469, 144469, 0, 0, 3, 0, 0),
+(144469, 144477, 0, 0, 3, 0, 0),
+(144469, 144478, 0, 0, 3, 0, 0),
+(144481, 144481, 0, 0, 3, 0, 0),
+(144481, 144471, 0, 0, 3, 0, 0),
+(144481, 144472, 0, 0, 3, 0, 0),
+(144470, 144470, 0, 0, 3, 0, 0),
+(144470, 144479, 0, 0, 3, 0, 0),
+(144470, 144480, 0, 0, 3, 0, 0),
+(144452, 144452, 0, 0, 3, 0, 0),
+(144452, 144453, 0, 0, 3, 0, 0),
+(144452, 144458, 0, 0, 3, 0, 0),
+(144452, 144459, 0, 0, 3, 0, 0),
+(144452, 144586, 0, 0, 3, 0, 0),
+(144452, 144587, 0, 0, 3, 0, 0),
+(144456, 144456, 0, 0, 3, 0, 0),
+(144456, 144457, 0, 0, 3, 0, 0),
+(144456, 144462, 0, 0, 3, 0, 0),
+(144456, 144463, 0, 0, 3, 0, 0),
+(144456, 144590, 0, 0, 3, 0, 0),
+(144456, 144591, 0, 0, 3, 0, 0),
+(144454, 144454, 0, 0, 3, 0, 0),
+(144454, 144455, 0, 0, 3, 0, 0),
+(144454, 144460, 0, 0, 3, 0, 0),
+(144454, 144461, 0, 0, 3, 0, 0),
+(144454, 144588, 0, 0, 3, 0, 0),
+(144454, 144589, 0, 0, 3, 0, 0);
diff --git a/data/sql/updates/db_world/2022_08_07_03.sql b/data/sql/updates/db_world/2022_08_07_03.sql
new file mode 100644
index 000000000..bedff5b58
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_03.sql
@@ -0,0 +1,7 @@
+-- DB update 2022_08_07_02 -> 2022_08_07_03
+--
+UPDATE `creature_template_addon` SET `auras` = '' WHERE (`entry` = 15385);
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15385) AND (`source_type` = 0) AND (`id` IN (1));
+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
+(15385, 0, 1, 0, 0, 0, 100, 2, 12000, 13000, 20000, 26000, 0, 11, 25462, 32, 0, 0, 0, 0, 26, 20, 0, 0, 0, 0, 0, 0, 0, 'Colonel Zerran - In Combat - Cast \'Enlarge\'');
diff --git a/data/sql/updates/db_world/2022_08_07_04.sql b/data/sql/updates/db_world/2022_08_07_04.sql
new file mode 100644
index 000000000..f1f84b3a0
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_04.sql
@@ -0,0 +1,14 @@
+-- DB update 2022_08_07_03 -> 2022_08_07_04
+--
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5316 WHERE `MenuID`=435 AND `OptionID`=0;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=3428 WHERE `MenuID`=435 AND `OptionID`=6;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=9756 WHERE `MenuID`=435 AND `OptionID`=10;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=10359 WHERE `MenuID`=435 AND `OptionID`=11;
+
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=2870 WHERE `MenuID`=1951 AND `OptionID`=2;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=4895 WHERE `MenuID`=1951 AND `OptionID`=4;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5316 WHERE `MenuID`=1951 AND `OptionID`=5;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5518 WHERE `MenuID`=1951 AND `OptionID`=6;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=7253 WHERE `MenuID`=1951 AND `OptionID`=7;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=9756 WHERE `MenuID`=1951 AND `OptionID`=9;
+UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=10359 WHERE `MenuID`=1951 AND `OptionID`=10;
diff --git a/data/sql/updates/db_world/2022_08_07_05.sql b/data/sql/updates/db_world/2022_08_07_05.sql
new file mode 100644
index 000000000..b4f866e56
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_05.sql
@@ -0,0 +1,10 @@
+-- DB update 2022_08_07_04 -> 2022_08_07_05
+DELETE FROM `gameobject` WHERE `id` = 176966;
+DELETE FROM `gameobject` WHERE `guid` = 75160;
+INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`,
+ `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`,
+ `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`,
+ `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`)
+VALUES (75160, 176966, 469, 0, 0, 1, 1, -7488.1, -1150.7, 476.535, 3.73064, -0.0,
+ -0.0, -0.95694, 0.290285, 300, 0, 1, 'Nefarian\'s Gate', 0);
+UPDATE `gameobject_template_addon` SET `flags` = `flags`|16 WHERE `entry` = 176966;
diff --git a/data/sql/updates/db_world/2022_08_07_06.sql b/data/sql/updates/db_world/2022_08_07_06.sql
new file mode 100644
index 000000000..6b01fd86c
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_06.sql
@@ -0,0 +1,12 @@
+-- DB update 2022_08_07_05 -> 2022_08_07_06
+--
+UPDATE `creature_template` SET `lootid` = 0, `skinloot` = 0, `mingold` = 0, `maxgold` = 0 WHERE (`entry` = 11374);
+DELETE FROM `creature_loot_template` WHERE `entry` = 11374;
+
+UPDATE `creature_template` SET `skinloot` = 0 WHERE (`entry` = 10596);
+
+UPDATE `creature_template` SET `lootid` = 0, `skinloot` = 0 WHERE (`entry` = 15101);
+DELETE FROM `creature_loot_template` WHERE `entry` = 15101;
+
+UPDATE `creature_template` SET `lootid` = 0, `skinloot` = 0 WHERE (`entry` = 15068);
+DELETE FROM `creature_loot_template` WHERE `entry` = 15068;
diff --git a/data/sql/updates/db_world/2022_08_07_07.sql b/data/sql/updates/db_world/2022_08_07_07.sql
new file mode 100644
index 000000000..b3928f67a
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_07_07.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_07_06 -> 2022_08_07_07
+--
+UPDATE `gameobject` SET `ScriptName` = '' WHERE `id` = 176966;
diff --git a/data/sql/updates/db_world/2022_08_08_00.sql b/data/sql/updates/db_world/2022_08_08_00.sql
new file mode 100644
index 000000000..ee547efc9
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_08_00.sql
@@ -0,0 +1,63 @@
+-- DB update 2022_08_07_07 -> 2022_08_08_00
+--
+-- Pathing for Sand Vortex Entry: 15428
+SET @NPC := 144680;
+SET @PATH := @NPC * 10;
+UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-9524.06,`position_y`=1881.9224,`position_z`=85.64029 WHERE `guid`=@NPC;
+DELETE FROM `creature_addon` WHERE `guid`=@NPC;
+INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0,25160);
+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,-9467.716,1801.2075,85.68075,0,0,0,0,100,0),
+(@PATH,2,-9433.638,1767.3511,85.68072,0,0,0,0,100,0),
+(@PATH,3,-9400.586,1733.8876,85.68073,0,0,0,0,100,0),
+(@PATH,4,-9366.376,1733.2712,85.65805,0,0,0,0,100,0),
+(@PATH,5,-9333.135,1732.013,85.61758,0,0,0,0,100,0),
+(@PATH,6,-9300.71,1733.3823,85.68074,0,0,0,0,100,0),
+(@PATH,7,-9266.841,1766.4036,85.68074,0,0,0,0,100,0),
+(@PATH,8,-9234.005,1800.0885,85.68074,0,0,0,0,100,0),
+(@PATH,9,-9200.683,1833.4056,85.68073,0,0,0,0,100,0),
+(@PATH,10,-9168.018,1866.673,86.23005,0,0,0,0,100,0),
+(@PATH,11,-9171.645,1901.1793,85.68071,0,0,0,0,100,0),
+(@PATH,12,-9173.781,1933.2633,85.68071,0,0,0,0,100,0),
+(@PATH,13,-9195.187,1966.727,86.19511,0,0,0,0,100,0),
+(@PATH,14,-9220.778,1999.9199,85.68075,0,0,0,0,100,0),
+(@PATH,15,-9256.546,2032.9481,86.04485,0,0,0,0,100,0),
+(@PATH,16,-9289.013,2066.2517,87.10255,0,0,0,0,100,0),
+(@PATH,17,-9333.082,2071.4539,85.99686,0,0,0,0,100,0),
+(@PATH,18,-9366.466,2075.198,86.651405,0,0,0,0,100,0),
+(@PATH,19,-9399.833,2040.6716,86.5944,0,0,0,0,100,0),
+(@PATH,20,-9432.466,2006.033,85.930725,0,0,0,0,100,0),
+(@PATH,21,-9466.139,1975.4115,85.92978,0,0,0,0,100,0),
+(@PATH,22,-9499.492,1940.9631,85.67978,0,0,0,0,100,0),
+(@PATH,23,-9525.446,1900.1099,85.680725,0,0,0,0,100,0),
+(@PATH,24,-9519.793,1870.9224,85.68071,0,0,0,0,100,0),
+(@PATH,25,-9499.598,1833.6816,85.68074,0,0,0,0,100,0);
+
+-- Pathing for Sand Vortex Entry: 15428
+SET @NPC := 144679;
+SET @PATH := @NPC * 10;
+UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-9228.479,`position_y`=1925.3331,`position_z`=85.64147 WHERE `guid`=@NPC;
+DELETE FROM `creature_addon` WHERE `guid`=@NPC;
+INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0,25160);
+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,-9267.194,1866.0243,85.597404,0,0,0,0,100,0),
+(@PATH,2,-9299.206,1833.0114,85.52548,0,0,0,0,100,0),
+(@PATH,3,-9333.244,1799.9004,83.67978,0,0,0,0,100,0),
+(@PATH,4,-9366.875,1774.673,85.68073,0,0,0,0,100,0),
+(@PATH,5,-9393.9375,1800.2031,85.642654,0,0,0,0,100,0),
+(@PATH,6,-9399.323,1833.3334,85.68074,0,0,0,0,100,0),
+(@PATH,7,-9425.436,1859.5237,85.63606,0,0,0,0,100,0),
+(@PATH,8,-9461.292,1861.6554,85.68074,0,0,0,0,100,0),
+(@PATH,9,-9466.752,1899.8247,85.68074,0,0,0,0,100,0),
+(@PATH,10,-9432.557,1932.738,84.57658,0,0,0,0,100,0),
+(@PATH,11,-9400.856,1965.8516,86.60922,0,0,0,0,100,0),
+(@PATH,12,-9369.419,2000.3989,85.680725,0,0,0,0,100,0),
+(@PATH,13,-9332.606,2018.017,85.68073,0,0,0,0,100,0),
+(@PATH,14,-9311.325,1999.8208,85.68074,0,0,0,0,100,0),
+(@PATH,15,-9310.085,1969.1917,85.68074,0,0,0,0,100,0),
+(@PATH,16,-9285.372,1947.293,85.68074,0,0,0,0,100,0),
+(@PATH,17,-9255.054,1952.4874,85.68074,0,0,0,0,100,0),
+(@PATH,18,-9225.013,1923.3672,85.68074,0,0,0,0,100,0),
+(@PATH,19,-9233.319,1899.1927,85.68073,0,0,0,0,100,0);
diff --git a/data/sql/updates/db_world/2022_08_09_00.sql b/data/sql/updates/db_world/2022_08_09_00.sql
new file mode 100644
index 000000000..14bda1883
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_09_00.sql
@@ -0,0 +1,21 @@
+-- DB update 2022_08_08_00 -> 2022_08_09_00
+--
+SET @NPC := 15369;
+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,-9689.981,1548.2961,33.27733,0,0,0,0,100,0),
+(@PATH,2,-9682.716,1554.252,31.416214,0,0,0,0,100,0),
+(@PATH,3,-9677.917,1558.839,27.249535,0,0,0,0,100,0);
+
+-- Summon HiveZara larvae
+UPDATE `spell_dbc` SET `Effect_1` = 28, `EffectMiscValueB_1` = 64, `EffectBasePoints_1` = 1, `EffectDieSides_1` = 0 WHERE `ID` IN (26538, 26539);
+
+DELETE FROM `spell_target_position` WHERE `ID` IN (26538, 26539);
+INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES
+(26538, 0, 509, -9678.29, 1526.39, 24.403833,0,0),
+(26539, 0, 509, -9709, 1551.2, 23.988834, 0, 0);
+
+DELETE FROM `creature_template_movement` WHERE `CreatureId` = 15546;
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
+(15546, 1, 0, 1, 0, 0, NULL);
diff --git a/data/sql/updates/db_world/2022_08_10_00.sql b/data/sql/updates/db_world/2022_08_10_00.sql
new file mode 100644
index 000000000..b5bb80ff1
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_10_00.sql
@@ -0,0 +1,31 @@
+-- DB update 2022_08_09_00 -> 2022_08_10_00
+--
+DELETE FROM `spell_target_position` WHERE `ID` IN (720, 731, 1121, 518, 25831, 25832);
+INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`) VALUES
+(720, 0, 531, -8043.6, 1254.1, -84.3, 0),
+(731, 0, 531, -8003, 1222.9, -82.1, 0),
+(1121, 0, 531, -8022.3, 1149, -89.1, 0),
+(518, 0, 531, -8028.5, 1050.9, -54, 0),
+(25831, 0, 531, -8158.03, 1139.3, -83.95, 0),
+(25832, 0, 531, -8029.25, 1237.78, -85.2285, 0);
+
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15630) AND (`source_type` = 0) AND (`id` IN (0));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(15630, 0, 0, 0, 0, 0, 100, 3, 10000, 20000, 0, 0, 0, 11, 26662, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Spawn of Fankriss - In Combat - Cast \'Berserk\' (No Repeat) (Normal Dungeon)');
+
+DELETE FROM `creature_formations` WHERE `memberGUID` IN (87911, 87773, 87775, 87796, 87806, 87792);
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(87911, 87911, 0, 0, 3, 0, 0),
+(87911, 87773, 0, 0, 3, 0, 0),
+(87911, 87775, 0, 0, 3, 0, 0),
+(87911, 87796, 0, 0, 3, 0, 0),
+(87911, 87806, 0, 0, 3, 0, 0),
+(87911, 87792, 0, 0, 3, 0, 0);
+
+DELETE FROM `linked_respawn` WHERE `guid` IN (87773, 87775, 87796, 87806, 87792);
+INSERT INTO `linked_respawn` (`guid`, `linkedGuid`, `linkType`) VALUES
+(87773, 87911, 0),
+(87775, 87911, 0),
+(87796, 87911, 0),
+(87806, 87911, 0),
+(87792, 87911, 0);
diff --git a/data/sql/updates/db_world/2022_08_10_01.sql b/data/sql/updates/db_world/2022_08_10_01.sql
new file mode 100644
index 000000000..86ba73faa
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_10_01.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_10_00 -> 2022_08_10_01
+--
+DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryorguid` = 15277 AND `id`=12;
+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
+(15277, 0, 12, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 27630, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anubisath Defender - On Just Died - Cast \'Serverside - Drop Obsidian\'');
diff --git a/data/sql/updates/db_world/2022_08_10_02.sql b/data/sql/updates/db_world/2022_08_10_02.sql
new file mode 100644
index 000000000..1acdf4320
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_10_02.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_10_01 -> 2022_08_10_02
+--
+DELETE FROM `creature_addon` WHERE `guid`=144632;
diff --git a/data/sql/updates/db_world/2022_08_11_00.sql b/data/sql/updates/db_world/2022_08_11_00.sql
new file mode 100644
index 000000000..2b3b04e9a
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_11_00.sql
@@ -0,0 +1,10 @@
+-- DB update 2022_08_10_02 -> 2022_08_11_00
+--
+UPDATE `quest_template_addon` SET `AllowableClasses`=1 WHERE `id`=8316;
+UPDATE `quest_template_addon` SET `AllowableClasses`=2 WHERE `id`=8376;
+UPDATE `quest_template_addon` SET `AllowableClasses`=4 WHERE `id`=8377;
+UPDATE `quest_template_addon` SET `AllowableClasses`=8 WHERE `id`=8378;
+UPDATE `quest_template_addon` SET `AllowableClasses`=16 WHERE `id`=8379;
+UPDATE `quest_template_addon` SET `AllowableClasses`=64 WHERE `id`=8380;
+UPDATE `quest_template_addon` SET `AllowableClasses`=384 WHERE `id`=8381;
+UPDATE `quest_template_addon` SET `AllowableClasses`=1024 WHERE `id`=8382;
diff --git a/data/sql/updates/db_world/2022_08_12_00.sql b/data/sql/updates/db_world/2022_08_12_00.sql
new file mode 100644
index 000000000..ba7b36701
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_12_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_11_00 -> 2022_08_12_00
+
+UPDATE `conditions` SET `ConditionValue3` = 0 WHERE `SourceTypeOrReferenceId` = 22 AND `SourceGroup` = 2 AND `SourceEntry` = 182026;
diff --git a/data/sql/updates/db_world/2022_08_12_01.sql b/data/sql/updates/db_world/2022_08_12_01.sql
new file mode 100644
index 000000000..a419681ab
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_12_01.sql
@@ -0,0 +1,2 @@
+-- DB update 2022_08_12_00 -> 2022_08_12_01
+UPDATE `creature` SET `wander_distance`=20.0,`MovementType`=1 WHERE `guid`=58019 AND `id1`=16854;
diff --git a/data/sql/updates/db_world/2022_08_14_00.sql b/data/sql/updates/db_world/2022_08_14_00.sql
new file mode 100644
index 000000000..526cfcded
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_00.sql
@@ -0,0 +1,8 @@
+-- DB update 2022_08_12_01 -> 2022_08_14_00
+--
+UPDATE `creature_formations` SET `dist`=5 WHERE `memberGUID` IN (87649,87650,87651);
+
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=26084 AND `spell_effect`=25174 AND `type`=1;
+INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
+(26084, 25174, 1, 'Battleguard Sartura - OnHit Whirlwind - Apply Sundering Cleave');
+
diff --git a/data/sql/updates/db_world/2022_08_14_01.sql b/data/sql/updates/db_world/2022_08_14_01.sql
new file mode 100644
index 000000000..1dd0c127f
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_01.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_14_00 -> 2022_08_14_01
+--
+UPDATE `creature_template` SET `ScriptName`='npc_hivezara_stinger' WHERE `entry`=15327;
diff --git a/data/sql/updates/db_world/2022_08_14_02.sql b/data/sql/updates/db_world/2022_08_14_02.sql
new file mode 100644
index 000000000..187bacf19
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_02.sql
@@ -0,0 +1,16 @@
+-- DB update 2022_08_14_01 -> 2022_08_14_02
+--
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 15324 AND `source_type` = 0;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(15324,0,0,0,11,0,100,256,0,0,0,0,211,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - On Respawn - Set not phase reset"),
+(15324,0,1,0,0,0,100,0,5400,8500,6000,17000,11,5568,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - In Combat - Cast 'Trample'"),
+(15324,0,2,0,0,0,100,0,8500,13000,8000,16000,11,10966,0,0,0,0,0,2,0,0,0,0,0,0,0,"Qiraji Gladiator - In Combat - Cast 'Uppercut'"),
+(15324,0,3,4,38,0,100,0,0,1,0,0,11,25164,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - On Data Set 0 1 - Cast 'Vengeance'"),
+(15324,0,4,5,61,0,100,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - On Link - Say Line 0"),
+(15324,0,5,0,61,0,100,256,0,0,0,0,22,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - On Link - Set Phase 1"),
+(15324,0,6,0,6,0,100,0,0,0,0,0,45,0,1,0,0,0,0,19,15324,30,0,0,0,0,0,"Qiraji Gladiator - On Death - Set Data 0 1"),
+(15324,0,7,0,0,1,100,0,60000,60000,60000,60000,11,25164,0,0,0,0,0,1,0,0,0,0,0,0,0,"Qiraji Gladiator - IC - Cast 'Vengeance' (Phase 1)");
+
+DELETE FROM `creature_text` WHERE `CreatureID`=15324;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(15324,0,0,'%s becomes enraged!',16,0,100,0,0,0,24144,0,'Qiraji Gladiator');
diff --git a/data/sql/updates/db_world/2022_08_14_03.sql b/data/sql/updates/db_world/2022_08_14_03.sql
new file mode 100644
index 000000000..bc0408e18
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_03.sql
@@ -0,0 +1,11 @@
+-- DB update 2022_08_14_02 -> 2022_08_14_03
+--
+UPDATE `smart_scripts` SET `link`=2 WHERE `entryorguid` = 15323 AND `source_type` = 0 AND `id`=1;
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 15323 AND `source_type` = 0 AND `id` IN (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`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(15323,0,2,3,61,0,100,0,0,0,0,0,20,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - In Combat - Disable melee attack"),
+(15323,0,3,0,61,0,100,0,0,0,0,0,22,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - In Combat - Set Phase 1"),
+(15323,0,4,5,0,1,100,0,3000,6000,3000,6000,28,26381,0,0,0,0,0,1,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - IC - Remove Borrow"),
+(15323,0,5,6,61,0,100,0,0,0,0,0,11,41390,0,0,0,0,0,2,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - IC - Cast Ambush"),
+(15323,0,6,7,61,0,100,0,0,0,0,0,20,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - In Combat - Enable melee attack"),
+(15323,0,7,0,61,0,100,0,0,0,0,0,22,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Hive'Zara Sandstalker - In Combat - Set Phase 0");
diff --git a/data/sql/updates/db_world/2022_08_14_04.sql b/data/sql/updates/db_world/2022_08_14_04.sql
new file mode 100644
index 000000000..1f7648d9d
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_04.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_14_03 -> 2022_08_14_04
+--
+DELETE FROM `creature_text` WHERE `CreatureID`=15264;
+INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(15264,0,0,'%s becomes enraged!',16,0,100,0,0,0,24144,0,'Anubisath Sentinel');
diff --git a/data/sql/updates/db_world/2022_08_14_05.sql b/data/sql/updates/db_world/2022_08_14_05.sql
new file mode 100644
index 000000000..ff6c8cf76
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_14_05.sql
@@ -0,0 +1,24 @@
+-- DB update 2022_08_14_04 -> 2022_08_14_05
+-- Fix Silithid Carapace to depend only to Agent of Nozdormu item
+UPDATE `creature_loot_template` SET `QuestRequired` = 0 WHERE `Item` = 20384;
+
+DELETE FROM `conditions` WHERE `SourceEntry` = 20384 AND `ConditionValue1` = 20402;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(1, 11698, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11721, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11722, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11723, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11724, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11725, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11726, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11727, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11728, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11729, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11730, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11731, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11732, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11733, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 11734, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 13136, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 13301, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', ''),
+(1, 15759, 20384, 0, 0, 2, 0, 20402, 1, 0, 0, 0, 0, '', '');
diff --git a/data/sql/updates/db_world/2022_08_15_00.sql b/data/sql/updates/db_world/2022_08_15_00.sql
new file mode 100644
index 000000000..d50300ebc
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_00.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_14_05 -> 2022_08_15_00
+-- Remove a duplicate and wrong gossip with anachronos
+DELETE FROM `gossip_menu_option` WHERE `MenuID` = 6539 AND `OptionID` IN (0);
diff --git a/data/sql/updates/db_world/2022_08_15_01.sql b/data/sql/updates/db_world/2022_08_15_01.sql
new file mode 100644
index 000000000..0020614c9
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_01.sql
@@ -0,0 +1,110 @@
+-- DB update 2022_08_15_00 -> 2022_08_15_01
+--
+-- Remove all entries, they will be replaced
+DELETE FROM `creature` WHERE `id1`=2955;
+DELETE FROM `creature` WHERE `id2`=2955;
+DELETE FROM `creature` WHERE `id3`=2955;
+
+-- Corrects spawn points to sniffed values, mostly this was fine, but the XYZ values were done manually rather than from sniffed variables
+-- Wander distance was already set to 20, which is a good minimum value, about half of them have a wander value of around 30 or more, the sniff will be uploaded later to the collective if anyone wants to deep dive that for some reason
+-- Similarly, 155 was the spawntime set before this fix, 180 is probbably correct, but this is fine imo without dynamic spawning
+SET @GUID :=88354;
+DELETE FROM `creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+96;
+INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
+(@GUID+0, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2915.9321, -117.10601, 77.61542, 1.884955525398254394, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2915.9321 -117.10601 77.61542
+(@GUID+1, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2881.4697, -150.06369, 67.3019, 3.03687286376953125, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2881.4697 -150.06369 67.3019
+(@GUID+2, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2983.2869, -181.743, 63.0384, 2.146754980087280273, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2983.2869 -181.743 63.0384
+(@GUID+3, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3049.5332, -116.48638, 52.78892, 3.612831592559814453, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3049.5332 -116.48638 52.78892
+(@GUID+4, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3084.8281, -151.3636, 47.7102, 1.972222089767456054, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3084.8281 -151.3636 47.7102
+(@GUID+5, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3048.971, -183.28185, 59.85856, 1.553343057632446289, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3048.971 -183.28185 59.85856
+(@GUID+6, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3016.0718, -217.09685, 56.218082, 4.398229598999023437, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3016.0718 -217.09685 56.218082
+(@GUID+7, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2849.0051, -182.61052, 59.357796, 1.692969322204589843, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2849.0051 -182.61052 59.357796
+(@GUID+8, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2817.4912, -216.73177, 56.172832, 3.96189737319946289, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2817.4912 -216.73177 56.172832
+(@GUID+9, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2848.5728, -316.2174, 55.82892, 1.919862151145935058, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2848.5728 -316.2174 55.82892
+(@GUID+10, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2817.3057, -284.28928, 58.999767, 0.261799395084381103, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2817.3057 -284.28928 58.999767
+(@GUID+11, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2791.1252, -316.0387, 55.81441, 5.096361160278320312, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2791.1252 -316.0387 55.81441
+(@GUID+12, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2816.52, -348.31967, 57.394314, 4.747295379638671875, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2816.52 -348.31967 57.394314
+(@GUID+13, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2849.3384, -383.77203, 55.30781, 0.331612557172775268, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2849.3384 -383.77203 55.30781
+(@GUID+14, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2883.8289, -350.39417, 55.231503, 4.171336650848388671, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2883.8289 -350.39417 55.231503
+(@GUID+15, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2915.2188, -383.69476, 55.308075, 3.124139308929443359, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2915.2188 -383.69476 55.308075
+(@GUID+16, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2882.5889, -417.75314, 49.94027, 0, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2882.5889 -417.75314 49.94027
+(@GUID+17, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2864.4363, -449.93967, 53.77305, 1.605702877044677734, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2864.4363 -449.93967 53.77305
+(@GUID+18, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2883.513, -483.6671, 47.450447, 2.687807083129882812, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2883.513 -483.6671 47.450447
+(@GUID+19, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2951.8186, -350.5021, 55.86079, 5.846852779388427734, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2951.8186 -350.5021 55.86079
+(@GUID+20, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2983.916, -316.7991, 48.84321, 1.029744267463684082, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2983.916 -316.7991 48.84321
+(@GUID+21, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3018.8704, -284.1935, 43.844025, 2.111848354339599609, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3018.8704 -284.1935 43.844025
+(@GUID+22, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3050.7756, -317.3549, 42.753426, 0.383972436189651489, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3050.7756 -317.3549 42.753426
+(@GUID+23, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3117.3638, -317.11685, 40.205025, 1.815142393112182617, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3117.3638 -317.11685 40.205025
+(@GUID+24, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3082.7852, -283.14948, 36.52417, 4.450589656829833984, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3082.7852 -283.14948 36.52417
+(@GUID+25, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3082.5708, -350.88812, 36.985973, 0.139626339077949523, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3082.5708 -350.88812 36.985973
+(@GUID+26, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3049.2266, -384.4684, 39.612816, 3.682644605636596679, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3049.2266 -384.4684 39.612816
+(@GUID+27, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3084.3826, -417.4145, 37.911163, 5.951572895050048828, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3084.3826 -417.4145 37.911163
+(@GUID+28, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3116.5625, -383.2819, 41.819256, 2.321287870407104492, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3116.5625 -383.2819 41.819256
+(@GUID+29, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3016.7205, -417.2922, 48.25192, 0.575958669185638427, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3016.7205 -417.2922 48.25192
+(@GUID+30, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2983.6528, -382.88184, 53.537003, 2.827433347702026367, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2983.6528 -382.88184 53.537003
+(@GUID+31, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2984.1338, -450.97092, 46.477955, 4.537856101989746093, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2984.1338 -450.97092 46.477955
+(@GUID+32, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2950.2192, -417.1669, 53.86521, 0.104719758033752441, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2950.2192 -417.1669 53.86521
+(@GUID+33, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2917.082, -450.50412, 46.918938, 4.78220224380493164, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2917.082 -450.50412 46.918938
+(@GUID+34, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2883.351, -549.6797, 51.405052, 5.078907966613769531, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2883.351 -549.6797 51.405052
+(@GUID+35, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2850.924, -517.7154, 50.91358, 5.06145477294921875, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2850.924 -517.7154 50.91358
+(@GUID+36, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2817.7004, -549.1674, 55.274178, 2.617993831634521484, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2817.7004 -549.1674 55.274178
+(@GUID+37, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2851.802, -583.9538, 57.15891, 3.630284786224365234, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2851.802 -583.9538 57.15891
+(@GUID+38, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2915.418, -517.8362, 47.194675, 4.380776405334472656, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2915.418 -517.8362 47.194675
+(@GUID+39, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2817.2737, -617.9309, 56.016186, 5.619960308074951171, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2817.2737 -617.9309 56.016186
+(@GUID+40, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2884.533, -616.6502, 55.083035, 5.969026088714599609, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2884.533 -616.6502 55.083035
+(@GUID+41, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2949.897, -615.9156, 39.461315, 2.897246599197387695, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2949.897 -615.9156 39.461315
+(@GUID+42, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2915.745, -583.6176, 50.565845, 5.462880611419677734, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2915.745 -583.6176 50.565845
+(@GUID+43, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2949.016, -549.3831, 45.385597, 4.049163818359375, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2949.016 -549.3831 45.385597
+(@GUID+44, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2983.931, -583.4975, 38.284866, 6.0737457275390625, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2983.931 -583.4975 38.284866
+(@GUID+45, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3018.492, -617.0446, 29.809212, 1.256637096405029296, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3018.492 -617.0446 29.809212
+(@GUID+46, 2966, 0, 0, 1, 0, 0, 1, 1, 0, -3017.079, -685.03986, 41.89431, 5.432766437530517578, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3017.079 -685.03986 41.89431
+(@GUID+47, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3084.279, -682.7648, 31.90988, 0.802851438522338867, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3084.279 -682.7648 31.90988
+(@GUID+48, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3050.0088, -650.9782, 29.19056, 0.680678427219390869, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3050.0088 -650.9782 29.19056
+(@GUID+49, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3085.173, -617.01215, 34.477776, 5.689773082733154296, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3085.173 -617.01215 34.477776
+(@GUID+50, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3116.6624, -649.3928, 32.413265, 1.169370532035827636, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3116.6624 -649.3928 32.413265
+(@GUID+51, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3116.1125, -714.4594, 33.46272, 0.942477762699127197, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3116.1125 -714.4594 33.46272
+(@GUID+52, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3148.6108, -683.60284, 23.079771, 3.141592741012573242, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3148.6108 -683.60284 23.079771
+(@GUID+53, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3182.7786, -716.07, 26.982426, 4.537856101989746093, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3182.7786 -716.07 26.982426
+(@GUID+54, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3148.8203, -615.4817, 35.513004, 2.356194496154785156, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3148.8203 -615.4817 35.513004
+(@GUID+55, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3117.3677, -251.52632, 41.896477, 2.722713708877563476, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3117.3677 -251.52632 41.896477
+(@GUID+56, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3150.7246, -216.66353, 43.11533, 1.029744267463684082, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3150.7246 -216.66353 43.11533
+(@GUID+57, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3182.763, -249.51974, 40.0922, 0.628318548202514648, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3182.763 -249.51974 40.0922
+(@GUID+58, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3184.1643, -317.5604, 37.124756, 5.707226753234863281, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3184.1643 -317.5604 37.124756
+(@GUID+59, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3150.1514, -285.3053, 39.282925, 3.089232683181762695, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3150.1514 -285.3053 39.282925
+(@GUID+60, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3149.0168, -349.84933, 34.957115, 4.660028934478759765, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3149.0168 -349.84933 34.957115
+(@GUID+61, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3215.4568, -217.2468, 31.292675, 4.328416347503662109, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3215.4568 -217.2468 31.292675
+(@GUID+62, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3182.377, -184.5408, 41.331944, 1.692969322204589843, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3182.377 -184.5408 41.331944
+(@GUID+63, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3215.015, -284.60513, 30.6046, 4.590215682983398437, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3215.015 -284.60513 30.6046
+(@GUID+64, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3284.4084, -217.13043, 39.615646, 3.787364482879638671, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3284.4084 -217.13043 39.615646
+(@GUID+65, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3284.5642, -282.64816, 37.027092, 2.199114799499511718, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3284.5642 -282.64816 37.027092
+(@GUID+66, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3214.8604, -347.4374, 28.102503, 5.969026088714599609, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3214.8604 -347.4374 28.102503
+(@GUID+67, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3248.986, -316.8644, 32.329453, 4.886921882629394531, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3248.986 -316.8644 32.329453
+(@GUID+68, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3282.3496, -350.19608, 43.65876, 2.39110112190246582, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3282.3496 -350.19608 43.65876
+(@GUID+69, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3249.6396, -384.67285, 31.974255, 2.0245819091796875, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3249.6396 -384.67285 31.974255
+(@GUID+70, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3281.6199, -417.9758, 36.595318, 0.122173048555850982, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3281.6199 -417.9758 36.595318
+(@GUID+71, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3215.3584, -416.1518, 25.393665, 2.356194496154785156, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3215.3584 -416.1518 25.393665
+(@GUID+72, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3248.7173, -450.7054, 28.379059, 1.48352980613708496, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3248.7173 -450.7054 28.379059
+(@GUID+73, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3216.2603, -483.22516, 24.11747, 4.310963153839111328, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3216.2603 -483.22516 24.11747
+(@GUID+74, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3249.8452, -516.86914, 27.956903, 5.393067359924316406, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3249.8452 -516.86914 27.956903
+(@GUID+75, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3150.8284, -482.7306, 30.151358, 1.884955525398254394, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3150.8284 -482.7306 30.151358
+(@GUID+76, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3149.8757, -417.15897, 31.773283, 4.590215682983398437, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3149.8757 -417.15897 31.773283
+(@GUID+77, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3115.8054, -449.89996, 29.697945, 3.735004663467407226, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3115.8054 -449.89996 29.697945
+(@GUID+78, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3083.3086, -483.736, 31.280085, 3.560471534729003906, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3083.3086 -483.736 31.280085
+(@GUID+79, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3118.7922, -516.90375, 34.351627, 0.03490658476948738, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3118.7922 -516.90375 34.351627
+(@GUID+80, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3148.536, -550.18274, 30.679869, 2.443460941314697265, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3148.536 -550.18274 30.679869
+(@GUID+81, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3116.379, -583.2126, 34.0221, 4.886921882629394531, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3116.379 -583.2126 34.0221
+(@GUID+82, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3217.4094, -616.01, 28.73066, 3.665191411972045898, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3217.4094 -616.01 28.73066
+(@GUID+83, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3216.0747, -548.41754, 25.538637, 4.834561824798583984, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3216.0747 -548.41754 25.538637
+(@GUID+84, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3282.0308, -550.7741, 46.280766, 1.151917338371276855, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3282.0308 -550.7741 46.280766
+(@GUID+85, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3280.8374, -617.0858, 35.034283, 4.345870018005371093, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3280.8374 -617.0858 35.034283
+(@GUID+86, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3248.9495, -581.88226, 30.587183, 4.677482128143310546, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3248.9495 -581.88226 30.587183
+(@GUID+87, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3281.4895, -683.2465, 39.041134, 1.675516128540039062, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3281.4895 -683.2465 39.041134
+(@GUID+88, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3247.2446, -649.0194, 30.383823, 4.328416347503662109, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3247.2446 -649.0194 30.383823
+(@GUID+89, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3215.3052, -682.5738, 29.801714, 2.042035102844238281, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3215.3052 -682.5738 29.801714
+(@GUID+90, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3247.6877, -714.72, 36.439972, 2.652900457382202148, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3247.6877 -714.72 36.439972
+(@GUID+91, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3182.1843, -648.84247, 29.093792, 1.169370532035827636, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3182.1843 -648.84247 29.093792
+(@GUID+92, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3051.3738, -582.958, 25.07603, 1.535889744758605957, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3051.3738 -582.958 25.07603
+(@GUID+93, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3015.6433, -549.345, 31.536392, 0.401425719261169433, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -3015.6433 -549.345 31.536392
+(@GUID+94, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2949.265, -482.95715, 43.765648, 3.089232683181762695, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2949.265 -482.95715 43.765648
+(@GUID+95, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -2984.5002, -517.8174, 39.379818, 3.141592741012573242, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0), -- .go xyz -2984.5002 -517.8174 39.379818
+(@GUID+96, 2955, 0, 0, 1, 0, 0, 1, 1, 0, -3016.3232, -483.44913, 36.235992, 0.663225114345550537, 155, 20, 0, 1, 0, 1, 0, 0, 0, '', 0);
diff --git a/data/sql/updates/db_world/2022_08_15_02.sql b/data/sql/updates/db_world/2022_08_15_02.sql
new file mode 100644
index 000000000..c00dc06ec
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_02.sql
@@ -0,0 +1,4 @@
+-- DB update 2022_08_15_01 -> 2022_08_15_02
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15656) AND (`source_type` = 0) AND (`id` = 2);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(15656, 0, 2, 0, 75, 0, 100, 0, 0, 15958, 20, 1200, 0, 49, 0, 0, 0, 0, 0, 0, 19, 15402, 53, 0, 0, 0, 0, 0, 0, 'Angershade - On Distance To Creature - Start Attacking');
diff --git a/data/sql/updates/db_world/2022_08_15_03.sql b/data/sql/updates/db_world/2022_08_15_03.sql
new file mode 100644
index 000000000..ee1094bba
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_03.sql
@@ -0,0 +1,2 @@
+-- DB update 2022_08_15_02 -> 2022_08_15_03
+UPDATE `creature_addon` SET `bytes2`=1 WHERE `guid`=71028;
diff --git a/data/sql/updates/db_world/2022_08_15_04.sql b/data/sql/updates/db_world/2022_08_15_04.sql
new file mode 100644
index 000000000..f63d5a34f
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_04.sql
@@ -0,0 +1,158 @@
+-- DB update 2022_08_15_03 -> 2022_08_15_04
+--
+DELETE FROM `spell_target_position` WHERE `ID` IN (25708, 25709, 25825, 25826, 25827, 25828);
+INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES
+(25708, 0, 509, -9846, 1353, 106.083336, 0, 0),
+(25709, 0, 509, -9757.87, 1416.71, 76.7664, 0, 0),
+(25825, 0, 509, -9805.95, 1422.85, 77.5852, 0, 0),
+(25826, 0, 509, -9827.58, 1506.28, 82.3052, 0, 0),
+(25827, 0, 509, -9778.91, 1419.98, 61.0743, 0, 0),
+(25828, 0, 509, -9829.42, 1456.37, 90.7015, 0, 0);
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_ayamiss_swarmer_teleport_trigger';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(25830, 'spell_ayamiss_swarmer_teleport_trigger');
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_ayamiss_swarmer_swarm';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(25844, 'spell_ayamiss_swarmer_swarm');
+
+UPDATE `spell_dbc` SET `Effect_1` = 28, `EffectMiscValueB_1` = 64, `EffectBasePoints_1` = 1, `EffectDieSides_1` = 0 WHERE `ID` = 25708;
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_ayamiss_swarmer_start_loop';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(25711, 'spell_ayamiss_swarmer_start_loop');
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_gen_ayamiss_swarmer_loop_1', 'spell_gen_ayamiss_swarmer_loop_2', 'spell_gen_ayamiss_swarmer_loop_3');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(25833, 'spell_gen_ayamiss_swarmer_loop_1'),
+(25834, 'spell_gen_ayamiss_swarmer_loop_2'),
+(25835, 'spell_gen_ayamiss_swarmer_loop_3');
+
+UPDATE `creature_template` SET `ScriptName` = 'npc_hive_zara_swarmer' WHERE `entry` = 15546;
+
+SET @NPC := 15546;
+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, -9758.247, 1426.3112, 84.167656, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9762.383, 1436.3455, 84.428795, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9760.481, 1452.1432, 75.32612, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9754.527, 1466.5826, 61.60388, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9750.208, 1479.4608, 45.937202, 0, 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, -9804.298, 1432.3503, 85.9217, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9799.983, 1443.1294, 82.55095, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9785.31, 1456.0002, 76.88425, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9769.325, 1467.856, 68.520706, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9750.661, 1477.6143, 48.96516, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 2) * 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, -9818.727, 1512.838, 89.24695, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9812.264, 1511.9375, 87.49864, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9806.9375, 1505.4645, 83.19313, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9796.596, 1494.5698, 76.8735, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9781.221, 1486.8652, 71.7902, 0, 0, 0, 0, 100, 0),
+(@PATH, 6, -9765.105, 1476.7782, 63.17909, 0, 0, 0, 0, 100, 0),
+(@PATH, 7, -9753.014, 1478.1317, 50.817974, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 3) * 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, -9776.323, 1428.8531, 65.629776, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9776.123, 1436.0718, 67.35508, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9764.125, 1455.0714, 66.27153, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9754.778, 1466.8633, 62.577053, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9747.529, 1473.6367, 49.077087, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 4) * 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, -9818.173, 1460.0463, 95.69417, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9811.176, 1460.6091, 92.56013, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9802.768, 1455.1123, 86.143425, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9797.88, 1450.7151, 81.69902, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9761.196, 1470.298, 64.64121, 0, 0, 0, 0, 100, 0),
+(@PATH, 6, -9754.684, 1475.3403, 49.030098, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 5) * 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, -9745.072, 1489.5533, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9745.766, 1502.0659, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9734.748, 1502.8883, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9715.551, 1496.5533, 42.267452, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9697.712, 1511.8822, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 6, -9694.466, 1539.3663, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 7, -9696.591, 1561.1914, 41.37858, 0, 0, 0, 0, 100, 0),
+(@PATH, 8, -9667.614, 1571.5212, 43.489666, 0, 0, 0, 0, 100, 0),
+(@PATH, 9, -9653.44, 1552.1632, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 10, -9612.033, 1551.3334, 39.26745, 0, 0, 0, 0, 100, 0),
+(@PATH, 11, -9582.261, 1572.4617, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 12, -9598.483, 1615.416, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 13, -9638.286, 1645.0948, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 14, -9682.366, 1625.8219, 37.211887, 0, 0, 0, 0, 100, 0),
+(@PATH, 15, -9667.457, 1593.8171, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 16, -9625.382, 1598.9684, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 17, -9618.158, 1566.9963, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 18, -9661.183, 1554.485, 42.489677, 0, 0, 0, 0, 100, 0),
+(@PATH, 19, -9690.858, 1543.3951, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 20, -9711.017, 1540.3297, 43.517445, 0, 0, 0, 0, 100, 0),
+(@PATH, 21, -9736.964, 1511.8362, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 22, -9725.431, 1487.6272, 44.323, 0, 0, 0, 0, 100, 0),
+(@PATH, 23, -9742.012, 1485.945, 44.323, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 6) * 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, -9748.129, 1488.4904, 45.764896, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9748.667, 1498.9249, 47.07047, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9744.251, 1508.8634, 46.820465, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9713.56, 1502.6979, 43.542686, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9701.453, 1522.0952, 43.542686, 0, 0, 0, 0, 100, 0),
+(@PATH, 6, -9702.735, 1548.3297, 40.987125, 0, 0, 0, 0, 100, 0),
+(@PATH, 7, -9682.249, 1544.3987, 41.12602, 0, 0, 0, 0, 100, 0),
+(@PATH, 8, -9661.323, 1537.9355, 42.959347, 0, 0, 0, 0, 100, 0),
+(@PATH, 9, -9647.55, 1544.9911, 42.959347, 0, 0, 0, 0, 100, 0),
+(@PATH, 10, -9651.3125, 1565.7776, 42.98713, 0, 0, 0, 0, 100, 0),
+(@PATH, 11, -9657.682, 1593.8557, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 12, -9684.013, 1619.9458, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 13, -9645.765, 1642.1168, 50.042664, 0, 0, 0, 0, 100, 0),
+(@PATH, 14, -9618.591, 1606.9883, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 15, -9624.827, 1566.3673, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 16, -9662.095, 1559.2485, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 17, -9689.207, 1559.972, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 18, -9692.733, 1523.6748, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 19, -9731.375, 1527.3365, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 20, -9729.185, 1490.0042, 45.070454, 0, 0, 0, 0, 100, 0),
+(@PATH, 21, -9745.345, 1485.0509, 45.487125, 0, 0, 0, 0, 100, 0);
+
+SET @PATH := (@NPC + 7) * 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, -9745.88, 1488.399, 45.917397, 0, 0, 0, 0, 100, 0),
+(@PATH, 2, -9744.661, 1507.4883, 46.028458, 0, 0, 0, 0, 100, 0),
+(@PATH, 3, -9735.175, 1527.706, 43.806267, 0, 0, 0, 0, 100, 0),
+(@PATH, 4, -9701.6455, 1545.9641, 44.3896, 0, 0, 0, 0, 100, 0),
+(@PATH, 5, -9658.681, 1541.812, 43.472916, 0, 0, 0, 0, 100, 0),
+(@PATH, 6, -9616.4375, 1554.6978, 41.278492, 0, 0, 0, 0, 100, 0),
+(@PATH, 7, -9583.255, 1572.3322, 42.61181, 0, 0, 0, 0, 100, 0),
+(@PATH, 8, -9594.106, 1611.233, 43.16736, 0, 0, 0, 0, 100, 0),
+(@PATH, 9, -9626.409, 1625.0471, 40.945137, 0, 0, 0, 0, 100, 0),
+(@PATH, 10, -9665.356, 1653.7917, 45.472958, 0, 0, 0, 0, 100, 0),
+(@PATH, 11, -9684.14, 1617.8658, 42.111813, 0, 0, 0, 0, 100, 0),
+(@PATH, 12, -9687.5625, 1573.8448, 43.97294, 0, 0, 0, 0, 100, 0),
+(@PATH, 13, -9690.304, 1535.7795, 44.167366, 0, 0, 0, 0, 100, 0),
+(@PATH, 14, -9711.632, 1498.4967, 41.334064, 0, 0, 0, 0, 100, 0),
+(@PATH, 15, -9741.987, 1484.3424, 45.7785, 0, 0, 0, 0, 100, 0);
+
+DELETE FROM `creature_addon` WHERE `guid` = 144641;
+
+DELETE FROM `creature_template_movement` WHERE `CreatureId` = 15369;
+INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
+(15369, 1, 0, 1, 0, 0, NULL);
diff --git a/data/sql/updates/db_world/2022_08_15_05.sql b/data/sql/updates/db_world/2022_08_15_05.sql
new file mode 100644
index 000000000..335c5db78
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_05.sql
@@ -0,0 +1,12 @@
+-- DB update 2022_08_15_04 -> 2022_08_15_05
+--
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 1491;
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1491) AND (`source_type` = 0) AND (`id` IN (0, 1));
+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
+(1491, 0, 0, 0, 0, 0, 100, 512, 3000, 6000, 7000, 8000, 0, 11, 9080, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Zanzil Naga - In Combat - Cast \'Hamstring\''),
+(1491, 0, 1, 0, 0, 0, 100, 512, 4000, 5000, 10000, 11000, 0, 11, 12555, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Zanzil Naga - In Combat - Cast \'Pummel\'');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 1488;
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1488) AND (`source_type` = 0) AND (`id` IN (0));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(1488, 0, 0, 0, 0, 0, 100, 513, 2000, 3000, 0, 0, 0, 11, 7102, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Zanzil Zombie - In Combat - Cast \'Contagion of Rot\' (No Repeat)');
diff --git a/data/sql/updates/db_world/2022_08_15_06.sql b/data/sql/updates/db_world/2022_08_15_06.sql
new file mode 100644
index 000000000..41eb9c252
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_06.sql
@@ -0,0 +1,3 @@
+-- DB update 2022_08_15_05 -> 2022_08_15_06
+--
+UPDATE `gameobject_template_addon` SET `flags`=`flags`|1 WHERE `entry`=180619;
diff --git a/data/sql/updates/db_world/2022_08_15_07.sql b/data/sql/updates/db_world/2022_08_15_07.sql
new file mode 100644
index 000000000..1aef808c9
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_07.sql
@@ -0,0 +1,63 @@
+-- DB update 2022_08_15_06 -> 2022_08_15_07
+DELETE FROM `creature_queststarter` WHERE `quest` IN (6821, 6822, 6823, 6824, 7486) AND `id` = 13278;
+INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES
+(13278, 6821), -- Eye of the Emberseer
+(13278, 6822), -- The Molten Core
+(13278, 6823), -- Agent of Hydraxis
+(13278, 6824), -- Hands of the Enemy
+(13278, 7486); -- A Hero's Reward
+
+DELETE FROM `creature_questender` WHERE `quest` IN (6804, 6821, 6822, 6823, 6824) AND `id` = 13278;
+INSERT INTO `creature_questender` (`id`, `quest`) VALUES
+(13278, 6804), -- Poisoned Water
+(13278, 6821), -- Eye of the Emberseer
+(13278, 6822), -- The Molten Core
+(13278, 6823), -- Agent of Hydraxis
+(13278, 6824); -- Hands of the Enemy
+
+DELETE FROM `quest_template_addon` WHERE `ID` IN (6821, 6822, 6823, 6824, 7486);
+INSERT INTO `quest_template_addon` (`ID`, `PrevQuestID`, `NextQuestID`) VALUES
+(6821, 6805, 6822),
+(6822, 6021, 6823),
+(6823, 6022, 6824),
+(6824, 6823, 7486),
+(7486, 6824, 0);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` = 6821;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(19, 0, 6821, 0, 0, 47, 0, 6804, 64, 0, 0, 0, 0, '', 'Quest Eyes of the Emberseer available if quest Poisoned Water has been rewarded.'),
+(19, 0, 6821, 0, 0, 47, 0, 6805, 64, 0, 0, 0, 0, '', 'Quest Eyes of the Emberseer available if quest Stormers and Rumblers has been rewarded.');
+
+DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 5065) AND (`SourceId` IN (0, 1));
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(15, 5065, 0, 0, 0, 5, 0, 749, 224, 0, 0, 0, 0, '', 'Duke Hydraxis - Create Aqual Quintessence Gossip - Requires Honored Rep'),
+(15, 5065, 0, 0, 0, 47, 0, 6824, 64, 0, 0, 0, 0, '', 'Duke Hydraxis - Aqual Quintessence Gossip available if quest Hand of the Enemy rewarded.'),
+(15, 5065, 1, 0, 0, 5, 0, 749, 192, 0, 0, 0, 0, '', 'Duke Hydraxis - Create Eternal Quintessence Gossip - Requires Revered Rep'),
+(15, 5065, 1, 0, 0, 47, 0, 6824, 64, 0, 0, 0, 0, '', 'Duke Hydraxis - Create Eternal Quintessence Gossip - Requires Hand of the Enemy rewarded');
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` IN (6822, 6823, 6824, 7486);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(19, 0, 6822, 0, 0, 47, 0, 6821, 64, 0, 0, 0, 0, '', 'Quest Molten Core available if quest Eye of the Emberseer has been rewarded.'),
+(19, 0, 6823, 0, 0, 47, 0, 6822, 64, 0, 0, 0, 0, '', 'Quest Agent of Hydraxis available if quest Molten Core has been rewarded.'),
+(19, 0, 6824, 0, 0, 47, 0, 6823, 64, 0, 0, 0, 0, '', 'Quest Hands of the Enemy available if quest Agents of Hydraxis has been rewarded.'),
+(19, 0, 7486, 0, 0, 47, 0, 6824, 64, 0, 0, 0, 0, '', 'Quest A Hero\'s Reward available if quest Hands of the Enemy has been rewarded.');
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 19 AND `SourceEntry` IN (6822, 6823, 6824, 7486);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(19, 0, 6822, 0, 0, 47, 0, 6821, 64, 0, 0, 0, 0, '', 'Quest Molten Core available if quest Eye of the Emberseer has been rewarded.'),
+(19, 0, 6823, 0, 0, 47, 0, 6822, 64, 0, 0, 0, 0, '', 'Quest Agent of Hydraxis available if quest Molten Core has been rewarded.'),
+(19, 0, 6824, 0, 0, 47, 0, 6823, 64, 0, 0, 0, 0, '', 'Quest Hands of the Enemy available if quest Agents of Hydraxis has been rewarded.'),
+(19, 0, 7486, 0, 0, 47, 0, 6824, 64, 0, 0, 0, 0, '', 'Quest A Hero\'s Reward available if quest Hands of the Enemy has been rewarded.');
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 13278;
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 13278) 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`, `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
+(13278, 0, 0, 1, 62, 0, 100, 0, 5065, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Duke Hydraxis - On Gossip Option 0 Selected - Close Gossip'),
+(13278, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 56, 17333, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Duke Hydraxis - On Link - Add item \'Aqual Quintessence\''),
+(13278, 0, 2, 3, 62, 0, 100, 0, 5065, 1, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Duke Hydraxis - On Gossip Option 1 Selected - Close Gossip'),
+(13278, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 56, 22754, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Duke Hydraxis - On Link - Add item \' Eternal Quintessence\'');
+
+DELETE FROM `gossip_menu_option` WHERE `MenuID` = 5065 AND `OptionID` IN (0, 1);
+INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
+(5065,0,0,'I require a vial of aqual quintessence, Hydraxis, for I go to the Molten Core to extinguish a rune of the Firelords.',8666,1,2,0,0,0,0,'',0,0),
+(5065,1,0,'I desire this eternal quintessence, Duke Hydraxis.',12363,1,2,0,0,0,0,'',0,0);
diff --git a/data/sql/updates/db_world/2022_08_15_08.sql b/data/sql/updates/db_world/2022_08_15_08.sql
new file mode 100644
index 000000000..8e8745d1a
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_15_08.sql
@@ -0,0 +1,5 @@
+-- DB update 2022_08_15_07 -> 2022_08_15_08
+--
+UPDATE `creature_template` SET `unit_flags` = `unit_flags` | 33554432, `ScriptName` = 'npc_dirt_mound' WHERE `entry` = 15712;
+
+UPDATE `gameobject_template_addon` SET `flags` = `flags` | 16 WHERE `entry` = 180795;
diff --git a/data/sql/updates/db_world/2022_08_16_00.sql b/data/sql/updates/db_world/2022_08_16_00.sql
new file mode 100644
index 000000000..d1a2a259e
--- /dev/null
+++ b/data/sql/updates/db_world/2022_08_16_00.sql
@@ -0,0 +1,60 @@
+-- DB update 2022_08_15_08 -> 2022_08_16_00
+--
+UPDATE `quest_template_addon` SET `SpecialFlags` = `SpecialFlags` | 1 WHERE `id` IN (8805, 8807);
+
+SET @ENTRY := 21132;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 20939, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment II - Alliance"),
+(@ENTRY, 21257, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment IV"),
+(@ENTRY, 21259, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment V"),
+(@ENTRY, 21260, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment VI"),
+(@ENTRY, 21263, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment VII"),
+(@ENTRY, 20806, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment X");
+
+SET @ENTRY := 21266;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 21379, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment II - Horde"),
+(@ENTRY, 21258, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment IV - Horde"),
+(@ENTRY, 21382, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment V - Horde"),
+(@ENTRY, 21261, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment VI - Horde"),
+(@ENTRY, 21264, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment VII - Horde"),
+(@ENTRY, 21385, 0, 0, 0, 1, 1, 1, 1, "Logistics Assigment X - Horde");
+
+
+SET @ENTRY := 20805;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 20807, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment I - Alliance"),
+(@ENTRY, 20940, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment III - Alliance"),
+(@ENTRY, 21262, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment VIII - Alliance"),
+(@ENTRY, 21265, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment IX - Alliance"),
+(@ENTRY, 21514, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment XI - Alliance");
+
+SET @ENTRY := 21386;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 21378, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment I - Horde"),
+(@ENTRY, 21380, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment III - Horde"),
+(@ENTRY, 21384, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment VIII - Horde"),
+(@ENTRY, 21381, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment IX - Horde"),
+(@ENTRY, 21514, 0, 0, 0, 1, 1, 1, 1, "Logistics Assignment XI - Horde");
+
+SET @ENTRY := 20809;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 21245, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment I - Horde"),
+(@ENTRY, 21751, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment III - Horde"),
+(@ENTRY, 21165, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment VI - Horde"),
+(@ENTRY, 21166, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment VII - Horde"),
+(@ENTRY, 20944, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment IX - Horde");
+
+SET @ENTRY := 21133;
+DELETE FROM `item_loot_template` WHERE `Entry` = @ENTRY;
+INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(@ENTRY, 20945, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment II - Horde"),
+(@ENTRY, 20947, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment IV - Horde"),
+(@ENTRY, 20948, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment V - Horde"),
+(@ENTRY, 21167, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment VIII - Horde"),
+(@ENTRY, 20943, 0, 0, 0, 1, 1, 1, 1, "Tactical Assignment X - Horde");
diff --git a/src/common/Utilities/EventEmitter.h b/src/common/Utilities/EventEmitter.h
new file mode 100644
index 000000000..77755935b
--- /dev/null
+++ b/src/common/Utilities/EventEmitter.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#ifndef __EVENT_EMITTER_H
+#define __EVENT_EMITTER_H
+
+template
+class EventEmitter
+{
+public:
+ template
+ void operator+=(Functor&& f)
+ {
+ functions.emplace_back(std::forward(f));
+ }
+
+ template
+ void operator()(Args&&... args) const
+ {
+ for (auto& f : functions)
+ {
+ f(args...);
+ }
+ }
+
+private:
+ std::vector> functions;
+};
+
+#endif
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 314c37b17..dd44d437a 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -102,7 +102,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, "
"item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_ENTRY_POINT, "SELECT joinX, joinY, joinZ, joinO, joinMapId, taxiPath, mountSpell FROM character_entry_point WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_ENTRY_POINT, "SELECT joinX, joinY, joinZ, joinO, joinMapId, taxiPath0, taxiPath1, mountSpell FROM character_entry_point WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, specMask FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC);
@@ -286,7 +286,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_ARENA_TEAM_NAME, "UPDATE arena_team SET name = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
// Character battleground data
- PrepareStatement(CHAR_INS_PLAYER_ENTRY_POINT, "INSERT INTO character_entry_point (guid, joinX, joinY, joinZ, joinO, joinMapId, taxiPath, mountSpell) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_PLAYER_ENTRY_POINT, "INSERT INTO character_entry_point (guid, joinX, joinY, joinZ, joinO, joinMapId, taxiPath0, taxiPath1, mountSpell) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_ENTRY_POINT, "DELETE FROM character_entry_point WHERE guid = ?", CONNECTION_ASYNC);
// Character homebind
diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp
index d1ac8350f..f8b8973d7 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.cpp
+++ b/src/server/game/AI/CoreAI/PassiveAI.cpp
@@ -29,7 +29,7 @@ int32 NullCreatureAI::Permissible(Creature const* creature)
return PERMIT_BASE_PROACTIVE + 50;
if (creature->IsTrigger())
- return PERMIT_BASE_REACTIVE;
+ return PERMIT_BASE_PROACTIVE;
return PERMIT_BASE_IDLE;
}
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index baf48ef86..1304a6cfe 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -90,6 +90,24 @@ bool UnitAI::DoSpellAttackIfReady(uint32 spell)
return false;
}
+void UnitAI::DoSpellAttackToRandomTargetIfReady(uint32 spell, uint32 threatTablePosition /*= 0*/, float dist /*= 0.f*/, bool playerOnly /*= true*/)
+{
+ if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady())
+ return;
+
+ if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell))
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, threatTablePosition, dist, playerOnly))
+ {
+ if (me->IsWithinCombatRange(target, spellInfo->GetMaxRange(false)))
+ {
+ me->CastSpell(target, spell, false);
+ me->resetAttackTimer();
+ }
+ }
+ }
+}
+
Unit* UnitAI::SelectTarget(SelectTargetMethod targetType, uint32 position, float dist, bool playerOnly, int32 aura)
{
return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura));
@@ -106,6 +124,14 @@ float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive)
return spellInfo ? spellInfo->GetMaxRange(positive) : 0;
}
+std::string UnitAI::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << std::boolalpha
+ << "Me: " << (me ? me->GetDebugInfo() : "NULL");
+ return sstr.str();
+}
+
SpellCastResult UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid)
{
if (me->IsInCombat())
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index ae24f2dcb..a423997b9 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -330,6 +330,7 @@ public:
void DoMeleeAttackIfReady();
bool DoSpellAttackIfReady(uint32 spell);
+ void DoSpellAttackToRandomTargetIfReady(uint32 spell, uint32 threatTablePosition = 0, float dist = 0.f, bool playerOnly = true);
static AISpellInfoType* AISpellInfo;
static void FillAISpellInfo();
@@ -345,6 +346,8 @@ public:
virtual void sQuestComplete(Player* /*player*/, Quest const* /*quest*/) {}
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {}
virtual void sOnGameEvent(bool /*start*/, uint16 /*eventId*/) {}
+
+ virtual std::string GetDebugInfo() const;
};
class PlayerAI : public UnitAI
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 29cda5530..61db4f067 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -917,7 +917,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (IsUnit(target))
{
float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle;
- CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType);
+ CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType, e.action.follow.aliveState);
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}",
me->GetGUID().ToString(), target->GetGUID().ToString());
break;
@@ -3187,6 +3187,10 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
{
targets.push_back(owner);
}
+ else if (me->IsSummon() && me->ToTempSummon()->GetSummonerUnit())
+ {
+ targets.push_back(me->ToTempSummon()->GetSummonerUnit());
+ }
}
else if (go)
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 92c24beaa..80c2eb221 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -492,7 +492,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
case SMART_EVENT_IC_LOS: return sizeof(SmartEvent::los);
case SMART_EVENT_PASSENGER_BOARDED: return sizeof(SmartEvent::minMax);
case SMART_EVENT_PASSENGER_REMOVED: return sizeof(SmartEvent::minMax);
- // case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
+ case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
case SMART_EVENT_CHARMED_TARGET: return NO_PARAMS;
case SMART_EVENT_SPELLHIT_TARGET: return sizeof(SmartEvent::spellHit);
case SMART_EVENT_DAMAGED: return sizeof(SmartEvent::minMaxRepeat);
@@ -533,7 +533,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget);
case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent);
case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent);
- // case SMART_EVENT_GO_LOOT_STATE_CHANGED: return sizeof(SmartEvent::goLootStateChanged);
+ case SMART_EVENT_GO_STATE_CHANGED: return sizeof(SmartEvent::goStateChanged);
case SMART_EVENT_GO_EVENT_INFORM: return sizeof(SmartEvent::eventInform);
case SMART_EVENT_ACTION_DONE: return sizeof(SmartEvent::doAction);
case SMART_EVENT_ON_SPELLCLICK: return NO_PARAMS;
@@ -546,9 +546,11 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
//case SMART_EVENT_SCENE_CANCEL: return sizeof(SmartEvent::raw);
//case SMART_EVENT_SCENE_COMPLETE: return sizeof(SmartEvent::raw);
case SMART_EVENT_SUMMONED_UNIT_DIES: return sizeof(SmartEvent::summoned);
+ case SMART_EVENT_NEAR_PLAYERS: return sizeof(SmartEvent::nearPlayer);
+ case SMART_EVENT_NEAR_PLAYERS_NEGATION: return sizeof(SmartEvent::nearPlayerNegation);
default:
- LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
- e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
+ LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
+ e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType());
return sizeof(SmartEvent::raw);
}
}();
@@ -602,8 +604,8 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: return sizeof(SmartAction::combatMove);
case SMART_ACTION_SET_EVENT_PHASE: return sizeof(SmartAction::setEventPhase);
case SMART_ACTION_INC_EVENT_PHASE: return sizeof(SmartAction::incEventPhase);
- // case SMART_ACTION_EVADE: return sizeof(SmartAction::evade);
- // case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::fleeAssist);
+ case SMART_ACTION_EVADE: return NO_PARAMS;
+ case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::flee);
case SMART_ACTION_CALL_GROUPEVENTHAPPENS: return sizeof(SmartAction::quest);
case SMART_ACTION_COMBAT_STOP: return NO_PARAMS;
case SMART_ACTION_REMOVEAURASFROMSPELL: return sizeof(SmartAction::removeAura);
@@ -624,9 +626,10 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: return sizeof(SmartAction::morphOrMount);
case SMART_ACTION_SET_INGAME_PHASE_MASK: return sizeof(SmartAction::ingamePhaseMask);
case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData);
+ case SMART_ACTION_MOVE_FORWARD: return sizeof(SmartAction::moveRandom);
case SMART_ACTION_ATTACK_STOP: return NO_PARAMS;
case SMART_ACTION_SET_VISIBILITY: return sizeof(SmartAction::visibility);
- // case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::active);
+ case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::setActive);
case SMART_ACTION_ATTACK_START: return NO_PARAMS;
case SMART_ACTION_SUMMON_GO: return sizeof(SmartAction::summonGO);
case SMART_ACTION_KILL_UNIT: return NO_PARAMS;
@@ -638,7 +641,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_REMOVE_ITEM: return sizeof(SmartAction::item);
case SMART_ACTION_INSTALL_AI_TEMPLATE: return sizeof(SmartAction::installTtemplate);
case SMART_ACTION_SET_RUN: return sizeof(SmartAction::setRun);
- // case SMART_ACTION_SET_DISABLE_GRAVITY: return sizeof(SmartAction::setDisableGravity);
+ case SMART_ACTION_SET_FLY: return sizeof(SmartAction::setFly);
case SMART_ACTION_SET_SWIM: return sizeof(SmartAction::setSwim);
case SMART_ACTION_TELEPORT: return sizeof(SmartAction::teleport);
case SMART_ACTION_SET_COUNTER: return sizeof(SmartAction::setCounter);
@@ -648,7 +651,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_CREATE_TIMED_EVENT: return sizeof(SmartAction::timeEvent);
case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie);
case SMART_ACTION_MOVE_TO_POS: return sizeof(SmartAction::moveToPos);
- // case SMART_ACTION_ENABLE_TEMP_GOBJ: return sizeof(SmartAction::enableTempGO);
+ case SMART_ACTION_RESPAWN_TARGET: return sizeof(SmartAction::RespawnTarget);
case SMART_ACTION_EQUIP: return sizeof(SmartAction::equip);
case SMART_ACTION_CLOSE_GOSSIP: return NO_PARAMS;
case SMART_ACTION_TRIGGER_TIMED_EVENT: return sizeof(SmartAction::timeEvent);
@@ -663,7 +666,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_REMOVE_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_SIMPLE_TALK: return sizeof(SmartAction::simpleTalk);
- // case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast);
+ case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_CROSS_CAST: return sizeof(SmartAction::crossCast);
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: return sizeof(SmartAction::randTimedActionList);
case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: return sizeof(SmartAction::randRangeTimedActionList);
@@ -692,7 +695,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
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_MOVE_OFFSET: return NO_PARAMS;
+ 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);
case SMART_ACTION_DISABLE_EVADE: return sizeof(SmartAction::disableEvade);
@@ -722,6 +725,19 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover);
case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct);
//case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw);
+ case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPos);
+ case SMART_ACTION_SET_GO_STATE: return sizeof(SmartAction::goState);
+ case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
+ case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: return sizeof(SmartAction::movementFlag);
+ case SMART_ACTION_SET_COMBAT_DISTANCE: return sizeof(SmartAction::combatDistance);
+ case SMART_ACTION_SET_CASTER_COMBAT_DIST: return sizeof(SmartAction::casterDistance);
+ case SMART_ACTION_FALL: return NO_PARAMS;
+ case SMART_ACTION_SET_EVENT_FLAG_RESET: return sizeof(SmartAction::setActive);
+ case SMART_ACTION_STOP_MOTION: return sizeof(SmartAction::stopMotion);
+ case SMART_ACTION_NO_ENVIRONMENT_UPDATE: return NO_PARAMS;
+ case SMART_ACTION_ZONE_UNDER_ATTACK: return NO_PARAMS;
+ case SMART_ACTION_LOAD_GRID: return NO_PARAMS;
+ case SMART_ACTION_MUSIC: return sizeof(SmartAction::music);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -785,9 +801,10 @@ bool SmartAIMgr::CheckUnusedTargetParams(SmartScriptHolder const& e)
case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest);
case SMART_TARGET_VEHICLE_PASSENGER: return sizeof(SmartTarget::vehicle);
// case SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT: return sizeof(SmartTarget::goClosest);
+ case SMART_TARGET_PLAYER_WITH_AURA: return sizeof(SmartTarget::playerWithAura);
default:
- LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using a target with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.",
- e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
+ LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using a target {} with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.",
+ e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
return sizeof(SmartTarget::raw);
}
}();
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
index 7f1cbe78b..43f9b7320 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
@@ -86,28 +86,29 @@ bool BattlegroundQueue::SelectionPool::KickGroup(const uint32 size)
// find last group with proper size or largest
bool foundProper = false;
- auto groupToKick = SelectedGroups.begin();
- for (auto& itr = groupToKick; itr != SelectedGroups.end(); ++itr)
+ GroupQueueInfo* groupToKick{ SelectedGroups.front() };
+
+ for (auto const& gInfo : SelectedGroups)
{
// if proper size - overwrite to kick last one
- if (std::abs(int32((*itr)->Players.size()) - (int32)size) <= 1)
+ if (std::abs(int32(gInfo->Players.size()) - (int32)size) <= 1)
{
- groupToKick = itr;
+ groupToKick = gInfo;
foundProper = true;
}
- else if (!foundProper && (*itr)->Players.size() >= (*groupToKick)->Players.size())
- groupToKick = itr;
+ else if (!foundProper && gInfo->Players.size() >= groupToKick->Players.size())
+ groupToKick = gInfo;
}
// remove selected from pool
- GroupQueueInfo* ginfo = (*groupToKick);
- SelectedGroups.erase(groupToKick);
- PlayerCount -= ginfo->Players.size();
+ auto playersCountInGroup{ groupToKick->Players.size() };
+ PlayerCount -= playersCountInGroup;
+ std::erase(SelectedGroups, groupToKick);
if (foundProper)
return false;
- return (ginfo->Players.size() > size);
+ return playersCountInGroup > size;
}
// returns true if added or desired count not yet reached
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index ccf220a9c..7a03bd85c 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -565,11 +565,11 @@ void LoadDBCStores(const std::string& dataPath)
if (sInfo->Effect[j] == SPELL_EFFECT_SEND_TAXI)
spellPaths.insert(sInfo->EffectMiscValue[j]);
- memset(sTaxiNodesMask, 0, sizeof(sTaxiNodesMask));
- memset(sOldContinentsNodesMask, 0, sizeof(sOldContinentsNodesMask));
- memset(sHordeTaxiNodesMask, 0, sizeof(sHordeTaxiNodesMask));
- memset(sAllianceTaxiNodesMask, 0, sizeof(sAllianceTaxiNodesMask));
- memset(sDeathKnightTaxiNodesMask, 0, sizeof(sDeathKnightTaxiNodesMask));
+ sTaxiNodesMask.fill(0);
+ sOldContinentsNodesMask.fill(0);
+ sHordeTaxiNodesMask.fill(0);
+ sAllianceTaxiNodesMask.fill(0);
+ sDeathKnightTaxiNodesMask.fill(0);
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
{
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 7e261d8d7..34976db59 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -3656,3 +3656,12 @@ uint32 Creature::GetPlayerDamageReq() const
{
return _playerDamageReq;
}
+
+std::string Creature::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Unit::GetDebugInfo() << "\n"
+ << "AIName: " << GetAIName() << " ScriptName: " << GetScriptName()
+ << " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index ffafd9bf4..782e94ffa 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -385,6 +385,8 @@ public:
void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration);
+ std::string GetDebugInfo() const override;
+
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp
index 9f3c289e5..a76ea477f 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.cpp
+++ b/src/server/game/Entities/Creature/TemporarySummon.cpp
@@ -320,6 +320,15 @@ void TempSummon::RemoveFromWorld()
Creature::RemoveFromWorld();
}
+std::string TempSummon::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Creature::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "TempSummonType : " << std::to_string(GetSummonType()) << " Summoner: " << GetSummonerGUID().ToString();
+ return sstr.str();
+}
+
Minion::Minion(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : TempSummon(properties, owner, isWorldObject)
, m_owner(owner)
{
@@ -378,6 +387,15 @@ void Minion::setDeathState(DeathState s, bool despawn)
}
}
+std::string Minion::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << TempSummon::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "Owner: " << (GetOwner() ? GetOwner()->GetGUID().ToString() : "");
+ return sstr.str();
+}
+
Guardian::Guardian(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) : Minion(properties, owner, isWorldObject)
{
m_unitTypeMask |= UNIT_MASK_GUARDIAN;
@@ -416,6 +434,13 @@ void Guardian::InitSummon()
}
}
+std::string Guardian::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Minion::GetDebugInfo();
+ return sstr.str();
+}
+
Puppet::Puppet(SummonPropertiesEntry const* properties, ObjectGuid owner) : Minion(properties, owner, false), m_owner(owner) //maybe true?
{
ASSERT(owner.IsPlayer());
diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h
index c9700e8da..3e005270f 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.h
+++ b/src/server/game/Entities/Creature/TemporarySummon.h
@@ -52,12 +52,14 @@ public:
[[nodiscard]] Unit* GetSummonerUnit() const;
[[nodiscard]] Creature* GetSummonerCreatureBase() const;
[[nodiscard]] GameObject* GetSummonerGameObject() const;
- ObjectGuid GetSummonerGUID() { return m_summonerGUID; }
- TempSummonType const& GetSummonType() { return m_type; }
+ ObjectGuid GetSummonerGUID() const { return m_summonerGUID; }
+ TempSummonType GetSummonType() const { return m_type; }
uint32 GetTimer() { return m_timer; }
void SetTimer(uint32 t) { m_timer = t; }
const SummonPropertiesEntry* const m_Properties;
+
+ std::string GetDebugInfo() const override;
private:
TempSummonType m_type;
uint32 m_timer;
@@ -77,6 +79,8 @@ public:
[[nodiscard]] bool IsPetGhoul() const {return GetEntry() == 26125 /*normal ghoul*/ || GetEntry() == 30230 /*Raise Ally ghoul*/;} // Ghoul may be guardian or pet
[[nodiscard]] bool IsGuardianPet() const;
void setDeathState(DeathState s, bool despawn = false) override; // override virtual Unit::setDeathState
+
+ std::string GetDebugInfo() const override;
protected:
const ObjectGuid m_owner;
float m_followAngle;
@@ -97,6 +101,8 @@ public:
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void UpdateDamagePhysical(WeaponAttackType attType) override;
+
+ std::string GetDebugInfo() const override;
};
class Puppet : public Minion
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index f7dae5606..50a36df5e 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -131,7 +131,7 @@ void GameObject::RemoveFromOwner()
return;
}
- LOG_FATAL("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list. Crash possible later.",
+ LOG_DEBUG("entities.gameobject", "Delete GameObject ({} Entry: {} SpellId {} LinkedGO {}) that lost references to owner {} GO list.",
GetGUID().ToString(), GetGOInfo()->entry, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), ownerGUID.ToString());
SetOwnerGUID(ObjectGuid::Empty);
@@ -3091,3 +3091,11 @@ bool GameObject::IsInSkillupList(ObjectGuid playerGuid) const
return false;
}
+
+std::string GameObject::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << WorldObject::GetDebugInfo() << "\n"
+ << "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index d74f7cccd..ce62f7a55 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -1061,6 +1061,8 @@ public:
void UpdateSaveToDb(bool enable);
void SavingStateOnDB();
+
+ std::string GetDebugInfo() const override;
protected:
bool AIM_Initialize();
GameObjectModel* CreateModel();
diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp
index 4d887f082..ad7164c56 100644
--- a/src/server/game/Entities/Item/Container/Bag.cpp
+++ b/src/server/game/Entities/Item/Container/Bag.cpp
@@ -239,3 +239,10 @@ Item* Bag::GetItemByPos(uint8 slot) const
return nullptr;
}
+
+std::string Bag::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Item::GetDebugInfo();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h
index afd59d1c5..dfe7654f8 100644
--- a/src/server/game/Entities/Item/Container/Bag.h
+++ b/src/server/game/Entities/Item/Container/Bag.h
@@ -35,7 +35,6 @@ public:
bool Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owner) override;
- void Clear();
void StoreItem(uint8 slot, Item* pItem, bool update);
void RemoveItem(uint8 slot, bool update);
@@ -58,6 +57,8 @@ public:
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
+ std::string GetDebugInfo() const override;
+
protected:
// Bag Storage space
Item* m_bagslot[MAX_BAG_SIZE];
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index 01149086f..bfcb13892 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -1097,7 +1097,7 @@ Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clo
if (count > pProto->GetMaxStackSize())
count = pProto->GetMaxStackSize();
- ASSERT(count != 0 && "pProto->Stackable == 0 but checked at loading already");
+ ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already");
Item* pItem = NewItemOrBag(pProto);
if (pItem->Create(sObjectMgr->GetGenerator().Generate(), item, player))
@@ -1287,3 +1287,13 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
+
+std::string Item::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Object::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "Owner: " << GetOwnerGUID().ToString() << " Count: " << GetCount()
+ << " BagSlot: " << std::to_string(GetBagSlot()) << " Slot: " << std::to_string(GetSlot()) << " Equipped: " << IsEquipped();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 6be9b0cfe..300e7a6a1 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -353,6 +353,8 @@ public:
void RemoveFromObjectUpdate() override;
[[nodiscard]] uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
+
+ std::string GetDebugInfo() const override;
private:
std::string m_text;
uint8 m_slot;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index ac23ffbaf..506f4c3f9 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1010,6 +1010,13 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
+std::string Object::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << GetGUID().ToString() + " Entry " << GetEntry();
+ return sstr.str();
+}
+
void MovementInfo::OutDebug()
{
LOG_INFO("movement", "MOVEMENT INFO");
@@ -2419,6 +2426,15 @@ Player* WorldObject::SelectNearestPlayer(float distance) const
return target;
}
+std::string WorldObject::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << WorldLocation::GetDebugInfo() << "\n"
+ << Object::GetDebugInfo() << "\n"
+ << "Name: " << GetName();
+ return sstr.str();
+}
+
void WorldObject::GetGameObjectListWithEntryInGrid(std::list& gameobjectList, uint32 entry, float maxSearchRange) const
{
Acore::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index bb1bbb476..a7dcd97e3 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -208,6 +208,8 @@ public:
DynamicObject* ToDynObject() { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast(this); else return nullptr; }
[[nodiscard]] DynamicObject const* ToDynObject() const { if (GetTypeId() == TYPEID_DYNAMICOBJECT) return reinterpret_cast(this); else return nullptr; }
+ virtual std::string GetDebugInfo() const;
+
DataMap CustomData;
protected:
@@ -613,6 +615,8 @@ public:
[[nodiscard]] bool HasAllowedLooter(ObjectGuid guid) const;
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
+ std::string GetDebugInfo() const override;
+
ElunaEventProcessor* elunaEvents;
protected:
diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp
index a4920bfb4..90302ac4c 100644
--- a/src/server/game/Entities/Object/Position.cpp
+++ b/src/server/game/Entities/Object/Position.cpp
@@ -208,3 +208,10 @@ ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& st
buf << x << y << z << o;
return buf;
}
+
+std::string WorldLocation::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << "MapID: " << m_mapId << " " << Position::ToString();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h
index 98f51e86b..8b87368d1 100644
--- a/src/server/game/Entities/Object/Position.h
+++ b/src/server/game/Entities/Object/Position.h
@@ -317,6 +317,8 @@ public:
}
uint32 m_mapId;
+
+ std::string GetDebugInfo() const;
};
ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer);
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 79ea17ede..dd78a94b7 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -2439,3 +2439,13 @@ std::string Pet::GenerateActionBarData() const
return oss.str();
}
+
+std::string Pet::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Guardian::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "PetType: " << std::to_string(getPetType()) << " "
+ << "PetNumber: " << m_charmInfo->GetPetNumber();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h
index 2f9b84167..12086749d 100644
--- a/src/server/game/Entities/Pet/Pet.h
+++ b/src/server/game/Entities/Pet/Pet.h
@@ -143,6 +143,8 @@ public:
void SetLoading(bool load) { m_loading = load; }
[[nodiscard]] bool HasTempSpell() const { return m_tempspell != 0; }
+
+ std::string GetDebugInfo() const override;
protected:
Player* m_owner;
int32 m_happinessTimer;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 949fc9707..701cafe4e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -222,6 +222,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_bHasDelayedTeleport = false;
teleportStore_options = 0;
m_canTeleport = false;
+ m_canKnockback = false;
m_trade = nullptr;
@@ -1644,10 +1645,8 @@ void Player::ProcessDelayedOperations()
{
if (m_entryPointData.HasTaxiPath())
{
- for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
- m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
- m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
-
+ m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
+ m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
ContinueTaxiFlight();
}
@@ -10004,26 +10003,6 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
return false;
}
- // check node starting pos data set case if provided
- if (node->x != 0.0f || node->y != 0.0f || node->z != 0.0f)
- {
- if (node->map_id != GetMapId() ||
- (node->x - GetPositionX()) * (node->x - GetPositionX()) +
- (node->y - GetPositionY()) * (node->y - GetPositionY()) +
- (node->z - GetPositionZ()) * (node->z - GetPositionZ()) >
- (2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE) * (2 * INTERACTION_DISTANCE))
- {
- GetSession()->SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
- return false;
- }
- }
- // node must have pos if taxi master case (npc != nullptr)
- else if (npc)
- {
- GetSession()->SendActivateTaxiReply(ERR_TAXIUNSPECIFIEDSERVERERROR);
- return false;
- }
-
// Prepare to flight start now
// stop combat at start taxi flight if any
@@ -10045,6 +10024,7 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
// fill destinations path tail
uint32 sourcepath = 0;
uint32 totalcost = 0;
+ uint32 firstcost = 0;
uint32 prevnode = sourcenode;
uint32 lastnode = 0;
@@ -10063,6 +10043,8 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
}
totalcost += cost;
+ if (i == 1)
+ firstcost = cost;
if (prevnode == sourcenode)
sourcepath = path;
@@ -10091,7 +10073,16 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
uint32 money = GetMoney();
if (npc)
- totalcost = (uint32)ceil(totalcost * GetReputationPriceDiscount(npc));
+ {
+ float discount = GetReputationPriceDiscount(npc);
+ totalcost = uint32(ceil(totalcost * discount));
+ firstcost = uint32(ceil(firstcost * discount));
+ m_taxi.SetFlightMasterFactionTemplateId(npc->GetFaction());
+ }
+ else
+ {
+ m_taxi.SetFlightMasterFactionTemplateId(0);
+ }
if (money < totalcost)
{
@@ -10102,8 +10093,6 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
//Checks and preparations done, DO FLIGHT
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1);
- ModifyMoney(-(int32)totalcost);
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
// prevent stealth flight
//RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
@@ -10113,12 +10102,16 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc
{
TaxiNodesEntry const* lastPathNode = sTaxiNodesStore.LookupEntry(nodes[nodes.size() - 1]);
m_taxi.ClearTaxiDestinations();
+ ModifyMoney(-(int32)totalcost);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
TeleportTo(lastPathNode->map_id, lastPathNode->x, lastPathNode->y, lastPathNode->z, GetOrientation());
return false;
}
else
{
m_flightSpellActivated = spellid;
+ ModifyMoney(-(int32)firstcost);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, firstcost);
GetSession()->SendActivateTaxiReply(ERR_TAXIOK);
GetSession()->SendDoFlight(mount_display_id, sourcepath);
}
@@ -10214,6 +10207,39 @@ void Player::ContinueTaxiFlight()
GetSession()->SendDoFlight(mountDisplayId, path, startNode);
}
+void Player::SendTaxiNodeStatusMultiple()
+{
+ for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
+ {
+ if (!itr->IsCreature())
+ {
+ continue;
+ }
+
+ Creature* creature = ObjectAccessor::GetCreature(*this, *itr);
+ if (!creature || creature->IsHostileTo(this))
+ {
+ continue;
+ }
+
+ if (!creature->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
+ {
+ continue;
+ }
+
+ uint32 nearestNode = sObjectMgr->GetNearestTaxiNode(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetMapId(), GetTeamId());
+ if (!nearestNode)
+ {
+ continue;
+ }
+
+ WorldPacket data(SMSG_TAXINODE_STATUS, 9);
+ data << *itr;
+ data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 0);
+ SendDirectMessage(&data);
+ }
+}
+
void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
{
PacketCooldowns cooldowns;
@@ -10984,11 +11010,8 @@ void Player::SetEntryPoint()
m_entryPointData.mountSpell = 0;
m_entryPointData.joinPos = WorldLocation(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
- std::vector const& taxi = m_taxi.GetPath();
- for (std::vector::const_iterator itr = taxi.begin(); itr != taxi.end(); ++itr)
- m_entryPointData.taxiPath.push_back(*itr);
-
- m_entryPointData.taxiPath.push_back(m_taxi.GetTaxiSegment());
+ m_entryPointData.taxiPath[0] = m_taxi.GetTaxiSource();
+ m_entryPointData.taxiPath[1] = m_taxi.GetTaxiDestination();
}
else
{
@@ -11353,6 +11376,7 @@ void Player::SendInitialPacketsAfterAddToMap()
SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map
SendQuestGiverStatusMultiple();
+ SendTaxiNodeStatusMultiple();
// raid downscaling - send difficulty to player
if (GetMap()->IsRaid())
@@ -12007,23 +12031,21 @@ bool Player::GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const
float Player::GetReputationPriceDiscount(Creature const* creature) const
{
- FactionTemplateEntry const* vendorFaction = creature->GetFactionTemplateEntry();
- if (!vendorFaction)
+ return GetReputationPriceDiscount(creature->GetFactionTemplateEntry());
+}
+
+float Player::GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const
+{
+ if (!factionTemplate || !factionTemplate->faction)
{
return 1.0f;
}
- return GetReputationPriceDiscount(vendorFaction);
-}
-
-float Player::GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const
-{
- if (!vendorFaction->faction)
- return 1.0f;
-
- ReputationRank rank = GetReputationRank(vendorFaction->faction);
+ ReputationRank rank = GetReputationRank(factionTemplate->faction);
if (rank <= REP_NEUTRAL)
+ {
return 1.0f;
+ }
return 1.0f - 0.05f * (rank - REP_NEUTRAL);
}
@@ -13875,20 +13897,27 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
bool Player::CanResummonPet(uint32 spellid)
{
- if (getClass() == CLASS_DEATH_KNIGHT)
+ switch (getClass())
{
- if (CanSeeDKPet())
+ case CLASS_DEATH_KNIGHT:
+ if (CanSeeDKPet())
+ return true;
+ else if (spellid == 52150) //Raise Dead
+ return false;
+ break;
+ case CLASS_MAGE:
+ if (HasSpell(31687) && HasAura(70937)) //Has [Summon Water Elemental] spell and [Glyph of Eternal Water].
+ return true;
+ break;
+ case CLASS_HUNTER:
+ case CLASS_WARLOCK:
return true;
- else if (spellid == 52150)
- return false;
+ break;
+ default:
+ break;
}
- else if (getClass() == CLASS_HUNTER || getClass() == CLASS_MAGE || getClass() == CLASS_WARLOCK)
- return true;
- if (!HasSpell(spellid))
- return false;
-
- return true;
+ return HasSpell(spellid);
}
bool Player::CanSeeSpellClickOn(Creature const* c) const
@@ -14228,16 +14257,9 @@ void Player::_SaveEntryPoint(CharacterDatabaseTransaction trans)
stmt->SetData (3, m_entryPointData.joinPos.GetPositionZ());
stmt->SetData (4, m_entryPointData.joinPos.GetOrientation());
stmt->SetData(5, m_entryPointData.joinPos.GetMapId());
-
- std::ostringstream ss("");
- if (m_entryPointData.HasTaxiPath())
- {
- for (size_t i = 0; i < m_entryPointData.taxiPath.size(); ++i)
- ss << m_entryPointData.taxiPath[i] << ' '; // xinef: segment is stored as last point
- }
-
- stmt->SetData(6, ss.str());
- stmt->SetData(7, m_entryPointData.mountSpell);
+ stmt->SetData(6, m_entryPointData.taxiPath[0]);
+ stmt->SetData(7, m_entryPointData.taxiPath[1]);
+ stmt->SetData(8, m_entryPointData.mountSpell);
trans->Append(stmt);
}
@@ -15958,3 +15980,10 @@ void Player::ResetSpeakTimers()
m_speakTime = 0;
m_speakCount = 0;
}
+
+std::string Player::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Unit::GetDebugInfo();
+ return sstr.str();
+}
\ No newline at end of file
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 89124e9c7..a3974576d 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1035,11 +1035,11 @@ struct EntryPointData
}
uint32 mountSpell{0};
- std::vector taxiPath;
+ std::array taxiPath;
WorldLocation joinPos;
- void ClearTaxiPath() { taxiPath.clear(); }
- [[nodiscard]] bool HasTaxiPath() const { return !taxiPath.empty(); }
+ void ClearTaxiPath() { taxiPath.fill(0); }
+ [[nodiscard]] bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; }
};
class Player : public Unit, public GridObject
@@ -1126,6 +1126,7 @@ public:
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 1);
void CleanupAfterTaxiFlight();
void ContinueTaxiFlight();
+ void SendTaxiNodeStatusMultiple();
// mount_id can be used in scripting calls
[[nodiscard]] bool IsDeveloper() const { return HasPlayerFlag(PLAYER_FLAGS_DEVELOPER); }
@@ -1336,8 +1337,8 @@ public:
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot);
bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore);
- float GetReputationPriceDiscount(Creature const* creature) const;
- float GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const;
+ [[nodiscard]] float GetReputationPriceDiscount(Creature const* creature) const;
+ [[nodiscard]] float GetReputationPriceDiscount(FactionTemplateEntry const* factionTemplate) const;
[[nodiscard]] Player* GetTrader() const { return m_trade ? m_trade->GetTrader() : nullptr; }
[[nodiscard]] TradeData* GetTradeData() const { return m_trade; }
@@ -2429,6 +2430,8 @@ public:
bool CanTeleport() { return m_canTeleport; }
void SetCanTeleport(bool value) { m_canTeleport = value; }
+ bool CanKnockback() { return m_canKnockback; }
+ void SetCanKnockback(bool value) { m_canKnockback = value; }
bool isAllowedToLoot(Creature const* creature);
@@ -2557,6 +2560,8 @@ public:
void ResetSpeakTimers();
+ std::string GetDebugInfo() const override;
+
protected:
// Gamemaster whisper whitelist
WhisperListContainer WhisperList;
@@ -2884,6 +2889,7 @@ private:
bool m_bMustDelayTeleport;
bool m_bHasDelayedTeleport;
bool m_canTeleport;
+ bool m_canKnockback;
std::unique_ptr m_petStable;
diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp
index 7e275bd1d..1b615fe65 100644
--- a/src/server/game/Entities/Player/PlayerStorage.cpp
+++ b/src/server/game/Entities/Player/PlayerStorage.cpp
@@ -4894,21 +4894,9 @@ void Player::_LoadEntryPointData(PreparedQueryResult result)
fields[2].Get(), // Z
fields[3].Get()); // Orientation
- std::string_view taxi = fields[5].Get();
- if (!taxi.empty())
- {
- for (auto const& itr : Acore::Tokenize(taxi, ' ', false))
- {
- uint32 node = Acore::StringTo(itr).value_or(0);
- m_entryPointData.taxiPath.emplace_back(node);
- }
-
- // Check integrity
- if (m_entryPointData.taxiPath.size() < 3)
- m_entryPointData.ClearTaxiPath();
- }
-
- m_entryPointData.mountSpell = fields[6].Get();
+ m_entryPointData.taxiPath[0] = fields[5].Get();
+ m_entryPointData.taxiPath[1] = fields[6].Get();
+ m_entryPointData.mountSpell = fields[7].Get();
}
bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid::LowType guid)
@@ -5190,10 +5178,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
// xinef: restore taxi flight from entry point data
if (m_entryPointData.HasTaxiPath())
{
- for (size_t i = 0; i < m_entryPointData.taxiPath.size() - 1; ++i)
- m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[i]);
- m_taxi.SetTaxiSegment(m_entryPointData.taxiPath[m_entryPointData.taxiPath.size() - 1]);
-
+ m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[0]);
+ m_taxi.AddTaxiDestination(m_entryPointData.taxiPath[1]);
m_entryPointData.ClearTaxiPath();
}
}
diff --git a/src/server/game/Entities/Player/PlayerTaxi.cpp b/src/server/game/Entities/Player/PlayerTaxi.cpp
index a4bff7aa6..680af2e28 100644
--- a/src/server/game/Entities/Player/PlayerTaxi.cpp
+++ b/src/server/game/Entities/Player/PlayerTaxi.cpp
@@ -20,11 +20,6 @@
#include "Tokenize.h"
#include "StringConvert.h"
-PlayerTaxi::PlayerTaxi() : _taxiSegment(0)
-{
- memset(m_taximask, 0, sizeof(m_taximask));
-}
-
void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
{
// class specific initial known nodes
@@ -136,9 +131,25 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
{
ClearTaxiDestinations();
- for (auto const& itr : Acore::Tokenize(values, ' ', false))
+ std::vector tokens = Acore::Tokenize(values, ' ', false);
+ auto itr = tokens.begin();
+ if (itr != tokens.end())
{
- if (Optional node = Acore::StringTo(itr))
+ if (Optional faction = Acore::StringTo(*itr))
+ {
+ m_flightMasterFactionId = *faction;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ return false;
+
+ while ((++itr) != tokens.end())
+ {
+ if (Optional node = Acore::StringTo(*itr))
{
AddTaxiDestination(*node);
}
@@ -148,26 +159,33 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
}
}
+ if (m_TaxiDestinations.empty())
+ {
+ return true;
+ }
+
// Check integrity
- if (m_TaxiDestinations.size() < 3)
+ if (m_TaxiDestinations.size() < 2)
+ {
return false;
+ }
- // xinef: current segment is saved as last destination in db
- _taxiSegment = m_TaxiDestinations[m_TaxiDestinations.size() - 1];
- m_TaxiDestinations.pop_back();
-
- for (size_t i = 0; i < m_TaxiDestinations.size() - 1; ++i)
+ for (size_t i = 1; i < m_TaxiDestinations.size(); ++i)
{
uint32 cost;
uint32 path;
- sObjectMgr->GetTaxiPath(m_TaxiDestinations[i], m_TaxiDestinations[i + 1], path, cost);
+ sObjectMgr->GetTaxiPath(m_TaxiDestinations[i - 1], m_TaxiDestinations[i], path, cost);
if (!path)
+ {
return false;
+ }
}
// can't load taxi path without mount set (quest taxi path?)
if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), teamId, true))
+ {
return false;
+ }
return true;
}
@@ -175,26 +193,34 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, TeamI
std::string PlayerTaxi::SaveTaxiDestinationsToString()
{
if (m_TaxiDestinations.empty())
+ {
return "";
+ }
+
+ ASSERT(m_TaxiDestinations.size() >= 2);
std::ostringstream ss;
+ ss << m_flightMasterFactionId << ' ';
for (size_t i = 0; i < m_TaxiDestinations.size(); ++i)
+ {
ss << m_TaxiDestinations[i] << ' ';
+ }
- ss << _taxiSegment << ' ';
return ss.str();
}
uint32 PlayerTaxi::GetCurrentTaxiPath() const
{
- if (m_TaxiDestinations.size() < 2 || m_TaxiDestinations.size() <= _taxiSegment + 1)
+ if (m_TaxiDestinations.size() < 2)
+ {
return 0;
+ }
uint32 path;
uint32 cost;
- sObjectMgr->GetTaxiPath(m_TaxiDestinations[_taxiSegment], m_TaxiDestinations[_taxiSegment + 1], path, cost);
+ sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost);
return path;
}
@@ -205,3 +231,8 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
ss << taxi.m_taximask[i] << ' ';
return ss;
}
+
+FactionTemplateEntry const* PlayerTaxi::GetFlightMasterFactionTemplate() const
+{
+ return sFactionTemplateStore.LookupEntry(m_flightMasterFactionId);
+}
diff --git a/src/server/game/Entities/Player/PlayerTaxi.h b/src/server/game/Entities/Player/PlayerTaxi.h
index 774b8499b..3923a8c54 100644
--- a/src/server/game/Entities/Player/PlayerTaxi.h
+++ b/src/server/game/Entities/Player/PlayerTaxi.h
@@ -26,7 +26,7 @@ class ByteBuffer;
class AC_GAME_API PlayerTaxi
{
public:
- PlayerTaxi();
+ PlayerTaxi() : m_flightMasterFactionId(0) { m_taximask.fill(0); }
~PlayerTaxi() = default;
// Nodes
@@ -59,29 +59,28 @@ public:
bool LoadTaxiDestinationsFromString(std::string const& values, TeamId teamId);
std::string SaveTaxiDestinationsToString();
- void ClearTaxiDestinations() { m_TaxiDestinations.clear(); _taxiSegment = 0; }
+ void ClearTaxiDestinations() { m_TaxiDestinations.clear(); }
void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); }
- [[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment]; }
- [[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() <= _taxiSegment + 1 ? 0 : m_TaxiDestinations[_taxiSegment + 1]; }
+ [[nodiscard]] uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); }
+ [[nodiscard]] uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; }
[[nodiscard]] uint32 GetCurrentTaxiPath() const;
uint32 NextTaxiDestination()
{
- ++_taxiSegment;
+ m_TaxiDestinations.pop_front();
return GetTaxiDestination();
}
- // xinef:
- void SetTaxiSegment(uint32 segment) { _taxiSegment = segment; }
- [[nodiscard]] uint32 GetTaxiSegment() const { return _taxiSegment; }
-
- [[nodiscard]] std::vector const& GetPath() const { return m_TaxiDestinations; }
+ [[nodiscard]] std::deque const& GetPath() const { return m_TaxiDestinations; }
[[nodiscard]] bool empty() const { return m_TaxiDestinations.empty(); }
+ [[nodiscard]] FactionTemplateEntry const* GetFlightMasterFactionTemplate() const;
+ void SetFlightMasterFactionTemplateId(uint32 factionTemplateId) { m_flightMasterFactionId = factionTemplateId; }
friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi);
+
private:
TaxiMask m_taximask;
- std::vector m_TaxiDestinations;
- uint32 _taxiSegment;
+ std::deque m_TaxiDestinations;
+ uint32 m_flightMasterFactionId;
};
#endif
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 73486f979..172cf5fd6 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -116,38 +116,40 @@ void Totem::UnSummon(uint32 msTime)
CombatStop();
RemoveAurasDueToSpell(GetSpell(), GetGUID());
- Unit* owner = GetOwner();
- // clear owner's totem slot
- for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
+ if (Unit* owner = GetOwner())
{
- if (owner->m_SummonSlot[i] == GetGUID())
+ // clear owner's totem slot
+ for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
- owner->m_SummonSlot[i].Clear();
- break;
- }
- }
-
- owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
-
- // Remove Sentry Totem Aura
- if (GetEntry() == SENTRY_TOTEM_ENTRY)
- owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
-
- //remove aura all party members too
- if (Player* player = owner->ToPlayer())
- {
- player->SendAutoRepeatCancel(this);
-
- if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
- player->SendCooldownEvent(spell, 0, nullptr, false);
-
- if (Group* group = player->GetGroup())
- {
- for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
+ if (owner->m_SummonSlot[i] == GetGUID())
{
- Player* target = itr->GetSource();
- if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
- target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
+ owner->m_SummonSlot[i].Clear();
+ break;
+ }
+ }
+
+ owner->RemoveAurasDueToSpell(GetSpell(), GetGUID());
+
+ // Remove Sentry Totem Aura
+ if (GetEntry() == SENTRY_TOTEM_ENTRY)
+ owner->RemoveAurasDueToSpell(SENTRY_TOTEM_SPELLID);
+
+ //remove aura all party members too
+ if (Player* player = owner->ToPlayer())
+ {
+ player->SendAutoRepeatCancel(this);
+
+ if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetUInt32Value(UNIT_CREATED_BY_SPELL)))
+ player->SendCooldownEvent(spell, 0, nullptr, false);
+
+ if (Group* group = player->GetGroup())
+ {
+ for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
+ {
+ Player* target = itr->GetSource();
+ if (target && target->IsInMap(player) && group->SameSubGroup(player, target))
+ target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
+ }
}
}
}
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 841dd1b69..89e1e329f 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -1004,3 +1004,10 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll)
}
}
}
+
+std::string MotionTransport::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << GameObject::GetDebugInfo();
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 98aae380f..75fc9f9ee 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -78,6 +78,7 @@ public:
uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
+ std::string GetDebugInfo() const override;
private:
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 488dda03c..11be39428 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -465,6 +465,7 @@ void Unit::Update(uint32 p_time)
// xinef: if attack time > 0, reduce by diff
// if on next update, attack time < 0 assume player didnt attack - set to 0
bool suspendAttackTimer = false;
+ bool suspendRangedAttackTimer = false;
if (IsPlayer() && HasUnitState(UNIT_STATE_CASTING))
{
for (Spell* spell : m_currentSpells)
@@ -473,6 +474,11 @@ void Unit::Update(uint32 p_time)
{
if (spell->GetSpellInfo()->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
{
+ if (spell->IsChannelActive())
+ {
+ suspendRangedAttackTimer = true;
+ }
+
suspendAttackTimer = true;
break;
}
@@ -493,9 +499,12 @@ void Unit::Update(uint32 p_time)
}
}
- if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
+ if (!suspendRangedAttackTimer)
{
- setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32) p_time : 0);
+ if (int32 ranged_attack = getAttackTimer(RANGED_ATTACK))
+ {
+ setAttackTimer(RANGED_ATTACK, ranged_attack > 0 ? ranged_attack - (int32)p_time : 0);
+ }
}
// update abilities available only for fraction of time
@@ -1109,7 +1118,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
{
Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
- ASSERT(he && he->duel);
+ ASSERT_NODEBUGINFO(he && he->duel);
if (duel_wasMounted) // In this case victim==mount
victim->SetHealth(1);
@@ -2415,7 +2424,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
- ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
+ Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage,
damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo);
if (GetTypeId() == TYPEID_PLAYER)
@@ -5961,15 +5970,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo,
SendSpellNonMeleeDamageLog(&log);
}
-void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
+void Unit::ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase)
{
// Not much to do if no flags are set.
- if (procAttacker)
- ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
+ if (procAttacker && actor)
+ actor->ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
// Now go on with a victim's events'n'auras
// Not much to do if no flags are set or there is no victim
if (victim && victim->IsAlive() && procVictim)
- victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
+ victim->ProcDamageAndSpellFor(true, actor, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
@@ -6151,7 +6160,7 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
}
//victim may be nullptr
-bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
+bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/)
{
SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
uint32 effIndex = triggeredByAura->GetEffIndex();
@@ -7077,7 +7086,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
case 28719:
{
// mana back
- basepoints0 = int32(CalculatePct(procSpell->ManaCost, 30));
+ basepoints0 = int32(CalculatePct(spellProc->GetPowerCost(), 30));
target = this;
triggered_spell_id = 28742;
break;
@@ -16009,7 +16018,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_DUMMY:
{
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown))
+ if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell))
takeCharges = true;
break;
}
@@ -17406,15 +17415,15 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
if (killer && (killer->IsPet() || killer->IsTotem()))
if (Unit* owner = killer->GetOwner())
{
- owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
+ Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature());
}
if (killer != victim && !victim->IsCritter())
- killer->ProcDamageAndSpell(victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
+ Unit::ProcDamageAndSpell(killer, victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// Proc auras on death - must be before aura/combat remove
- victim->ProcDamageAndSpell(nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
+ Unit::ProcDamageAndSpell(victim, nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
@@ -18750,6 +18759,7 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
player->SetCanFly(true, true);
sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true);
+ player->SetCanKnockback(true);
}
}
@@ -20843,3 +20853,14 @@ bool Unit::IsInDisallowedMountForm() const
return false;
}
+
+std::string Unit::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << WorldObject::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "AliveState: " << IsAlive()
+ << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
+ << " Class: " << std::to_string(getClass());
+ return sstr.str();
+}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 3a5edde39..ce81bb6e3 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1525,7 +1525,7 @@ public:
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
- void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
+ static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/);
void GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo);
@@ -2431,6 +2431,8 @@ public:
virtual bool SetCannotReachTarget(bool cannotReach, bool isChase = true);
[[nodiscard]] bool CanNotReachTarget() const { return m_cannotReachTarget; }
+ std::string GetDebugInfo() const override;
+
protected:
explicit Unit (bool isWorldObject);
@@ -2515,7 +2517,7 @@ protected:
private:
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
- bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index c82efc403..025ec9a0b 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -9875,8 +9875,8 @@ void ObjectMgr::SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint3
MailSender sender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
MailDraft draft(subject, body);
- draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyH : rewardMoneyA);
- if (Item* mailItem = Item::CreateItem(player->GetTeamId() == TEAM_ALLIANCE ? rewardItemH : rewardItemA, player->GetTeamId() == TEAM_ALLIANCE ? rewardItemCountH : rewardItemCountA))
+ draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyA : rewardMoneyH);
+ if (Item* mailItem = Item::CreateItem(player->GetTeamId() == TEAM_ALLIANCE ? rewardItemA : rewardItemH, player->GetTeamId() == TEAM_ALLIANCE ? rewardItemCountA : rewardItemCountH))
{
mailItem->SaveToDB(trans);
draft.AddItem(mailItem);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index ab72656b9..4623f8ca7 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1449,7 +1449,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
roll->getLoot()->unlootedCount--;
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
- sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
+ if (_item)
+ sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
@@ -1518,7 +1519,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
roll->getLoot()->unlootedCount--;
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
- sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
+ if (_item)
+ sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index c03f619aa..ece0e94df 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -506,6 +506,7 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData)
sAuctionMgr->SendAuctionSalePendingMail(auction, trans);
sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
sAuctionMgr->SendAuctionWonMail(auction, trans);
+ sScriptMgr->OnAuctionSuccessful(auctionHouse, auction);
SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, ERR_AUCTION_OK);
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index e89c2d71c..7e76aa6e4 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -533,13 +533,20 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
}
else // leave queue
{
- bgQueue.RemovePlayer(_player->GetGUID(), true);
- _player->RemoveBattlegroundQueueId(bgQueueTypeId);
+ for (auto const& playerGuid : ginfo.Players)
+ {
+ auto player = ObjectAccessor::FindConnectedPlayer(playerGuid);
+ if (!player)
+ continue;
- sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
- SendPacket(&data);
+ bgQueue.RemovePlayer(playerGuid, true);
+ player->RemoveBattlegroundQueueId(bgQueueTypeId);
- LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetBgTypeID(), bgQueueTypeId);
+ sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
+ player->SendDirectMessage(&data);
+
+ LOG_DEBUG("bg.battleground", "Battleground: player {} {} left queue for bgtype {}, queue type {}.", player->GetName(), playerGuid.ToString(), bg->GetBgTypeID(), bgQueueTypeId);
+ }
// player left queue, we should update it - do not update Arena Queue
if (!ginfo.ArenaType)
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index d7eadb063..f0c6c053c 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -2189,7 +2189,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrSetData(0, uint16(AT_LOGIN_CHECK_ACHIEVS));
+ stmt->SetData(1, lowGuid);
+ trans->Append(stmt);
+
CharacterDatabase.CommitTransaction(trans);
LOG_DEBUG("entities.player", "{} (IP: {}) changed race from {} to {}", GetPlayerInfo(), GetRemoteAddress(), oldRace, factionChangeInfo->Race);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 0c602e8bb..8c9523f00 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -188,6 +188,22 @@ void WorldSession::HandleMoveWorldportAck()
GetPlayer()->SendInitialPacketsAfterAddToMap();
+ // flight fast teleport case
+ if (GetPlayer()->IsInFlight())
+ {
+ if (!GetPlayer()->InBattleground())
+ {
+ // short preparations to continue flight
+ MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top();
+ movementGenerator->Initialize(GetPlayer());
+ return;
+ }
+
+ // battleground state prepare, stop flight
+ GetPlayer()->GetMotionMaster()->MovementExpired();
+ GetPlayer()->CleanupAfterTaxiFlight();
+ }
+
// resurrect character at enter into instance where his corpse exist after add to map
Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID());
if (corpse && corpse->GetType() != CORPSE_BONES)
diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp
index 466285a24..e3678168a 100644
--- a/src/server/game/Handlers/TaxiHandler.cpp
+++ b/src/server/game/Handlers/TaxiHandler.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "GameTime.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
@@ -36,25 +37,24 @@ void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvData)
void WorldSession::SendTaxiStatus(ObjectGuid guid)
{
- // cheating checks
- Creature* unit = GetPlayer()->GetMap()->GetCreature(guid);
- if (!unit)
+ Player* const player = GetPlayer();
+ Creature* unit = ObjectAccessor::GetCreature(*player, guid);
+ if (!unit || unit->IsHostileTo(player) || !unit->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
{
LOG_DEBUG("network", "WorldSession::SendTaxiStatus - Unit ({}) not found.", guid.ToString());
return;
}
- uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeamId());
-
- // not found nearest
- if (curloc == 0)
+ // find taxi node
+ uint32 nearest = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), player->GetTeamId());
+ if (!nearest)
+ {
return;
-
- LOG_DEBUG("network", "WORLD: current location {} ", curloc);
+ }
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
data << guid;
- data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0);
+ data << uint8(player->m_taxi.IsTaximaskNodeKnown(nearest) ? 1 : 0);
SendPacket(&data);
LOG_DEBUG("network", "WORLD: Sent SMSG_TAXINODE_STATUS");
}
@@ -166,7 +166,7 @@ void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid)
}
}
-void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData)
+void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recvData)
{
LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXIEXPRESS");
@@ -179,6 +179,7 @@ void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData)
if (!npc)
{
LOG_DEBUG("network", "WORLD: HandleActivateTaxiExpressOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
+ SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return;
}
std::vector nodes;
@@ -218,6 +219,46 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
ReadMovementInfo(recvData, &movementInfo);
recvData.read_skip(); // spline id
+
+ // in taxi flight packet received in 2 case:
+ // 1) end taxi path in far (multi-node) flight
+ // 2) switch from one map to other in case multim-map taxi path
+ // we need process only (1)
+
+ uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
+ if (curDest)
+ {
+ TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
+
+ // far teleport case
+ if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
+ {
+ if (FlightPathMovementGenerator* flight = dynamic_cast(GetPlayer()->GetMotionMaster()->top()))
+ {
+ // short preparations to continue flight
+ flight->SetCurrentNodeAfterTeleport();
+ TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()];
+ flight->SkipCurrentNode();
+
+ GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
+ }
+ }
+
+ return;
+ }
+
+ // at this point only 1 node is expected (final destination)
+ if (GetPlayer()->m_taxi.GetPath().size() != 1)
+ {
+ return;
+ }
+
+ GetPlayer()->CleanupAfterTaxiFlight();
+ GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ());
+ if (GetPlayer()->pvpInfo.IsHostile)
+ {
+ GetPlayer()->CastSpell(GetPlayer(), 2479, true);
+ }
}
void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)
@@ -234,6 +275,7 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)
if (!npc)
{
LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - Unit ({}) not found or you can't interact with it.", guid.ToString());
+ SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return;
}
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index 6058b300b..f622976ec 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -94,7 +94,7 @@ InstanceSave* InstanceSaveMgr::AddInstanceSave(uint32 mapId, uint32 instanceId,
}
else
{
- resetTime = GameTime::GetGameTime().count() + 3 * DAY; // normals expire after 3 days even if someone is still bound to them, cleared on startup
+ resetTime = GameTime::GetGameTime().count() + static_cast(3) * DAY; // normals expire after 3 days even if someone is still bound to them, cleared on startup
extendedResetTime = 0;
}
InstanceSave* save = new InstanceSave(mapId, instanceId, difficulty, resetTime, extendedResetTime);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 25cc841f4..062719942 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -429,14 +429,6 @@ bool LootItem::AllowedForPlayer(Player const* player, bool isGivenByMasterLooter
return false;
}
- // Checking for unique or unique(XX) objects
- // master looter should still be able to see the loot to give to people.
- // casting to avoid warnings, it's unlikely there's an item with unique but 2^31 items allowed.
- if (!isMasterLooter && pProto->MaxCount > 0 && ((int32)player->GetItemCount(itemid, true) >= pProto->MaxCount))
- {
- return false;
- }
-
// not show loot for not own team
if ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeamId(true) != TEAM_HORDE)
{
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 0846f2281..e821c1623 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -4027,3 +4027,21 @@ void Map::DeleteCorpseData()
stmt->SetData(1, GetInstanceId());
CharacterDatabase.Execute(stmt);
}
+
+std::string Map::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << std::boolalpha
+ << "Id: " << GetId() << " InstanceId: " << GetInstanceId() << " Difficulty: " << std::to_string(GetDifficulty())
+ << " HasPlayers: " << HavePlayers();
+ return sstr.str();
+}
+
+std::string InstanceMap::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << Map::GetDebugInfo() << "\n"
+ << std::boolalpha
+ << "ScriptId: " << GetScriptId() << " ScriptName: " << GetScriptName();
+ return sstr.str();
+}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index cfa5fba90..a0aa1f82f 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -649,6 +649,8 @@ public:
return m_activeNonPlayers.size();
}
+ virtual std::string GetDebugInfo() const;
+
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
@@ -830,6 +832,9 @@ public:
[[nodiscard]] uint32 GetMaxResetDelay() const;
void InitVisibilityDistance() override;
+
+ std::string GetDebugInfo() const override;
+
private:
bool m_resetAfterUnload;
bool m_unloadWhenEmpty;
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 10c9563df..bd57f449f 100644
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -270,35 +270,69 @@ void WaypointMovementGenerator::MovementInform(Creature* creature)
uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
{
if (i_currentNode >= i_path.size())
+ {
return i_path.size();
+ }
uint32 curMapId = i_path[i_currentNode]->mapid;
for (uint32 i = i_currentNode; i < i_path.size(); ++i)
+ {
if (i_path[i]->mapid != curMapId)
+ {
return i;
+ }
+ }
return i_path.size();
}
+#define SKIP_SPLINE_POINT_DISTANCE_SQ (40.0f * 40.0f)
+
+bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntry const* p2)
+{
+ return p1->mapid != p2->mapid || std::pow(p1->x - p2->x, 2) + std::pow(p1->y - p2->y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ;
+}
+
void FlightPathMovementGenerator::LoadPath(Player* player)
{
_pointsForPathSwitch.clear();
- std::vector const& taxi = player->m_taxi.GetPath();
- for (uint32 src = player->m_taxi.GetTaxiSegment(), dst = player->m_taxi.GetTaxiSegment() + 1; dst < taxi.size(); src = dst++)
+ std::deque const& taxi = player->m_taxi.GetPath();
+ float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate());
+ for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
{
uint32 path, cost;
sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
if (path > sTaxiPathNodesByPath.size())
+ {
return;
+ }
TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
if (!nodes.empty())
{
+ TaxiPathNodeEntry const* start = nodes[0];
+ TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
+ bool passedPreviousSegmentProximityCheck = false;
for (uint32 i = 0; i < nodes.size(); ++i)
- i_path.push_back(nodes[i]);
+ {
+ if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i]))
+ {
+ if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
+ (dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1)))
+ {
+ passedPreviousSegmentProximityCheck = true;
+ i_path.push_back(nodes[i]);
+ }
+ }
+ else
+ {
+ i_path.pop_back();
+ --_pointsForPathSwitch.back().PathIndex;
+ }
+ }
}
- _pointsForPathSwitch.push_back(uint32(i_path.size() - 1));
+ _pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) });
}
}
@@ -313,7 +347,7 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
player->ClearUnitState(UNIT_STATE_IN_FLIGHT);
- // xinef: this should be cleaned by CleanupAfterTaxiFlight(); function!
+ player->m_taxi.ClearTaxiDestinations();
player->Dismount();
player->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
@@ -324,6 +358,8 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
player->StopMoving();
+
+ // When the player reaches the last flight point, teleport to destination taxi node location
player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
}
@@ -334,13 +370,23 @@ void FlightPathMovementGenerator::DoFinalize(Player* player)
void FlightPathMovementGenerator::DoReset(Player* player)
{
+ uint32 end = GetPathAtMapEnd();
+ uint32 currentNodeId = GetCurrentNode();
+
+ if (currentNodeId == end)
+ {
+ LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString().c_str());
+ return;
+ }
+
player->getHostileRefMgr().setOnlineOfflineState(false);
player->AddUnitState(UNIT_STATE_IN_FLIGHT);
player->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Movement::MoveSplineInit init(player);
- uint32 end = GetPathAtMapEnd();
- for (uint32 i = GetCurrentNode(); i < end; ++i)
+ // Providing a starting vertex since the taxi paths do not provide such
+ init.Path().push_back(G3D::Vector3(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()));
+ for (uint32 i = currentNodeId; i != end; ++i)
{
G3D::Vector3 vertice(i_path[i]->x, i_path[i]->y, i_path[i]->z);
init.Path().push_back(vertice);
@@ -353,77 +399,40 @@ void FlightPathMovementGenerator::DoReset(Player* player)
bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
{
- if (!player)
- return false;
-
- // xinef: map was switched
- if (_mapSwitch)
- {
- DoInitialize(player);
- _mapSwitch = false;
- return true;
- }
-
- uint32 pointId = (uint32)player->movespline->currentPathIdx();
- if (pointId > i_currentNode)
+ // skipping the first spline path point because it's our starting point and not a taxi path point
+ uint32 pointId = player->movespline->currentPathIdx() <= 0 ? 0 : player->movespline->currentPathIdx() - 1;
+ if (pointId > i_currentNode && i_currentNode < i_path.size() - 1)
{
bool departureEvent = true;
do
{
- if (i_currentNode >= i_path.size())
- {
- LOG_INFO("misc", "TAXI NODE WAS GREATER THAN PATH SIZE, {}, POINTID: {}, NODESIZE: {}, CURRENT: {}",
- player->GetGUID().ToString(), pointId, i_path.size(), i_currentNode);
- player->CleanupAfterTaxiFlight();
- return false;
- }
-
- if (i_path[i_currentNode]->mapid != player->GetMapId())
- {
- LOG_INFO("misc", "Player on different map, curmap: {}, pointmap: {}, nodesize: {}, currentnode: {}", player->GetMapId(), i_path[i_currentNode]->mapid, i_path.size(), i_currentNode);
- player->CleanupAfterTaxiFlight();
- return false;
- }
+ ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString().c_str());
DoEventIfAny(player, i_path[i_currentNode], departureEvent);
-
- // xinef: erase any previous points
- uint32 curSize = _pointsForPathSwitch.size();
- while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front() <= i_currentNode)
+ while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode)
+ {
_pointsForPathSwitch.pop_front();
-
- // xinef: switch destination only once
- if (curSize != _pointsForPathSwitch.size())
player->m_taxi.NextTaxiDestination();
+ if (!_pointsForPathSwitch.empty())
+ {
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, _pointsForPathSwitch.front().Cost);
+ player->ModifyMoney(-_pointsForPathSwitch.front().Cost);
+ }
+ }
if (pointId == i_currentNode)
+ {
break;
+ }
- if (i_currentNode == _preloadTargetNode && player->GetMapId() == _endMapId)
+ if (i_currentNode == _preloadTargetNode)
+ {
PreloadEndGrid();
- i_currentNode += (uint32)departureEvent;
+ }
+
+ i_currentNode += departureEvent ? 1 : 0;
departureEvent = !departureEvent;
-
- // xinef: map should be switched, do not rely on client packets QQ
- if (i_currentNode + 1 < i_path.size() && i_path[i_currentNode + 1]->mapid != player->GetMapId())
- {
- ++i_currentNode;
- _mapSwitch = true;
- player->TeleportTo(i_path[i_currentNode]->mapid, i_path[i_currentNode]->x, i_path[i_currentNode]->y, i_path[i_currentNode]->z, player->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
- return true;
- }
-
- // xinef: reached the end
- if (i_currentNode >= i_path.size() - 1)
- {
- player->CleanupAfterTaxiFlight();
- player->SetFallInformation(GameTime::GetGameTime().count(), player->GetPositionZ());
- if (player->pvpInfo.IsHostile)
- player->CastSpell(player, 2479, true);
-
- return false;
- }
- } while (true);
+ } while (i_currentNode < i_path.size() - 1);
}
return i_currentNode < (i_path.size() - 1);
@@ -432,7 +441,9 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
{
if (i_path.empty() || i_currentNode >= i_path.size())
+ {
return;
+ }
uint32 map0 = i_path[i_currentNode]->mapid;
for (size_t i = i_currentNode + 1; i < i_path.size(); ++i)
@@ -449,11 +460,20 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
{
if (uint32 eventid = departure ? node->departureEventID : node->arrivalEventID)
{
- LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName());
+ LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName().c_str());
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
+bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
+{
+ TaxiPathNodeEntry const* node = i_path[i_currentNode];
+ x = node->x;
+ y = node->y;
+ z = node->z;
+ return true;
+}
+
void FlightPathMovementGenerator::InitEndGridInfo()
{
/*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
@@ -485,11 +505,11 @@ void FlightPathMovementGenerator::PreloadEndGrid()
// Load the grid
if (endMap)
{
- LOG_DEBUG("movement", "Preloading rid ({}, {}) for map {} at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
+ LOG_DEBUG("misc", "Preloading grid ({}, {}) for map %u at node index {}/{}", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path.size() - 1));
endMap->LoadGrid(_endGridX, _endGridY);
}
else
{
- LOG_DEBUG("movement", "Unable to determine map to preload flightmaster grid");
+ LOG_DEBUG("misc", "Unable to determine map to preload flightmaster grid");
}
}
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index 35eaa932a..1699a71a6 100644
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -101,40 +101,48 @@ private:
class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, FlightPathMovementGenerator >,
public PathMovementBase
{
-public:
- explicit FlightPathMovementGenerator(uint32 startNode = 0)
- {
- i_currentNode = startNode;
- _endGridX = 0.0f;
- _endGridY = 0.0f;
- _endMapId = 0;
- _preloadTargetNode = 0;
- _mapSwitch = false;
- }
- void LoadPath(Player* player);
- void DoInitialize(Player*);
- void DoReset(Player*);
- void DoFinalize(Player*);
- bool DoUpdate(Player*, uint32);
- MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
+ public:
+ explicit FlightPathMovementGenerator(uint32 startNode = 0)
+ {
+ i_currentNode = startNode;
+ _endGridX = 0.0f;
+ _endGridY = 0.0f;
+ _endMapId = 0;
+ _preloadTargetNode = 0;
+ }
+ void LoadPath(Player* player);
+ void DoInitialize(Player*);
+ void DoReset(Player*);
+ void DoFinalize(Player*);
+ bool DoUpdate(Player*, uint32);
+ MovementGeneratorType GetMovementGeneratorType() override { return FLIGHT_MOTION_TYPE; }
- TaxiPathNodeList const& GetPath() { return i_path; }
- uint32 GetPathAtMapEnd() const;
- bool HasArrived() const { return (i_currentNode >= i_path.size()); }
- void SetCurrentNodeAfterTeleport();
- void SkipCurrentNode() { ++i_currentNode; }
- void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure);
+ TaxiPathNodeList const& GetPath() { return i_path; }
+ uint32 GetPathAtMapEnd() const;
+ bool HasArrived() const { return (i_currentNode >= i_path.size()); }
+ void SetCurrentNodeAfterTeleport();
+ void SkipCurrentNode() { ++i_currentNode; }
+ void DoEventIfAny(Player* player, TaxiPathNodeEntry const* node, bool departure);
- void InitEndGridInfo();
- void PreloadEndGrid();
+ bool GetResetPos(Player*, float& x, float& y, float& z);
-private:
- float _endGridX; //! X coord of last node location
- float _endGridY; //! Y coord of last node location
- uint32 _endMapId; //! map Id of last node location
- uint32 _preloadTargetNode; //! node index where preloading starts
- bool _mapSwitch;
+ void InitEndGridInfo();
+ void PreloadEndGrid();
- std::deque _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes
+ private:
+
+ float _endGridX; //! X coord of last node location
+ float _endGridY; //! Y coord of last node location
+ uint32 _endMapId; //! map Id of last node location
+ uint32 _preloadTargetNode; //! node index where preloading starts
+
+ struct TaxiNodeChangeInfo
+ {
+ uint32 PathIndex;
+ int32 Cost;
+ };
+
+ std::deque _pointsForPathSwitch; //! node indexes and costs where TaxiPath changes
};
+
#endif
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 4d9e89169..0717511cc 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1913,6 +1913,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
case FORM_FLIGHT:
case FORM_MOONKIN:
{
+ if (Player* player = target->ToPlayer())
+ {
+ player->SetCanTeleport(true);
+ }
// remove movement affects
target->RemoveAurasByShapeShift();
@@ -6396,8 +6400,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
target->SendPeriodicAuraLog(&pInfo);
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
- // allow null caster to call this function
- caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
+
+ Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const
@@ -6485,8 +6489,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
int32 new_damage;
new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
- // allow null caster to call this function
- caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
+
+ Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
if (!caster || !caster->IsAlive())
return;
@@ -6668,8 +6672,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
// ignore item heals
if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot
- // xinef: allow null caster to proc
- caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
+ Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -6857,7 +6860,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
caster->DealSpellDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo, DOT);
- caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
+ Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo);
}
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 28c979e86..0a9e80332 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -297,8 +297,8 @@ void AuraApplication::ClientUpdate(bool remove)
uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner)
{
- ASSERT(spellProto);
- ASSERT(owner);
+ ASSERT_NODEBUGINFO(spellProto);
+ ASSERT_NODEBUGINFO(owner);
uint8 effMask = 0;
switch (owner->GetTypeId())
{
@@ -325,10 +325,10 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleE
Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool periodicReset /*= false*/)
{
- ASSERT(spellproto);
- ASSERT(owner);
- ASSERT(caster || casterGUID);
- ASSERT(tryEffMask <= MAX_EFFECT_MASK);
+ ASSERT_NODEBUGINFO(spellproto);
+ ASSERT_NODEBUGINFO(owner);
+ ASSERT_NODEBUGINFO(caster || casterGUID);
+ ASSERT_NODEBUGINFO(tryEffMask <= MAX_EFFECT_MASK);
if (refresh)
*refresh = false;
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
@@ -351,10 +351,10 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas
Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, ObjectGuid itemGUID /*= ObjectGuid::Empty*/)
{
- ASSERT(spellproto);
- ASSERT(owner);
- ASSERT(caster || casterGUID);
- ASSERT(tryEffMask <= MAX_EFFECT_MASK);
+ ASSERT_NODEBUGINFO(spellproto);
+ ASSERT_NODEBUGINFO(owner);
+ ASSERT_NODEBUGINFO(caster || casterGUID);
+ ASSERT_NODEBUGINFO(tryEffMask <= MAX_EFFECT_MASK);
uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner);
if (!effMask)
return nullptr;
@@ -363,11 +363,11 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject
Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid itemGUID /*= ObjectGuid::Empty*/)
{
- ASSERT(effMask);
- ASSERT(spellproto);
- ASSERT(owner);
- ASSERT(caster || casterGUID);
- ASSERT(effMask <= MAX_EFFECT_MASK);
+ ASSERT_NODEBUGINFO(effMask);
+ ASSERT_NODEBUGINFO(spellproto);
+ ASSERT_NODEBUGINFO(owner);
+ ASSERT_NODEBUGINFO(caster || casterGUID);
+ ASSERT_NODEBUGINFO(effMask <= MAX_EFFECT_MASK);
// try to get caster of aura
if (casterGUID)
{
@@ -2707,6 +2707,15 @@ void Aura::SetTriggeredByAuraSpellInfo(SpellInfo const* triggeredByAuraSpellInfo
m_triggeredByAuraSpellInfo = triggeredByAuraSpellInfo;
}
+std::string Aura::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << std::boolalpha
+ << "Id: " << GetId() << " Caster: " << GetCasterGUID().ToString()
+ << "\nOwner: " << (GetOwner() ? GetOwner()->GetDebugInfo() : "NULL");
+ return sstr.str();
+}
+
SpellInfo const* Aura::GetTriggeredByAuraSpellInfo() const
{
return m_triggeredByAuraSpellInfo;
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index bcf0d6408..4600a4242 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -236,6 +236,8 @@ public:
std::list m_loadedScripts;
+ virtual std::string GetDebugInfo() const;
+
void SetTriggeredByAuraSpellInfo(SpellInfo const* triggeredByAuraSpellInfo);
SpellInfo const* GetTriggeredByAuraSpellInfo() const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 75b252b20..96c554a5d 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2792,7 +2792,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (canEffectTrigger)
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
+ Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo);
}
// Do damage and triggers
@@ -2871,7 +2871,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE);
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
+ Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
@@ -2891,7 +2891,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo dmgInfo(damageInfo, NODAMAGE);
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
+ Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
// Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also
@@ -3972,7 +3972,7 @@ void Spell::_cast(bool skipCheck)
break;
}
- m_originalCaster->ProcDamageAndSpell(m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
+ Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
}
@@ -4312,7 +4312,7 @@ void Spell::_handle_finish_phase()
break;
}
- m_originalCaster->ProcDamageAndSpell(m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
+ Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH);
}
}
@@ -8155,7 +8155,7 @@ bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID);
if (target && _caster->IsInMap(target))
- _caster->ProcDamageAndSpell(target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
+ Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo);
return true;
}
@@ -8866,6 +8866,15 @@ void TriggeredByAuraSpellData::Init(AuraEffect const* aurEff)
tickNumber = aurEff->GetTickNumber();
}
+std::string Spell::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << std::boolalpha
+ << "Id: " << GetSpellInfo()->Id << " OriginalCaster: " << m_originalCasterGUID.ToString()
+ << " State: " << getState();
+ return sstr.str();
+}
+
namespace Acore
{
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 65f2d9bf7..d9a564871 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -606,6 +606,8 @@ public:
Spell** m_selfContainer; // pointer to our spell container (if applicable)
+ std::string GetDebugInfo() const;
+
//Spell data
SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example)
WeaponAttackType m_attackType; // For weapon based attack
diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp
index 30ca46693..4a46e8115 100644
--- a/src/server/game/Spells/SpellInfoCorrections.cpp
+++ b/src/server/game/Spells/SpellInfoCorrections.cpp
@@ -4329,6 +4329,25 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00000003, 0x00001000);
});
+ // Elemental Vulnerability
+ ApplySpellFix({ 28772 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->Speed = 1;
+ });
+
+ // Find the Ancient Hero: Kill Credit
+ ApplySpellFix({ 25729 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->Effects[EFFECT_0].TargetA = TARGET_UNIT_SUMMONER;
+ });
+
+ // Artorius Demonic Doom
+ ApplySpellFix({ 23298 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->AttributesEx4 |= SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS;
+ spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS;
+ });
+
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
diff --git a/src/server/scripts/Commands/cs_achievement.cpp b/src/server/scripts/Commands/cs_achievement.cpp
index 1fb43b2db..070ae2d4f 100644
--- a/src/server/scripts/Commands/cs_achievement.cpp
+++ b/src/server/scripts/Commands/cs_achievement.cpp
@@ -40,7 +40,7 @@ public:
static ChatCommandTable achievementCommandTable =
{
{ "add", HandleAchievementAddCommand, SEC_GAMEMASTER, Console::No },
- { "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::No }
+ { "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::Yes }
};
static ChatCommandTable commandTable =
{
@@ -63,17 +63,33 @@ public:
return true;
}
- static bool HandleAchievementCheckAllCommand(ChatHandler* handler)
+ static bool HandleAchievementCheckAllCommand(ChatHandler* handler, Optional player)
{
- Player* target = handler->getSelectedPlayer();
- if (!target)
+ if (!player)
{
- handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
+ player = PlayerIdentifier::FromTarget(handler);
+ }
+
+ if (!player)
+ {
+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
- target->CheckAllAchievementCriteria();
+ if (player->IsConnected())
+ {
+ if (Player* target = player->GetConnectedPlayer())
+ target->CheckAllAchievementCriteria();
+ }
+ else
+ {
+ auto* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
+ stmt->SetData(0, uint16(AT_LOGIN_CHECK_ACHIEVS));
+ stmt->SetData(1, player->GetGUID().GetCounter());
+ CharacterDatabase.Execute(stmt);
+ }
+
return true;
}
};
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h
index a0adcf52b..1313f4f3a 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h
@@ -43,7 +43,8 @@ enum BWLEncounter
DATA_NEFARIAN_TROOPS = 10,
// Doors
- DATA_GO_CHROMAGGUS_DOOR = 11
+ DATA_GO_CHROMAGGUS_DOOR = 11,
+ DATA_GO_CHROMAGGUS_DOOR_EXIT= 12
};
enum BWLCreatureIds
@@ -92,7 +93,8 @@ enum BWLGameObjectIds
GO_PORTCULLIS_THREEDRAGONS = 179115,
GO_CHROMAGGUS_LEVER = 179148,
GO_PORTCULLIS_CHROMAGGUS = 179116,
- GO_PORTCULLIS_NEFARIAN = 179117,
+ GO_PORTCULLIS_CHROMAGGUS_EXIT = 179117,
+ GO_PORTCULLIS_NEFARIAN = 176966,
GO_SUPPRESSION_DEVICE = 179784
};
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp
index 9da7d418a..e01a22aab 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp
@@ -85,7 +85,7 @@ public:
Acore::Containers::RandomResize(_breathSpells, 2);
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
- creature->SetReactState(REACT_PASSIVE);
+ creature->SetImmuneToAll(true);
}
void Initialize()
@@ -122,7 +122,7 @@ public:
{
_playerGUID = guid;
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
- me->SetReactState(REACT_AGGRESSIVE);
+ me->SetImmuneToAll(false);
}
}
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp
index a9d1299e6..93abf5146 100644
--- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp
@@ -35,8 +35,9 @@ DoorData const doorData[] =
{ GO_PORTCULLIS_RAZORGORE_ROOM, DATA_RAZORGORE_THE_UNTAMED, DOOR_TYPE_ROOM, }, // ID 176964 || GUID 75158
{ GO_PORTCULLIS_VAELASTRASZ, DATA_VAELASTRAZ_THE_CORRUPT, DOOR_TYPE_PASSAGE }, // ID 175185 || GUID 7229
{ GO_PORTCULLIS_BROODLORD, DATA_BROODLORD_LASHLAYER, DOOR_TYPE_PASSAGE }, // ID 179365 || GUID 75159
- { GO_PORTCULLIS_NEFARIAN, DATA_CHROMAGGUS, DOOR_TYPE_PASSAGE }, // ID 179116 || GUID 75161
- { GO_PORTCULLIS_NEFARIAN, DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 179117 || GUID 75164
+ { GO_PORTCULLIS_CHROMAGGUS_EXIT,DATA_CHROMAGGUS, DOOR_TYPE_PASSAGE }, // ID 179117 || GUID 75164
+ { GO_PORTCULLIS_CHROMAGGUS_EXIT,DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 179117 || GUID 75164
+ { GO_PORTCULLIS_NEFARIAN, DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 176966
{ 0, 0, DOOR_TYPE_ROOM } // END
};
@@ -45,12 +46,13 @@ ObjectData const creatureData[] =
{ NPC_GRETHOK, DATA_GRETHOK },
{ NPC_NEFARIAN_TROOPS, DATA_NEFARIAN_TROOPS },
{ NPC_VICTOR_NEFARIUS, DATA_LORD_VICTOR_NEFARIUS },
- { NPC_CHROMAGGUS, DATA_CHROMAGGUS }
+ { NPC_CHROMAGGUS, DATA_CHROMAGGUS },
};
ObjectData const objectData[] =
{
- { GO_PORTCULLIS_CHROMAGGUS, DATA_GO_CHROMAGGUS_DOOR }
+ { GO_PORTCULLIS_CHROMAGGUS, DATA_GO_CHROMAGGUS_DOOR },
+ { GO_PORTCULLIS_CHROMAGGUS_EXIT, DATA_GO_CHROMAGGUS_DOOR_EXIT }
};
Position const SummonPosition[8] =
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
index dc6a899d0..e376e3fd1 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
@@ -1220,33 +1220,6 @@ public:
};
};
-class spell_q12779_an_end_to_all_things : public SpellScriptLoader
-{
-public:
- spell_q12779_an_end_to_all_things() : SpellScriptLoader("spell_q12779_an_end_to_all_things") { }
-
- class spell_q12779_an_end_to_all_things_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_q12779_an_end_to_all_things_SpellScript);
-
- void HandleScriptEffect(SpellEffIndex /*effIndex*/)
- {
- if (GetHitUnit())
- GetHitUnit()->CastSpell(GetCaster(), GetEffectValue(), true);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_q12779_an_end_to_all_things_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_q12779_an_end_to_all_things_SpellScript();
- }
-};
-
void AddSC_the_scarlet_enclave_c2()
{
new npc_crusade_persuaded();
@@ -1254,7 +1227,4 @@ void AddSC_the_scarlet_enclave_c2()
new npc_koltira_deathweaver();
new npc_high_inquisitor_valroth();
new npc_a_special_surprise();
-
- // Xinef: Should be in chapter III
- new spell_q12779_an_end_to_all_things();
}
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter3.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter3.cpp
new file mode 100644
index 000000000..7504b35cf
--- /dev/null
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter3.cpp
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#include "Player.h"
+#include "ScriptMgr.h"
+#include "SpellInfo.h"
+#include "SpellScript.h"
+
+class spell_q12779_an_end_to_all_things : public SpellScript
+{
+ PrepareSpellScript(spell_q12779_an_end_to_all_things);
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (GetHitUnit())
+ GetHitUnit()->CastSpell(GetCaster(), GetEffectValue(), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_q12779_an_end_to_all_things::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+void AddSC_the_scarlet_enclave_c3()
+{
+ RegisterSpellScript(spell_q12779_an_end_to_all_things);
+}
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp
index 4cf8348d0..d05d1696f 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp
@@ -168,18 +168,20 @@ class spell_pagles_point_cast : public SpellScript
{
if (InstanceScript* instanceScript = caster->GetInstanceScript())
{
- if (!instanceScript->GetData(DATA_GAHZRANKA))
+ if (!instanceScript->GetData(DATA_GAHZRANKA) && !caster->FindNearestCreature(NPC_GAHZRANKA, 50.0f))
{
caster->m_Events.AddEventAtOffset([caster]()
{
if (GameObject* lure = caster->SummonGameObject(GAMEOBJECT_MUDSKUNK_LURE, -11688.5f, -1737.74f, 10.409842f, 1.f, 0.f, 0.f, 0.f, 0.f, 30 * IN_MILLISECONDS))
{
- caster->m_Events.AddEventAtOffset([caster, lure]()
+ lure->DespawnOrUnsummon(5s);
+ caster->m_Events.AddEventAtOffset([caster]()
{
- if (lure)
- lure->DespawnOrUnsummon();
- caster->CastSpell(caster, SPELL_SPLASH, true);
- caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
+ if (!caster->FindNearestCreature(NPC_GAHZRANKA, 50.0f))
+ {
+ caster->CastSpell(caster, SPELL_SPLASH, true);
+ caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
+ }
}, 5s);
}
}, 2s);
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
index cf9d16c47..a9d8414a6 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp
@@ -719,11 +719,14 @@ public:
{
if (Unit* target = GetTarget())
{
- if (Creature* caster = GetCaster()->ToCreature())
+ if (Unit* caster = GetCaster())
{
- if (caster->IsAIEnabled)
+ if (Creature* cCaster = caster->ToCreature())
{
- caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
+ if (cCaster->IsAIEnabled)
+ {
+ cCaster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
+ }
}
}
}
diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
index cfe1b9ec3..e8cf955c9 100644
--- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
+++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp
@@ -97,6 +97,7 @@ void AddSC_instance_molten_core();
void AddSC_the_scarlet_enclave(); //Scarlet Enclave
void AddSC_the_scarlet_enclave_c1();
void AddSC_the_scarlet_enclave_c2();
+void AddSC_the_scarlet_enclave_c3();
void AddSC_the_scarlet_enclave_c5();
void AddSC_instance_scarlet_monastery(); //Scarlet Monastery
void AddSC_boss_kirtonos_the_herald();
@@ -247,6 +248,7 @@ void AddEasternKingdomsScripts()
AddSC_the_scarlet_enclave(); //Scarlet Enclave
AddSC_the_scarlet_enclave_c1();
AddSC_the_scarlet_enclave_c2();
+ AddSC_the_scarlet_enclave_c3();
AddSC_the_scarlet_enclave_c5();
AddSC_instance_scarlet_monastery(); //Scarlet Monastery
AddSC_boss_kirtonos_the_herald();
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
index d1198e820..41204a176 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp
@@ -18,281 +18,427 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
#include "ruins_of_ahnqiraj.h"
+#include "TaskScheduler.h"
enum Spells
{
- SPELL_STINGER_SPRAY = 25749,
- SPELL_POISON_STINGER = 25748,
- SPELL_PARALYZE = 25725,
- SPELL_FRENZY = 8269,
- SPELL_LASH = 25852,
- SPELL_FEED = 25721
+ SPELL_STINGER_SPRAY = 25749,
+ SPELL_POISON_STINGER = 25748,
+ SPELL_PARALYZE = 25725,
+ SPELL_FRENZY = 8269,
+ SPELL_LASH = 25852,
+ SPELL_FEED = 25721,
+ SPELL_THRASH = 3391,
+
+ // Server-side spells
+ SPELL_SUMMON_LARVA_A = 26538,
+ SPELL_SUMMON_LARVA_B = 26539,
+ SPELL_LARVA_AGGRO_EFFECT = 25724, // Unknown purpose
+ SPELL_LARVA_FEAR_EFFECT = 25726, // Unknown purpose
+ SPELL_SUMMON_HIVEZARA_SWARMER = 25708,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_1 = 25709,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_2 = 25825,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_3 = 25826,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_4 = 25827,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_5 = 25828,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER = 25830,
+ SPELL_HIVEZARA_SWARMER_START_LOOP = 25711,
+ SPELL_HIVEZARA_SWARMER_LOOP_1 = 25833,
+ SPELL_HIVEZARA_SWARMER_LOOP_2 = 25834,
+ SPELL_HIVEZARA_SWARMER_LOOP_3 = 25835,
+ SPELL_HIVEZARA_SWARMER_SWARM = 25844
};
-enum Events
+enum Misc
{
- EVENT_STINGER_SPRAY = 1,
- EVENT_POISON_STINGER = 2,
- EVENT_SUMMON_SWARMER = 3,
- EVENT_SWARMER_ATTACK = 4,
- EVENT_PARALYZE = 5,
- EVENT_LASH = 6
+ MAX_SWARMER_COUNT = 28,
+ ACTION_SWARMER_SWARM = 1,
};
enum Emotes
{
- EMOTE_FRENZY = 0
+ EMOTE_FRENZY = 0
};
enum Phases
{
- PHASE_AIR = 0,
- PHASE_GROUND = 1
+ PHASE_AIR = 0,
+ PHASE_GROUND = 1
};
enum Points
{
- POINT_AIR = 0,
- POINT_GROUND = 1,
- POINT_PARALYZE = 2
+ POINT_AIR = 0,
+ POINT_GROUND = 2,
+ POINT_PARALYZE = 2
};
-const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f };
-const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f };
-/// @todo These below are probably incorrect, taken from SD2
-const Position SwarmerPos = { -9647.352f, 1578.062f, 55.32f, 0.0f };
-const Position LarvaPos[2] =
-{
- { -9674.4707f, 1528.4133f, 22.457f, 0.0f },
- { -9701.6005f, 1566.9993f, 24.118f, 0.0f }
-};
+const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f };
+const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f };
-class boss_ayamiss : public CreatureScript
+struct boss_ayamiss : public BossAI
{
-public:
- boss_ayamiss() : CreatureScript("boss_ayamiss") { }
+ boss_ayamiss(Creature* creature) : BossAI(creature, DATA_AYAMISS) { homePos = creature->GetHomePosition(); }
- struct boss_ayamissAI : public BossAI
+ void Reset() override
{
- boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) {}
+ BossAI::Reset();
+ _phase = PHASE_AIR;
+ _enraged = false;
+ SetCombatMovement(false);
+ _scheduler.CancelAll();
+ }
- void Reset() override
+ void JustSummoned(Creature* who) override
+ {
+ switch (who->GetEntry())
{
- _Reset();
- _phase = PHASE_AIR;
- _enraged = false;
- SetCombatMovement(false);
+ case NPC_HIVEZARA_SWARMER:
+ who->CastSpell(who, SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER, true);
+ _swarmers.push_back(who->GetGUID());
+ break;
+ case NPC_HIVEZARA_LARVA:
+ who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos);
+ break;
}
- void JustSummoned(Creature* who) override
+ summons.Summon(who);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == POINT_AIR)
{
- switch (who->GetEntry())
+ me->AddUnitState(UNIT_STATE_ROOT);
+ }
+ else if (type == WAYPOINT_MOTION_TYPE && id == POINT_GROUND)
+ {
+ SetCombatMovement(true);
+
+ me->m_Events.AddEventAtOffset([this]()
{
- case NPC_SWARMER:
- _swarmers.push_back(who->GetGUID());
- break;
- case NPC_LARVA:
- who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos);
- break;
- case NPC_HORNET:
+ if (me->GetVictim())
+ {
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
+ }
+
+ }, 1s);
+ }
+ }
+
+ void ScheduleTasks()
+ {
+ _scheduler.Schedule(20s, 30s, [this](TaskContext context)
+ {
+ DoCastSelf(SPELL_STINGER_SPRAY);
+ context.Repeat(15s, 20s);
+ }).Schedule(5s, [this](TaskContext context) {
+ DoCastVictim(SPELL_POISON_STINGER);
+ context.SetGroup(PHASE_AIR);
+ context.Repeat(2s, 3s);
+ }).Schedule(5s, [this](TaskContext context) {
+ DoCastAOE(SPELL_SUMMON_HIVEZARA_SWARMER, true);
+
+ if (_swarmers.size() >= MAX_SWARMER_COUNT)
+ {
+ DoCastAOE(SPELL_HIVEZARA_SWARMER_SWARM, true);
+ }
+
+ context.Repeat(RAND(2400ms, 3600ms));
+ }).Schedule(15s, [this](TaskContext context) {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
+ {
+ DoCast(target, SPELL_PARALYZE, true);
+ instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
+ DoCastAOE(RAND(SPELL_SUMMON_LARVA_A, SPELL_SUMMON_LARVA_B), true);
+ }
+ context.Repeat();
+ });
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_SWARMER_SWARM)
+ {
+ for (ObjectGuid const& guid : _swarmers)
+ {
+ if (Creature* swarmer = me->GetMap()->GetCreature(guid))
+ {
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
{
- who->AI()->AttackStart(target);
+ swarmer->AI()->AttackStart(target);
}
- break;
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE)
- {
- switch (id)
- {
- case POINT_AIR:
- me->AddUnitState(UNIT_STATE_ROOT);
- break;
- case POINT_GROUND:
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- break;
}
}
+
+ _swarmers.clear();
}
+ }
- void EnterEvadeMode(EvadeReason why) override
- {
- me->ClearUnitState(UNIT_STATE_ROOT);
- BossAI::EnterEvadeMode(why);
- }
-
- void EnterCombat(Unit* attacker) override
- {
- BossAI::EnterCombat(attacker);
- events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(20000, 30000));
- events.ScheduleEvent(EVENT_POISON_STINGER, 5000);
- events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
- events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000);
- events.ScheduleEvent(EVENT_PARALYZE, 15000);
- me->SetCanFly(true);
- me->SetDisableGravity(true);
- me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos);
- }
-
- void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
- {
- if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f)
- {
- _phase = PHASE_GROUND;
- SetCombatMovement(true);
- me->ClearUnitState(UNIT_STATE_ROOT);
- me->SetCanFly(false);
- me->SetDisableGravity(false);
- Position VictimPos = me->GetVictim()->GetPosition();
- me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos);
- events.ScheduleEvent(EVENT_LASH, urand(5000, 8000));
- events.CancelEvent(EVENT_POISON_STINGER);
- DoResetThreat();
- }
- if (!_enraged && me->GetHealthPct() < 20.0f)
- {
- DoCastSelf(SPELL_FRENZY);
- Talk(EMOTE_FRENZY);
- _enraged = true;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_STINGER_SPRAY:
- DoCastSelf(SPELL_STINGER_SPRAY);
- events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000));
- break;
- case EVENT_POISON_STINGER:
- DoCastVictim(SPELL_POISON_STINGER);
- events.ScheduleEvent(EVENT_POISON_STINGER, urand(2000, 3000));
- break;
- case EVENT_PARALYZE:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
- {
- DoCast(target, SPELL_PARALYZE);
- instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
- uint8 Index = urand(0, 1);
- me->SummonCreature(NPC_LARVA, LarvaPos[Index], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
- }
- events.ScheduleEvent(EVENT_PARALYZE, 15000);
- break;
- case EVENT_SWARMER_ATTACK:
- for (ObjectGuid const& guid : _swarmers)
- {
- if (Creature* swarmer = me->GetMap()->GetCreature(guid))
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random))
- {
- swarmer->AI()->AttackStart(target);
- }
- }
- }
- _swarmers.clear();
- events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000);
- break;
- case EVENT_SUMMON_SWARMER:
- {
- Position Pos = me->GetRandomPoint(SwarmerPos, 80.0f);
- me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
- events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
- break;
- }
- case EVENT_LASH:
- DoCastVictim(SPELL_LASH);
- events.ScheduleEvent(EVENT_LASH, urand(8000, 15000));
- break;
- }
- }
- DoMeleeAttackIfReady();
- }
- private:
- GuidList _swarmers;
- uint8 _phase;
- bool _enraged;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+ void EnterEvadeMode(EvadeReason why) override
{
- return GetRuinsOfAhnQirajAI(creature);
+ me->ClearUnitState(UNIT_STATE_ROOT);
+ me->SetHomePosition(homePos);
+ BossAI::EnterEvadeMode(why);
+ }
+
+ void EnterCombat(Unit* attacker) override
+ {
+ BossAI::EnterCombat(attacker);
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos);
+ ScheduleTasks();
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (_phase == PHASE_AIR && me->HealthBelowPctDamaged(70, damage))
+ {
+ _phase = PHASE_GROUND;
+ me->ClearUnitState(UNIT_STATE_ROOT);
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
+ DoResetThreat();
+
+ _scheduler.Schedule(5s, 8s, [this](TaskContext context) {
+ DoCastVictim(SPELL_LASH);
+ context.Repeat(8s, 15s);
+ }).Schedule(16s, [this](TaskContext context)
+ {
+ DoCastSelf(SPELL_THRASH);
+ context.Repeat();
+ });
+
+ _scheduler.DelayAll(5s);
+ _scheduler.CancelGroup(PHASE_AIR);
+ }
+
+ if (!_enraged && me->HealthBelowPctDamaged(20, damage))
+ {
+ DoCastSelf(SPELL_FRENZY);
+ Talk(EMOTE_FRENZY);
+ _enraged = true;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff,
+ std::bind(&BossAI::DoMeleeAttackIfReady, this));
+ }
+private:
+ GuidList _swarmers;
+ uint8 _phase;
+ bool _enraged;
+ TaskScheduler _scheduler;
+ Position homePos;
+};
+
+struct npc_hive_zara_larva : public ScriptedAI
+{
+ npc_hive_zara_larva(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == POINT_PARALYZE)
+ {
+ if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
+ {
+ DoCast(target, SPELL_FEED);
+ }
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (Creature* ayamiss = _instance->GetCreature(DATA_AYAMISS))
+ {
+ ayamiss->AI()->JustSummoned(summon);
+ }
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
+ return;
+
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ void AttackStart(Unit* victim) override
+ {
+ if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
+ return;
+
+ ScriptedAI::AttackStart(victim);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
+ return;
+
+ ScriptedAI::UpdateAI(diff);
+ }
+private:
+ InstanceScript* _instance;
+};
+
+struct npc_hive_zara_swarmer : public ScriptedAI
+{
+ npc_hive_zara_swarmer(Creature* creature) : ScriptedAI(creature) { }
+
+ void PathEndReached(uint32 /*pathId*/) override
+ {
+ // Delay is required because we are calling the movement generator from inside the pathing hook.
+ // If we issue another call here, it will be flushed before it is executed.
+ me->m_Events.AddEventAtOffset([this]()
+ {
+ DoCastSelf(SPELL_HIVEZARA_SWARMER_START_LOOP);
+ }, 1s);
}
};
-class npc_hive_zara_larva : public CreatureScript
+struct WaspTeleportData
{
-public:
- npc_hive_zara_larva() : CreatureScript("npc_hive_zara_larva") { }
+ uint32 spellId;
+ uint32 pathId;
+};
- struct npc_hive_zara_larvaAI : public ScriptedAI
+class spell_ayamiss_swarmer_teleport_trigger : public SpellScript
+{
+ PrepareSpellScript(spell_ayamiss_swarmer_teleport_trigger);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
{
- npc_hive_zara_larvaAI(Creature* creature) : ScriptedAI(creature)
- {
- _instance = me->GetInstanceScript();
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE)
- {
- if (id == POINT_PARALYZE)
- {
- if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
- {
- DoCast(target, SPELL_FEED);
- }
- }
- }
- }
-
- void MoveInLineOfSight(Unit* who) override
-
- {
- if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
- return;
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void AttackStart(Unit* victim) override
- {
- if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
- return;
-
- ScriptedAI::AttackStart(victim);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
- return;
-
- ScriptedAI::UpdateAI(diff);
- }
- private:
- InstanceScript* _instance;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetRuinsOfAhnQirajAI(creature);
+ return ValidateSpellInfo
+ ( {
+ SPELL_HIVEZARA_SWARMER_TELEPORT_1, SPELL_HIVEZARA_SWARMER_TELEPORT_2,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_3, SPELL_HIVEZARA_SWARMER_TELEPORT_4,
+ SPELL_HIVEZARA_SWARMER_TELEPORT_5
+ });
}
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ WaspTeleportData telData[5] =
+ {
+ { SPELL_HIVEZARA_SWARMER_TELEPORT_1, NPC_HIVEZARA_SWARMER * 10 },
+ { SPELL_HIVEZARA_SWARMER_TELEPORT_2, (NPC_HIVEZARA_SWARMER + 1) * 10 },
+ { SPELL_HIVEZARA_SWARMER_TELEPORT_3, (NPC_HIVEZARA_SWARMER + 2) * 10 },
+ { SPELL_HIVEZARA_SWARMER_TELEPORT_4, (NPC_HIVEZARA_SWARMER + 3) * 10 },
+ { SPELL_HIVEZARA_SWARMER_TELEPORT_5, (NPC_HIVEZARA_SWARMER + 4) * 10 }
+ };
+
+ WaspTeleportData data = Acore::Containers::SelectRandomContainerElement(telData);
+ caster->CastSpell((Unit*)nullptr, data.spellId, true);
+
+ uint32 pathId = data.pathId;
+ caster->m_Events.AddEventAtOffset([caster, pathId]()
+ {
+ caster->GetMotionMaster()->MovePath(pathId, false);
+ }, 1s);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_teleport_trigger::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_ayamiss_swarmer_swarm : public SpellScript
+{
+ PrepareSpellScript(spell_ayamiss_swarmer_swarm);
+
+ bool Load() override
+ {
+ return GetCaster()->GetEntry() == NPC_AYAMISS;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->ToCreature()->AI()->DoAction(ACTION_SWARMER_SWARM);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_swarm::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+};
+
+class spell_ayamiss_swarmer_start_loop : public SpellScript
+{
+ PrepareSpellScript(spell_ayamiss_swarmer_start_loop);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 });
+ }
+
+ bool Load() override
+ {
+ return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ uint32 loopSpells[3] = { SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 };
+ GetCaster()->CastSpell((Unit*)nullptr, Acore::Containers::SelectRandomContainerElement(loopSpells));
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_start_loop::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_gen_ayamiss_swarmer_loop: public SpellScript
+{
+ PrepareSpellScript(spell_gen_ayamiss_swarmer_loop);
+
+public:
+ spell_gen_ayamiss_swarmer_loop(uint32 pathId) : SpellScript(), _pathId(pathId) { }
+
+ bool Load() override
+ {
+ return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->ToCreature()->GetMotionMaster()->Clear();
+ GetCaster()->ToCreature()->GetMotionMaster()->MovePath(_pathId, false);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gen_ayamiss_swarmer_loop::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+
+private:
+ uint32 _pathId;
};
void AddSC_boss_ayamiss()
{
- new boss_ayamiss();
- new npc_hive_zara_larva();
+ RegisterRuinsOfAhnQirajCreatureAI(boss_ayamiss);
+ RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_larva);
+ RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_swarmer);
+ RegisterSpellScript(spell_ayamiss_swarmer_teleport_trigger);
+ RegisterSpellScript(spell_ayamiss_swarmer_swarm);
+ RegisterSpellScript(spell_ayamiss_swarmer_start_loop);
+ RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_1", (NPC_HIVEZARA_SWARMER + 5) * 10);
+ RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_2", (NPC_HIVEZARA_SWARMER + 6) * 10);
+ RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_3", (NPC_HIVEZARA_SWARMER + 7) * 10);
}
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp
index 97a419af7..90744df9a 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp
@@ -80,7 +80,7 @@ struct boss_buru : public BossAI
void EnterCombat(Unit* who) override
{
- _EnterCombat();
+ BossAI::EnterCombat(who);
Talk(EMOTE_TARGET, who);
DoCastSelf(SPELL_THORNS);
ManipulateEggs(true);
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp
index 34619337a..b0cf0c878 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp
@@ -28,14 +28,16 @@ enum Spells
SPELL_SAND_TRAP = 25648,
SPELL_ENRAGE = 26527,
SPELL_SUMMON_PLAYER = 26446,
- SPELL_WIDE_SLASH = 25814
+ SPELL_WIDE_SLASH = 25814,
+ SPELL_THRASH = 3391
};
enum Events
{
EVENT_MORTAL_WOUND = 1,
EVENT_SAND_TRAP = 2,
- EVENT_WIDE_SLASH = 3
+ EVENT_WIDE_SLASH = 3,
+ EVENT_THRASH = 4
};
enum Texts
@@ -47,6 +49,12 @@ struct boss_kurinnaxx : public BossAI
{
boss_kurinnaxx(Creature* creature) : BossAI(creature, DATA_KURINNAXX) {}
+ void InitializeAI() override
+ {
+ me->m_CombatDistance = 50.0f;
+ Reset();
+ }
+
void Reset() override
{
BossAI::Reset();
@@ -54,6 +62,7 @@ struct boss_kurinnaxx : public BossAI
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s);
events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s);
events.ScheduleEvent(EVENT_WIDE_SLASH, 10s, 15s);
+ events.ScheduleEvent(EVENT_THRASH, 16s);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
@@ -108,6 +117,10 @@ struct boss_kurinnaxx : public BossAI
DoCastSelf(SPELL_WIDE_SLASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 12s, 15s);
break;
+ case EVENT_THRASH:
+ DoCastSelf(SPELL_THRASH);
+ events.ScheduleEvent(EVENT_THRASH, 16s);
+ break;
default:
break;
}
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp
index a4f70a104..d5b7269b1 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp
@@ -66,9 +66,9 @@ struct boss_moam : public BossAI
{
BossAI::EnterCombat(who);
Talk(EMOTE_AGGRO);
- events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
- events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9000);
- events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3000);
+ events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
+ events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9s);
+ events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3s);
}
void JustDied(Unit* /*killer*/) override
@@ -113,20 +113,20 @@ struct boss_moam : public BossAI
DoCastAOE(SPELL_SUMMON_MANA_FIENDS);
DoCastSelf(SPELL_ENERGIZE);
events.CancelEvent(EVENT_SPELL_DRAIN_MANA);
- events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000);
+ events.ScheduleEvent(EVENT_STONE_PHASE_END, 90s);
break;
case EVENT_STONE_PHASE_END:
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
- events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000));
- events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
+ events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s);
+ events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
break;
case EVENT_SPELL_DRAIN_MANA:
DoCastAOE(SPELL_DRAIN_MANA_SERVERSIDE);
- events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000));
+ events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s);
break;
case EVENT_SPELL_TRAMPLE:
DoCastAOE(SPELL_TRAMPLE);
- events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15000);
+ events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15s);
break;
default:
break;
@@ -148,6 +148,11 @@ class spell_moam_mana_drain_filter : public SpellScript
{
return !target->IsPlayer() || target->ToPlayer()->getPowerType() != POWER_MANA;
});
+
+ if (!targets.empty())
+ {
+ Acore::Containers::RandomResize(targets, 6);
+ }
}
void HandleScript(SpellEffIndex /*effIndex*/)
@@ -160,7 +165,7 @@ class spell_moam_mana_drain_filter : public SpellScript
void Register() override
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_moam_mana_drain_filter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
index bfa85bc52..e61163f57 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp
@@ -21,6 +21,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
+#include "SpellScript.h"
#include "ruins_of_ahnqiraj.h"
#include "TaskScheduler.h"
@@ -35,12 +36,20 @@ enum Texts
enum Spells
{
- SPELL_CURSE_OF_TONGUES = 25195,
- SPELL_ENVELOPING_WINDS = 25189,
- SPELL_WAR_STOMP = 25188,
- SPELL_STRENGHT_OF_OSSIRIAN = 25176,
- SPELL_SAND_STORM = 25160,
- SPELL_SUMMON_CRYSTAL = 25192
+ SPELL_CURSE_OF_TONGUES = 25195,
+ SPELL_ENVELOPING_WINDS = 25189,
+ SPELL_WAR_STOMP = 25188,
+ SPELL_STRENGHT_OF_OSSIRIAN = 25176,
+ SPELL_SAND_STORM = 25160,
+ SPELL_SUMMON_CRYSTAL = 25192,
+ SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK = 27627, // Server-side
+
+ // Crystal
+ SPELL_FIRE_WEAKNESS = 25177,
+ SPELL_FROST_WEAKNESS = 25178,
+ SPELL_NATURE_WEAKNESS = 25180,
+ SPELL_ARCANE_WEAKNESS = 25181,
+ SPELL_SHADOW_WEAKNESS = 25183
};
enum Actions
@@ -55,25 +64,27 @@ enum Events
EVENT_STOMP = 3
};
-uint8 const NUM_CRYSTALS = 9;
+uint8 const NUM_CRYSTALS = 11;
Position CrystalCoordinates[NUM_CRYSTALS] =
{
- { -9394.230469f, 1951.808594f, 85.97733f, 0.0f },
- { -9357.931641f, 1930.596802f, 85.556198f, 0.0f },
- { -9383.113281f, 2011.042725f, 85.556389f, 0.0f },
- { -9243.36f, 1979.04f, 85.556f, 0.0f },
- { -9281.68f, 1886.66f, 85.5558f, 0.0f },
- { -9241.8f, 1806.39f, 85.5557f, 0.0f },
- { -9366.78f, 1781.76f, 85.5561f, 0.0f },
- { -9430.37f, 1786.86f, 85.557f, 0.0f },
- { -9406.73f, 1863.13f, 85.5558f, 0.0f }
+ { -9388.4404296875f, 1940.20996093750f, 85.6390991210937f, 3.17650008201599f },
+ { -9357.8603515625f, 1929.07995605469f, 85.6390991210937f, 1.06465005874634f },
+ { -9383.2900390625f, 2012.68005371094f, 85.6511001586914f, 2.93214988708496f },
+ { -9248.4101562500f, 1974.82995605469f, 85.6390991210937f, 5.89920997619629f },
+ { -9432.4003906250f, 1782.53002929687f, 85.6390991210937f, 5.86430978775024f },
+ { -9299.7304687500f, 1748.44995117187f, 85.6390991210937f, 1.44861996173859f },
+ { -9406.0996093750f, 1862.38000488281f, 85.6390991210937f, 6.23082017898560f },
+ { -9506.1904296875f, 1865.56994628906f, 85.6390991210937f, 4.27606010437012f },
+ { -9282.0800781250f, 1887.33996582031f, 85.6390991210937f, 2.00712990760803f },
+ { -9244.4101562500f, 1808.97998046875f, 85.6390991210937f, 5.63741016387939f },
+ { -9367.1699218750f, 1780.89001464844f, 85.6390991210937f, 1.90241003036499f }
};
-float roomRadius = 165.0f;
-uint8 const NUM_TORNADOS = 2;
+Position initialCrystalPosition = { -9407.7197265625f, 1960.2099609375f, 85.6390991210937f, 1.11700999736786f };
+
uint8 const NUM_WEAKNESS = 5;
-uint32 const spellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 };
-Position const RoomCenter = { -9343.041992f, 1923.278198f, 85.555984f, 0.0 };
+uint32 const spellWeakness[NUM_WEAKNESS] =
+{ SPELL_FIRE_WEAKNESS, SPELL_FROST_WEAKNESS, SPELL_NATURE_WEAKNESS, SPELL_ARCANE_WEAKNESS, SPELL_SHADOW_WEAKNESS };
struct boss_ossirian : public BossAI
{
@@ -82,36 +93,103 @@ struct boss_ossirian : public BossAI
_saidIntro = false;
}
- void Reset() override
+ void InitializeAI() override
{
- BossAI::Reset();
- _crystalIterator = 0;
- _triggerGUID.Clear();
- _crystalGUID.Clear();
- }
+ Reset();
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- for (uint8 weakness : spellWeakness)
+ if (Creature* trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, initialCrystalPosition))
{
- if (spell->Id == weakness)
+ _triggerGUID[0] = trigger->GetGUID();
+ if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
+ initialCrystalPosition.GetPositionX(),
+ initialCrystalPosition.GetPositionY(),
+ initialCrystalPosition.GetPositionZ(),
+ 0, 0, 0, 0, 0, uint32(-1)))
{
- me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN);
- ((TempSummon*)caster)->UnSummon();
- SpawnNextCrystal();
+ _crystalGUID[0] = crystal->GetGUID();
+ crystal->SetOwnerGUID(ObjectGuid::Empty);
+ crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
}
}
}
- void DoAction(int32 action) override
+ void Reset() override
+ {
+ BossAI::Reset();
+
+ _crystalIterator = urand(0, NUM_CRYSTALS - 1);
+ _triggerGUID[1].Clear();
+ _crystalGUID[1].Clear();
+ }
+
+ void JustReachedHome() override
+ {
+ if (me->IsVisible())
+ {
+ Creature* trigger = me->GetMap()->GetCreature(_triggerGUID[0]);
+ if (trigger)
+ {
+ trigger->DespawnOrUnsummon();
+ if (GameObject* crystal = me->GetMap()->GetGameObject(_crystalGUID[0]))
+ crystal->Delete();
+ }
+
+ trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, initialCrystalPosition);
+ if (trigger)
+ {
+ _triggerGUID[0] = trigger->GetGUID();
+ if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
+ initialCrystalPosition.GetPositionX(),
+ initialCrystalPosition.GetPositionY(),
+ initialCrystalPosition.GetPositionZ(),
+ 0, 0, 0, 0, 0, uint32(-1)))
+ {
+ _crystalGUID[0] = crystal->GetGUID();
+ crystal->SetOwnerGUID(ObjectGuid::Empty);
+ crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
+ }
+ }
+ }
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ for (uint32 weakness : spellWeakness)
+ {
+ if (spell->Id == weakness)
+ {
+ me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN);
+
+ if (caster->GetGUID() == _triggerGUID[1])
+ {
+ if (Creature* creatureCaster = caster->ToCreature())
+ {
+ creatureCaster->DespawnOrUnsummon();
+ }
+ }
+ }
+ }
+ }
+
+ void SetGUID(ObjectGuid guid, int32 action) override
{
if (action == ACTION_TRIGGER_WEAKNESS)
{
- if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID))
+ for (uint8 i = 0; i < 2; ++i)
{
- if (!trigger->HasUnitState(UNIT_STATE_CASTING))
+ if (_crystalGUID[i] == guid)
{
- trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false);
+ if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID[i]))
+ {
+ if (!trigger->HasUnitState(UNIT_STATE_CASTING))
+ {
+ trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false);
+ }
+ }
+
+ SpawnNextCrystal();
+
+ break;
}
}
}
@@ -133,77 +211,55 @@ struct boss_ossirian : public BossAI
WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f);
map->SendToPlayers(weather.Write());
- for (uint8 i = 0; i < NUM_TORNADOS; ++i)
- {
- Position Point = me->GetRandomPoint(RoomCenter, roomRadius);
- if (Creature* Tornado = me->GetMap()->SummonCreature(NPC_SAND_VORTEX, Point))
- {
- Tornado->CastSpell(Tornado, SPELL_SAND_STORM, true);
- }
- }
+
SpawnNextCrystal();
}
+ void SummonedCreatureDespawn(Creature* summon) override
+ {
+ summons.Despawn(summon);
+
+ if (GameObject* crystal = GetClosestGameObjectWithEntry(summon, GO_OSSIRIAN_CRYSTAL, 5.0f))
+ {
+ crystal->Delete();
+ }
+ }
+
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
- void EnterEvadeMode(EvadeReason why) override
- {
- Cleanup();
- summons.DespawnAll();
- BossAI::EnterEvadeMode(why);
- }
-
- void JustDied(Unit* killer) override
- {
- Cleanup();
- BossAI::JustDied(killer);
- }
-
- void Cleanup()
- {
- if (GameObject* crystal = me->GetMap()->GetGameObject(_crystalGUID))
- {
- crystal->Use(me);
- }
-
- std::list vortexes;
- me->GetCreaturesWithEntryInRange(vortexes, 200.f, NPC_SAND_VORTEX);
- for (Creature* vortex : vortexes)
- vortex->DespawnOrUnsummon();
- }
-
void SpawnNextCrystal()
{
if (_crystalIterator == NUM_CRYSTALS)
_crystalIterator = 0;
- if (Creature* trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[_crystalIterator]))
+ if (Creature* trigger = me->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[_crystalIterator]))
{
- _triggerGUID = trigger->GetGUID();
+ _triggerGUID[1] = trigger->GetGUID();
if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
CrystalCoordinates[_crystalIterator].GetPositionX(),
CrystalCoordinates[_crystalIterator].GetPositionY(),
CrystalCoordinates[_crystalIterator].GetPositionZ(),
0, 0, 0, 0, 0, uint32(-1)))
{
- _crystalGUID = crystal->GetGUID();
+ _crystalGUID[1] = crystal->GetGUID();
++_crystalIterator;
crystal->SetOwnerGUID(ObjectGuid::Empty);
+ crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
}
}
}
void MoveInLineOfSight(Unit* who) override
-
{
if (!_saidIntro)
{
Talk(SAY_INTRO);
_saidIntro = true;
}
+
BossAI::MoveInLineOfSight(who);
}
@@ -220,7 +276,7 @@ struct boss_ossirian : public BossAI
}
else
{
- for (uint8 weakness : spellWeakness)
+ for (uint32 weakness : spellWeakness)
{
if (me->HasAura(weakness))
{
@@ -260,8 +316,8 @@ struct boss_ossirian : public BossAI
}
protected:
- ObjectGuid _triggerGUID;
- ObjectGuid _crystalGUID;
+ std::array _triggerGUID;
+ std::array _crystalGUID;
uint8 _crystalIterator;
bool _saidIntro;
};
@@ -271,18 +327,18 @@ class go_ossirian_crystal : public GameObjectScript
public:
go_ossirian_crystal() : GameObjectScript("go_ossirian_crystal") { }
- bool OnGossipHello(Player* player, GameObject* /*go*/) override
+ bool OnGossipHello(Player* player, GameObject* go) override
{
InstanceScript* instance = player->GetInstanceScript();
if (!instance)
- return false;
+ return true;
Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN);
- if (!ossirian || instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS)
- return false;
+ if (!ossirian)
+ return true;
- ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS);
- return true;
+ ossirian->AI()->SetGUID(go->GetGUID(), ACTION_TRIGGER_WEAKNESS);
+ return false;
}
};
@@ -348,6 +404,11 @@ struct npc_anubisath_guardian : public ScriptedAI
}
}
+ void JustDied(Unit* /*killer*/) override
+ {
+ DoCastSelf(SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK, true);
+ }
+
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -363,9 +424,28 @@ private:
TaskScheduler _scheduler;
};
+class spell_crystal_weakness : public SpellScript
+{
+ PrepareSpellScript(spell_crystal_weakness);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if([&](WorldObject const* target) -> bool
+ {
+ return target->GetEntry() != NPC_OSSIRIAN;
+ });
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_crystal_weakness::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENTRY);
+ }
+};
+
void AddSC_boss_ossirian()
{
RegisterRuinsOfAhnQirajCreatureAI(boss_ossirian);
new go_ossirian_crystal();
RegisterCreatureAI(npc_anubisath_guardian);
+ RegisterSpellScript(spell_crystal_weakness);
}
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp
index 2c648dfb0..6b543c55b 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp
@@ -46,71 +46,60 @@ enum Events
EVENT_CHANGE_AGGRO = 3,
};
-class boss_rajaxx : public CreatureScript
+struct boss_rajaxx : public BossAI
{
-public:
- boss_rajaxx() : CreatureScript("boss_rajaxx") { }
+ boss_rajaxx(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
- struct boss_rajaxxAI : public BossAI
+ void Reset() override
{
- boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
-
- void Reset() override
- {
- _Reset();
- enraged = false;
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
- _JustDied();
- }
-
- void EnterCombat(Unit* /*victim*/) override
- {
- _EnterCombat();
- events.ScheduleEvent(EVENT_DISARM, 10000);
- events.ScheduleEvent(EVENT_THUNDERCRASH, 12000);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_DISARM:
- DoCastVictim(SPELL_DISARM);
- events.ScheduleEvent(EVENT_DISARM, 22000);
- break;
- case EVENT_THUNDERCRASH:
- DoCast(me, SPELL_THUNDERCRASH);
- events.ScheduleEvent(EVENT_THUNDERCRASH, 21000);
- break;
- default:
- break;
- }
- }
-
- DoMeleeAttackIfReady();
- }
- private:
- bool enraged;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetRuinsOfAhnQirajAI(creature);
+ BossAI::Reset();
+ enraged = false;
}
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
+
+ void EnterCombat(Unit* /*victim*/) override
+ {
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_DISARM, 10s);
+ events.ScheduleEvent(EVENT_THUNDERCRASH, 12s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_DISARM:
+ DoCastVictim(SPELL_DISARM);
+ events.ScheduleEvent(EVENT_DISARM, 22s);
+ break;
+ case EVENT_THUNDERCRASH:
+ DoCastSelf(SPELL_THUNDERCRASH);
+ events.ScheduleEvent(EVENT_THUNDERCRASH, 21s);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+private:
+ bool enraged;
};
class spell_rajaxx_thundercrash : public SpellScript
@@ -136,6 +125,6 @@ class spell_rajaxx_thundercrash : public SpellScript
void AddSC_boss_rajaxx()
{
- new boss_rajaxx();
+ RegisterRuinsOfAhnQirajCreatureAI(boss_rajaxx);
RegisterSpellScript(spell_rajaxx_thundercrash);
}
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
index aa088d091..c5ac1d205 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp
@@ -26,6 +26,7 @@ ObjectData const creatureData[] =
{ NPC_BURU, DATA_BURU },
{ NPC_KURINNAXX, DATA_KURINNAXX },
{ NPC_RAJAXX, DATA_RAJAXX },
+ { NPC_AYAMISS, DATA_AYAMISS },
{ NPC_OSSIRIAN, DATA_OSSIRIAN },
{ NPC_QUUEZ, DATA_QUUEZ },
{ NPC_TUUBID, DATA_TUUBID },
@@ -36,14 +37,17 @@ ObjectData const creatureData[] =
{ NPC_ZERRAN, DATA_ZERRAN },
};
-enum RajaxxText
+enum RajaxxWaveEvent
{
SAY_WAVE3 = 0,
SAY_WAVE4 = 1,
SAY_WAVE5 = 2,
SAY_WAVE6 = 3,
SAY_WAVE7 = 4,
- SAY_ENGAGE = 5
+ SAY_ENGAGE = 5,
+
+ DATA_RAJAXX_WAVE_ENGAGED = 1,
+ GROUP_RAJAXX_WAVE_TIMER = 1
};
std::array RajaxxWavesData[] =
@@ -90,12 +94,13 @@ public:
case NPC_BURU:
_buruGUID = creature->GetGUID();
break;
- case NPC_AYAMISS:
- _ayamissGUID = creature->GetGUID();
- break;
case NPC_OSSIRIAN:
_ossirianGUID = creature->GetGUID();
break;
+ case NPC_SAND_VORTEX:
+ _sandVortexes.push_back(creature->GetGUID());
+ creature->SetVisible(false);
+ break;
}
}
@@ -130,6 +135,20 @@ public:
}
}
+ void SetData(uint32 type, uint32 /*data*/) override
+ {
+ if (type == DATA_RAJAXX_WAVE_ENGAGED)
+ {
+ _scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
+ _scheduler.Schedule(2min, [this](TaskContext context)
+ {
+ CallNextRajaxxLeader();
+ context.SetGroup(GROUP_RAJAXX_WAVE_TIMER);
+ context.Repeat();
+ });
+ }
+ }
+
void OnUnitDeath(Unit* unit) override
{
if (Creature* creature = unit->ToCreature())
@@ -151,7 +170,7 @@ public:
_scheduler.Schedule(1s, [this, formation](TaskContext /*context*/) {
if (!formation->IsAnyMemberAlive())
{
- CallNextRajaxxLeader();
+ CallNextRajaxxLeader(true);
}
});
break;
@@ -174,6 +193,31 @@ public:
_paralyzedGUID = data;
}
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DATA_OSSIRIAN:
+ {
+ for (ObjectGuid const& guid : _sandVortexes)
+ {
+ if (Creature* sandVortex = instance->GetCreature(guid))
+ {
+ sandVortex->SetVisible(state == IN_PROGRESS);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+ }
+
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
@@ -186,8 +230,6 @@ public:
return _moamGUID;
case DATA_BURU:
return _buruGUID;
- case DATA_AYAMISS:
- return _ayamissGUID;
case DATA_OSSIRIAN:
return _ossirianGUID;
case DATA_PARALYZED:
@@ -240,17 +282,20 @@ public:
OUT_LOAD_INST_DATA_COMPLETE;
}
- void CallNextRajaxxLeader()
+ void CallNextRajaxxLeader(bool announce = false)
{
++_rajaxWaveCounter;
if (Creature* nextLeader = GetCreature(RajaxxWavesData[_rajaxWaveCounter].at(0)))
{
- if (_rajaxWaveCounter >= 2)
+ if (announce)
{
- if (Creature* rajaxx = GetCreature(DATA_RAJAXX))
+ if (_rajaxWaveCounter >= 2)
{
- rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1));
+ if (Creature* rajaxx = GetCreature(DATA_RAJAXX))
+ {
+ rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1));
+ }
}
}
@@ -268,6 +313,7 @@ public:
void ResetRajaxxWaves()
{
_rajaxWaveCounter = 0;
+ _scheduler.CancelAll();
for (auto const& data : RajaxxWavesData)
{
if (Creature* creature = GetCreature(data.at(0)))
@@ -285,9 +331,9 @@ public:
ObjectGuid _rajaxxGUID;
ObjectGuid _moamGUID;
ObjectGuid _buruGUID;
- ObjectGuid _ayamissGUID;
ObjectGuid _ossirianGUID;
ObjectGuid _paralyzedGUID;
+ GuidVector _sandVortexes;
uint32 _rajaxWaveCounter;
TaskScheduler _scheduler;
};
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.cpp
new file mode 100644
index 000000000..5675b922a
--- /dev/null
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.cpp
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "ruins_of_ahnqiraj.h"
+#include "TaskScheduler.h"
+
+enum Spells
+{
+ SPELL_HIVEZARA_CATALYST = 25187,
+ SPELL_STINGER_CHARGE_NORMAL = 25190,
+ SPELL_STINGER_CHARGE_BUFFED = 25191
+};
+
+struct npc_hivezara_stinger : public ScriptedAI
+{
+ npc_hivezara_stinger(Creature* creature) : ScriptedAI(creature)
+ {
+ }
+
+ void Reset() override
+ {
+ _scheduler.CancelAll();
+ }
+
+ void EnterCombat(Unit* who) override
+ {
+ DoCast(who ,who->HasAura(SPELL_HIVEZARA_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true);
+
+ _scheduler.Schedule(5s, [this](TaskContext context)
+ {
+ Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u)
+ {
+ return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f) && u->HasAura(SPELL_HIVEZARA_CATALYST);
+ });
+ if (!target)
+ {
+ target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u)
+ {
+ return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f);
+ });
+ }
+
+ if (target)
+ {
+ DoCast(target, target->HasAura(SPELL_HIVEZARA_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true);
+ }
+
+ context.Repeat(4500ms, 6500ms);
+ });
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ {
+ return;
+ }
+
+ _scheduler.Update(diff,
+ std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
+ }
+
+private:
+ TaskScheduler _scheduler;
+};
+
+void AddSC_ruins_of_ahnqiraj()
+{
+ RegisterRuinsOfAhnQirajCreatureAI(npc_hivezara_stinger);
+}
diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h
index 522b70c78..418c9edbe 100644
--- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h
+++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h
@@ -60,9 +60,6 @@ enum Creatures
NPC_OSSIRIAN_TRIGGER = 15590,
NPC_HATCHLING = 15521,
NPC_BURU_EGG = 15514,
- NPC_LARVA = 15555,
- NPC_SWARMER = 15546,
- NPC_HORNET = 15934,
// Rajaxx
NPC_QUUEZ = 15391,
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp
index cf765b460..c57a95144 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp
@@ -137,9 +137,9 @@ public:
me->SetReactState(REACT_PASSIVE);
}
- void MovementInform(uint32 type, uint32 /*id*/) override
+ void MovementInform(uint32 type, uint32 id) override
{
- if (type != POINT_MOTION_TYPE)
+ if (type != POINT_MOTION_TYPE || id != POINT_CONSUME)
return;
me->GetMotionMaster()->MoveIdle();
@@ -153,6 +153,7 @@ public:
me->SetReactState(REACT_AGGRESSIVE);
if (Unit* target = me->GetVictim())
{
+ me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveChase(target);
AttackStart(target);
}
@@ -195,7 +196,7 @@ public:
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
- if (me->HealthBelowPctDamaged(1, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && who->GetGUID() != me->GetGUID())
+ if (me->HealthBelowPctDamaged(1, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && who->GetGUID() != me->GetGUID() && !dying)
{
damage = 0;
if (isEating)
@@ -205,6 +206,7 @@ public:
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->SetReactState(REACT_PASSIVE);
me->SetControlled(true, UNIT_STATE_ROOT);
+ dying = true;
DoFinalSpell();
@@ -236,7 +238,7 @@ public:
_scheduler.Schedule(4s, [this](TaskContext /*context*/)
{
- if (!me->IsInEvadeMode())
+ if (!me->IsInEvadeMode() && instance->GetData(DATA_BUG_TRIO_DEATH) < 2)
{
DoCastSelf(SPELL_BLOODY_DEATH, true);
Talk(EMOTE_DEVOURED);
@@ -452,9 +454,9 @@ class spell_vem_vengeance : public SpellScript
void AddSC_bug_trio()
{
- RegisterCreatureAI(boss_kri);
- RegisterCreatureAI(boss_vem);
- RegisterCreatureAI(boss_yauj);
+ RegisterTempleOfAhnQirajCreatureAI(boss_kri);
+ RegisterTempleOfAhnQirajCreatureAI(boss_vem);
+ RegisterTempleOfAhnQirajCreatureAI(boss_yauj);
RegisterSpellScript(spell_vem_knockback);
RegisterSpellScript(spell_vem_vengeance);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
index 66211a1b0..778daca97 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp
@@ -142,93 +142,85 @@ public:
//Kick out position
const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f};
-class boss_eye_of_cthun : public CreatureScript
+struct boss_eye_of_cthun : public ScriptedAI
{
-public:
- boss_eye_of_cthun() : CreatureScript("boss_eye_of_cthun") { }
-
- CreatureAI* GetAI(Creature* creature) const override
+ boss_eye_of_cthun(Creature* creature) : ScriptedAI(creature), _summons(creature)
{
- return GetTempleOfAhnQirajAI(creature);
+ instance = creature->GetInstanceScript();
+
+ SetCombatMovement(false);
}
- struct eye_of_cthunAI : public ScriptedAI
+ void Reset() override
{
- eye_of_cthunAI(Creature* creature) : ScriptedAI(creature), _summons(creature)
+ //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks)
+ DarkGlareTick = 0;
+ DarkGlareAngle = 0;
+ ClockWise = false;
+
+ _eyeTentacleCounter = 0;
+
+ //Reset flags
+ me->RemoveAurasDueToSpell(SPELL_RED_COLORATION);
+ me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ me->SetVisible(true);
+
+ //Reset Phase
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED);
+
+ //to avoid having a following void zone
+ Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10);
+ if (pPortal)
+ pPortal->SetReactState(REACT_PASSIVE);
+
+ _summons.DespawnAll();
+ _scheduler.CancelAll();
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ ScheduleTasks();
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat())
{
- instance = creature->GetInstanceScript();
-
- SetCombatMovement(false);
- }
-
- void Reset() override
- {
- //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks)
- DarkGlareTick = 0;
- DarkGlareAngle = 0;
- ClockWise = false;
-
- _eyeTentacleCounter = 0;
-
- //Reset flags
- me->RemoveAurasDueToSpell(SPELL_RED_COLORATION);
- me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- me->SetVisible(true);
-
- //Reset Phase
- instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED);
-
- //to avoid having a following void zone
- Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10);
- if (pPortal)
- pPortal->SetReactState(REACT_PASSIVE);
-
- _summons.DespawnAll();
- _scheduler.CancelAll();
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
- ScheduleTasks();
- instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat())
+ // Z checks are necessary here because AQ maps do funky stuff.
+ if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f)
{
- // Z checks are necessary here because AQ maps do funky stuff.
- if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f)
- {
- AttackStart(who);
- }
+ AttackStart(who);
}
}
+ }
- void DoAction(int32 action) override
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_SPAWN_EYE_TENTACLES)
{
- if (action == ACTION_SPAWN_EYE_TENTACLES)
- {
- me->SummonCreatureGroup(_eyeTentacleCounter);
- _eyeTentacleCounter++;
+ me->SummonCreatureGroup(_eyeTentacleCounter);
+ _eyeTentacleCounter++;
- if (_eyeTentacleCounter >= MAX_TENTACLE_GROUPS)
- {
- _eyeTentacleCounter = 0;
- }
+ if (_eyeTentacleCounter >= MAX_TENTACLE_GROUPS)
+ {
+ _eyeTentacleCounter = 0;
}
}
+ }
- void ScheduleTasks()
- {
- _scheduler.Schedule(3s, [this](TaskContext task)
+ void ScheduleTasks()
+ {
+ _scheduler.
+ Schedule(3s, [this](TaskContext task)
{
DoCastRandomTarget(SPELL_GREEN_BEAM);
task.SetGroup(GROUP_BEAM_PHASE);
task.Repeat();
- }).Schedule(12s, [this](TaskContext task)
+ })
+ .Schedule(12s, [this](TaskContext task)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
@@ -240,12 +232,14 @@ public:
task.SetGroup(GROUP_BEAM_PHASE);
task.Repeat();
- }).Schedule(45s, [this](TaskContext task)
+ })
+ .Schedule(45s, [this](TaskContext task)
{
DoAction(ACTION_SPAWN_EYE_TENTACLES);
task.SetGroup(GROUP_BEAM_PHASE);
task.Repeat();
- }).Schedule(50s, [this](TaskContext /*task*/)
+ })
+ .Schedule(50s, [this](TaskContext /*task*/)
{
_scheduler.CancelGroup(GROUP_BEAM_PHASE);
@@ -311,340 +305,366 @@ public:
});
});
});
- }
-
- void JustSummoned(Creature* summon) override
- {
- _summons.Summon(summon);
- summon->SetInCombatWithZone();
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- return;
-
- switch (instance->GetData(DATA_CTHUN_PHASE))
- {
- //Transition phase
- case PHASE_CTHUN_TRANSITION:
- //Remove any target
- me->SetTarget();
- me->SetHealth(0);
- me->SetVisible(false);
- break;
-
- //Dead phase
- case PHASE_CTHUN_DONE:
- if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10))
- {
- pPortal->DespawnOrUnsummon();
- }
-
- me->DespawnOrUnsummon();
- break;
- }
-
- _scheduler.Update(diff);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- switch (instance->GetData(DATA_CTHUN_PHASE))
- {
- case PHASE_EYE_GREEN_BEAM:
- case PHASE_EYE_RED_BEAM:
- //Only if it will kill
- if (damage < me->GetHealth())
- return;
-
- //Fake death in phase 0 or 1 (green beam or dark glare phase)
- me->InterruptNonMeleeSpells(false);
-
- //Remove Red coloration from c'thun
- me->RemoveAurasDueToSpell(SPELL_RED_COLORATION);
-
- //Reset to normal emote state and prevent select and attack
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
-
- //Remove Target field
- me->SetTarget();
-
- //Death animation/respawning;
- instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_TRANSITION);
-
- me->SetHealth(0);
- damage = 0;
-
- me->InterruptNonMeleeSpells(true);
- me->RemoveAllAuras();
- _scheduler.CancelAll();
- break;
-
- case PHASE_CTHUN_DONE:
- //Allow death here
- return;
-
- default:
- //Prevent death in these phases
- damage = 0;
- return;
- }
- }
-
- private:
- InstanceScript* instance;
-
- //Dark Glare phase
- uint32 DarkGlareTick;
- float DarkGlareAngle;
- bool ClockWise;
-
- uint32 _eyeTentacleCounter;
- TaskScheduler _scheduler;
- SummonList _summons;
- };
-};
-
-class boss_cthun : public CreatureScript
-{
-public:
- boss_cthun() : CreatureScript("boss_cthun") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetTempleOfAhnQirajAI(creature);
}
- struct cthunAI : public ScriptedAI
+ void JustSummoned(Creature* summon) override
{
- cthunAI(Creature* creature) : ScriptedAI(creature)
- {
- SetCombatMovement(false);
+ _summons.Summon(summon);
+ summon->SetInCombatWithZone();
+ }
- instance = creature->GetInstanceScript();
+ void UpdateAI(uint32 diff) override
+ {
+ //Check if we have a target
+ if (!UpdateVictim())
+ return;
+
+ switch (instance->GetData(DATA_CTHUN_PHASE))
+ {
+ //Transition phase
+ case PHASE_CTHUN_TRANSITION:
+ //Remove any target
+ me->SetTarget();
+ me->SetHealth(0);
+ me->SetVisible(false);
+ break;
+
+ //Dead phase
+ case PHASE_CTHUN_DONE:
+ if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10))
+ {
+ pPortal->DespawnOrUnsummon();
+ }
+
+ me->DespawnOrUnsummon();
+ break;
}
- InstanceScript* instance;
+ _scheduler.Update(diff);
+ }
- //Out of combat whisper timer
- uint32 WisperTimer;
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ switch (instance->GetData(DATA_CTHUN_PHASE))
+ {
+ case PHASE_EYE_GREEN_BEAM:
+ case PHASE_EYE_RED_BEAM:
+ //Only if it will kill
+ if (damage < me->GetHealth())
+ return;
- //Global variables
- uint32 PhaseTimer;
+ //Fake death in phase 0 or 1 (green beam or dark glare phase)
+ me->InterruptNonMeleeSpells(false);
- //-------------------
+ //Remove Red coloration from c'thun
+ me->RemoveAurasDueToSpell(SPELL_RED_COLORATION);
- //Phase transition
- ObjectGuid HoldPlayer;
+ //Reset to normal emote state and prevent select and attack
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+
+ //Remove Target field
+ me->SetTarget();
+
+ //Death animation/respawning;
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_TRANSITION);
+
+ me->SetHealth(0);
+ damage = 0;
+
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAllAuras();
+ _scheduler.CancelAll();
+ break;
+
+ case PHASE_CTHUN_DONE:
+ //Allow death here
+ return;
+
+ default:
+ //Prevent death in these phases
+ damage = 0;
+ return;
+ }
+ }
+
+private:
+ InstanceScript* instance;
+
+ //Dark Glare phase
+ uint32 DarkGlareTick;
+ float DarkGlareAngle;
+ bool ClockWise;
+
+ uint32 _eyeTentacleCounter;
+ TaskScheduler _scheduler;
+ SummonList _summons;
+};
+
+struct boss_cthun : public ScriptedAI
+{
+ boss_cthun(Creature* creature) : ScriptedAI(creature)
+ {
+ SetCombatMovement(false);
+
+ instance = creature->GetInstanceScript();
+ }
+
+ InstanceScript* instance;
+
+ //Out of combat whisper timer
+ uint32 WisperTimer;
+
+ //Global variables
+ uint32 PhaseTimer;
+
+ //-------------------
+
+ //Phase transition
+ ObjectGuid HoldPlayer;
+
+ //Body Phase
+ uint32 EyeTentacleTimer;
+ uint8 FleshTentaclesKilled;
+ uint32 GiantClawTentacleTimer;
+ uint32 GiantEyeTentacleTimer;
+ uint32 StomachAcidTimer;
+ uint32 StomachEnterTimer;
+ uint32 StomachEnterVisTimer;
+ ObjectGuid StomachEnterTarget;
+
+ //Stomach map, bool = true then in stomach
+ std::unordered_map Stomach_Map;
+
+ void Reset() override
+ {
+ //One random wisper every 90 - 300 seconds
+ WisperTimer = 90000;
+
+ //Phase information
+ PhaseTimer = 10000; //Emerge in 10 seconds
+
+ //No hold player for transition
+ HoldPlayer.Clear();
//Body Phase
- uint32 EyeTentacleTimer;
- uint8 FleshTentaclesKilled;
- uint32 GiantClawTentacleTimer;
- uint32 GiantEyeTentacleTimer;
- uint32 StomachAcidTimer;
- uint32 StomachEnterTimer;
- uint32 StomachEnterVisTimer;
- ObjectGuid StomachEnterTarget;
+ EyeTentacleTimer = 30000;
+ FleshTentaclesKilled = 0;
+ GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat)
+ GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat)
+ StomachAcidTimer = 4000; //Every 4 seconds
+ StomachEnterTimer = 10000; //Every 10 seconds
+ StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer
+ StomachEnterTarget.Clear(); //Target to be teleported to stomach
- //Stomach map, bool = true then in stomach
- std::unordered_map Stomach_Map;
+ //Clear players in stomach and outside
+ Stomach_Map.clear();
- void Reset() override
+ //Reset flags
+ me->RemoveAurasDueToSpell(SPELL_TRANSFORM);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ me->SetVisible(false);
+
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED);
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ }
+
+ Unit* SelectRandomNotStomach()
+ {
+ if (Stomach_Map.empty())
+ return nullptr;
+
+ std::unordered_map::const_iterator i = Stomach_Map.begin();
+
+ std::list temp;
+ std::list::const_iterator j;
+
+ //Get all players in map
+ while (i != Stomach_Map.end())
{
- //One random wisper every 90 - 300 seconds
- WisperTimer = 90000;
+ //Check for valid player
+ Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
- //Phase information
- PhaseTimer = 10000; //Emerge in 10 seconds
+ //Only units out of stomach
+ if (unit && !i->second)
+ temp.push_back(unit);
- //No hold player for transition
- HoldPlayer.Clear();
-
- //Body Phase
- EyeTentacleTimer = 30000;
- FleshTentaclesKilled = 0;
- GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat)
- GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat)
- StomachAcidTimer = 4000; //Every 4 seconds
- StomachEnterTimer = 10000; //Every 10 seconds
- StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer
- StomachEnterTarget.Clear(); //Target to be teleported to stomach
-
- //Clear players in stomach and outside
- Stomach_Map.clear();
-
- //Reset flags
- me->RemoveAurasDueToSpell(SPELL_TRANSFORM);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- me->SetVisible(false);
-
- instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED);
+ ++i;
}
- void EnterCombat(Unit* /*who*/) override
+ if (temp.empty())
+ return nullptr;
+
+ j = temp.begin();
+
+ //Get random but only if we have more than one unit on threat list
+ if (temp.size() > 1)
+ advance(j, rand() % (temp.size() - 1));
+
+ return (*j);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ //Check if we have a target
+ if (!UpdateVictim())
{
- DoZoneInCombat();
- }
-
- Unit* SelectRandomNotStomach()
- {
- if (Stomach_Map.empty())
- return nullptr;
-
- std::unordered_map::const_iterator i = Stomach_Map.begin();
-
- std::list temp;
- std::list::const_iterator j;
-
- //Get all players in map
- while (i != Stomach_Map.end())
+ //No target so we'll use this section to do our random wispers instance wide
+ //WisperTimer
+ if (WisperTimer <= diff)
{
- //Check for valid player
- Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
+ Map* map = me->GetMap();
+ if (!map->IsDungeon())
+ return;
- //Only units out of stomach
- if (unit && !i->second)
- temp.push_back(unit);
+ //Play random sound to the zone
+ Map::PlayerList const& PlayerList = map->GetPlayers();
- ++i;
- }
-
- if (temp.empty())
- return nullptr;
-
- j = temp.begin();
-
- //Get random but only if we have more than one unit on threat list
- if (temp.size() > 1)
- advance (j, rand() % (temp.size() - 1));
-
- return (*j);
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- {
- //No target so we'll use this section to do our random wispers instance wide
- //WisperTimer
- if (WisperTimer <= diff)
+ if (!PlayerList.IsEmpty())
{
- Map* map = me->GetMap();
- if (!map->IsDungeon())
- return;
-
- //Play random sound to the zone
- Map::PlayerList const& PlayerList = map->GetPlayers();
-
- if (!PlayerList.IsEmpty())
+ for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
{
- for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
- {
- if (Player* pPlr = itr->GetSource())
- pPlr->PlayDirectSound(RANDOM_SOUND_WHISPER, pPlr);
- }
+ if (Player* pPlr = itr->GetSource())
+ pPlr->PlayDirectSound(RANDOM_SOUND_WHISPER, pPlr);
}
-
- //One random wisper every 90 - 300 seconds
- WisperTimer = urand(90000, 300000);
}
- else WisperTimer -= diff;
- return;
+ //One random wisper every 90 - 300 seconds
+ WisperTimer = urand(90000, 300000);
}
+ else WisperTimer -= diff;
- me->SetTarget();
+ return;
+ }
- uint32 currentPhase = instance->GetData(DATA_CTHUN_PHASE);
- if (currentPhase == PHASE_CTHUN_STOMACH || currentPhase == PHASE_CTHUN_WEAK)
+ me->SetTarget();
+
+ uint32 currentPhase = instance->GetData(DATA_CTHUN_PHASE);
+ if (currentPhase == PHASE_CTHUN_STOMACH || currentPhase == PHASE_CTHUN_WEAK)
+ {
+ // EyeTentacleTimer
+ if (EyeTentacleTimer <= diff)
{
- // EyeTentacleTimer
- if (EyeTentacleTimer <= diff)
+ if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN))
{
- if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN))
- {
- eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES);
- }
-
- EyeTentacleTimer = 30000; // every 30sec in phase 2
+ eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES);
}
- else EyeTentacleTimer -= diff;
- }
- switch (currentPhase)
- {
+ EyeTentacleTimer = 30000; // every 30sec in phase 2
+ }
+ else EyeTentacleTimer -= diff;
+ }
+
+ switch (currentPhase)
+ {
//Transition phase
- case PHASE_CTHUN_TRANSITION:
- //PhaseTimer
- if (PhaseTimer <= diff)
+ case PHASE_CTHUN_TRANSITION:
+ //PhaseTimer
+ if (PhaseTimer <= diff)
+ {
+ //Switch
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
+
+ //Switch to c'thun model
+ me->InterruptNonMeleeSpells(false);
+ DoCast(me, SPELL_TRANSFORM, false);
+ me->SetFullHealth();
+
+ me->SetVisible(true);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+
+ //Emerging phase
+ //AttackStart(ObjectAccessor::GetUnit(*me, HoldpPlayer));
+ DoZoneInCombat();
+
+ //Place all units in threat list on outside of stomach
+ Stomach_Map.clear();
+
+ for (std::list::const_iterator i = me->GetThreatMgr().getThreatList().begin(); i != me->GetThreatMgr().getThreatList().end(); ++i)
+ Stomach_Map[(*i)->getUnitGuid()] = false; //Outside stomach
+
+ //Spawn 2 flesh tentacles
+ FleshTentaclesKilled = 0;
+
+ //Spawn flesh tentacle
+ for (uint8 i = 0; i < 2; i++)
{
- //Switch
- instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
-
- //Switch to c'thun model
- me->InterruptNonMeleeSpells(false);
- DoCast(me, SPELL_TRANSFORM, false);
- me->SetFullHealth();
-
- me->SetVisible(true);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
-
- //Emerging phase
- //AttackStart(ObjectAccessor::GetUnit(*me, HoldpPlayer));
- DoZoneInCombat();
-
- //Place all units in threat list on outside of stomach
- Stomach_Map.clear();
-
- for (std::list::const_iterator i = me->GetThreatMgr().getThreatList().begin(); i != me->GetThreatMgr().getThreatList().end(); ++i)
- Stomach_Map[(*i)->getUnitGuid()] = false; //Outside stomach
-
- //Spawn 2 flesh tentacles
- FleshTentaclesKilled = 0;
-
- //Spawn flesh tentacle
- for (uint8 i = 0; i < 2; i++)
- {
- Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
- if (!spawned)
- ++FleshTentaclesKilled;
- }
-
- PhaseTimer = 0;
+ Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
+ if (!spawned)
+ ++FleshTentaclesKilled;
}
- else PhaseTimer -= diff;
- break;
+ PhaseTimer = 0;
+ }
+ else PhaseTimer -= diff;
+
+ break;
//Body Phase
- case PHASE_CTHUN_STOMACH:
- //Remove Target field
- me->SetTarget();
+ case PHASE_CTHUN_STOMACH:
+ //Remove Target field
+ me->SetTarget();
- //Weaken
- if (FleshTentaclesKilled > 1)
+ //Weaken
+ if (FleshTentaclesKilled > 1)
+ {
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_WEAK);
+
+ Talk(EMOTE_WEAKENED);
+ PhaseTimer = 45000;
+
+ DoCast(me, SPELL_PURPLE_COLORATION, true);
+
+ std::unordered_map::iterator i = Stomach_Map.begin();
+
+ //Kick all players out of stomach
+ while (i != Stomach_Map.end())
{
- instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_WEAK);
+ //Check for valid player
+ Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
- Talk(EMOTE_WEAKENED);
- PhaseTimer = 45000;
-
- DoCast(me, SPELL_PURPLE_COLORATION, true);
-
- std::unordered_map::iterator i = Stomach_Map.begin();
-
- //Kick all players out of stomach
- while (i != Stomach_Map.end())
+ //Only move units in stomach
+ if (unit && i->second)
{
- //Check for valid player
- Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
+ //Teleport each player out
+ DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6));
- //Only move units in stomach
- if (unit && i->second)
+ //Cast knockback on them
+ DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true);
+
+ //Remove the acid debuff
+ unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
+
+ i->second = false;
+ }
+ ++i;
+ }
+
+ return;
+ }
+
+ //Stomach acid
+ if (StomachAcidTimer <= diff)
+ {
+ //Apply aura to all players in stomach
+ std::unordered_map::iterator i = Stomach_Map.begin();
+
+ while (i != Stomach_Map.end())
+ {
+ //Check for valid player
+ Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
+
+ //Only apply to units in stomach
+ if (unit && i->second)
+ {
+ //Cast digestive acid on them
+ DoCast(unit, SPELL_DIGESTIVE_ACID, true);
+
+ //Check if player should be kicked from stomach
+ if (unit->IsWithinDist3d(&KickPos, 15.0f))
{
//Teleport each player out
DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6));
@@ -657,388 +677,321 @@ public:
i->second = false;
}
- ++i;
}
-
- return;
+ ++i;
}
- //Stomach acid
- if (StomachAcidTimer <= diff)
+ StomachAcidTimer = 4000;
+ }
+ else StomachAcidTimer -= diff;
+
+ //Stomach Enter Timer
+ if (StomachEnterTimer <= diff)
+ {
+ if (Unit* target = SelectRandomNotStomach())
{
- //Apply aura to all players in stomach
- std::unordered_map::iterator i = Stomach_Map.begin();
-
- while (i != Stomach_Map.end())
- {
- //Check for valid player
- Unit* unit = ObjectAccessor::GetUnit(*me, i->first);
-
- //Only apply to units in stomach
- if (unit && i->second)
- {
- //Cast digestive acid on them
- DoCast(unit, SPELL_DIGESTIVE_ACID, true);
-
- //Check if player should be kicked from stomach
- if (unit->IsWithinDist3d(&KickPos, 15.0f))
- {
- //Teleport each player out
- DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6));
-
- //Cast knockback on them
- DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true);
-
- //Remove the acid debuff
- unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID);
-
- i->second = false;
- }
- }
- ++i;
- }
-
- StomachAcidTimer = 4000;
+ //Set target in stomach
+ Stomach_Map[target->GetGUID()] = true;
+ target->InterruptNonMeleeSpells(false);
+ target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, nullptr, nullptr, me->GetGUID());
+ StomachEnterTarget = target->GetGUID();
+ StomachEnterVisTimer = 3800;
}
- else StomachAcidTimer -= diff;
- //Stomach Enter Timer
- if (StomachEnterTimer <= diff)
+ StomachEnterTimer = 13800;
+ }
+ else StomachEnterTimer -= diff;
+
+ if (StomachEnterVisTimer && StomachEnterTarget)
+ {
+ if (StomachEnterVisTimer <= diff)
{
- if (Unit* target = SelectRandomNotStomach())
+ //Check for valid player
+ Unit* unit = ObjectAccessor::GetUnit(*me, StomachEnterTarget);
+
+ if (unit)
{
- //Set target in stomach
- Stomach_Map[target->GetGUID()] = true;
- target->InterruptNonMeleeSpells(false);
- target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, nullptr, nullptr, me->GetGUID());
- StomachEnterTarget = target->GetGUID();
- StomachEnterVisTimer = 3800;
+ DoTeleportPlayer(unit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O);
}
- StomachEnterTimer = 13800;
+ StomachEnterTarget.Clear();
+ StomachEnterVisTimer = 0;
}
- else StomachEnterTimer -= diff;
+ else StomachEnterVisTimer -= diff;
+ }
- if (StomachEnterVisTimer && StomachEnterTarget)
+ //GientClawTentacleTimer
+ if (GiantClawTentacleTimer <= diff)
+ {
+ if (Unit* target = SelectRandomNotStomach())
{
- if (StomachEnterVisTimer <= diff)
- {
- //Check for valid player
- Unit* unit = ObjectAccessor::GetUnit(*me, StomachEnterTarget);
-
- if (unit)
- {
- DoTeleportPlayer(unit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O);
- }
-
- StomachEnterTarget.Clear();
- StomachEnterVisTimer = 0;
- }
- else StomachEnterVisTimer -= diff;
+ //Spawn claw tentacle on the random target
+ if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
+ if (spawned->AI())
+ spawned->AI()->AttackStart(target);
}
- //GientClawTentacleTimer
- if (GiantClawTentacleTimer <= diff)
+ //One giant claw tentacle every minute
+ GiantClawTentacleTimer = 60000;
+ }
+ else GiantClawTentacleTimer -= diff;
+
+ //GiantEyeTentacleTimer
+ if (GiantEyeTentacleTimer <= diff)
+ {
+ if (Unit* target = SelectRandomNotStomach())
{
- if (Unit* target = SelectRandomNotStomach())
- {
- //Spawn claw tentacle on the random target
- if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
- if (spawned->AI())
- spawned->AI()->AttackStart(target);
- }
-
- //One giant claw tentacle every minute
- GiantClawTentacleTimer = 60000;
+ //Spawn claw tentacle on the random target
+ if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
+ if (spawned->AI())
+ spawned->AI()->AttackStart(target);
}
- else GiantClawTentacleTimer -= diff;
- //GiantEyeTentacleTimer
- if (GiantEyeTentacleTimer <= diff)
- {
- if (Unit* target = SelectRandomNotStomach())
- {
- //Spawn claw tentacle on the random target
- if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500))
- if (spawned->AI())
- spawned->AI()->AttackStart(target);
- }
+ //One giant eye tentacle every minute
+ GiantEyeTentacleTimer = 60000;
+ }
+ else GiantEyeTentacleTimer -= diff;
- //One giant eye tentacle every minute
- GiantEyeTentacleTimer = 60000;
- }
- else GiantEyeTentacleTimer -= diff;
-
- break;
+ break;
//Weakened state
- case PHASE_CTHUN_WEAK:
- //PhaseTimer
- if (PhaseTimer <= diff)
+ case PHASE_CTHUN_WEAK:
+ //PhaseTimer
+ if (PhaseTimer <= diff)
+ {
+ //Switch
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
+
+ //Remove purple coloration
+ me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION);
+
+ //Spawn 2 flesh tentacles
+ FleshTentaclesKilled = 0;
+
+ //Spawn flesh tentacle
+ for (uint8 i = 0; i < 2; i++)
{
- //Switch
- instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH);
-
- //Remove purple coloration
- me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION);
-
- //Spawn 2 flesh tentacles
- FleshTentaclesKilled = 0;
-
- //Spawn flesh tentacle
- for (uint8 i = 0; i < 2; i++)
- {
- Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
- if (!spawned)
- ++FleshTentaclesKilled;
- }
-
- PhaseTimer = 0;
+ Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN);
+ if (!spawned)
+ ++FleshTentaclesKilled;
}
- else PhaseTimer -= diff;
- break;
- }
+ PhaseTimer = 0;
+ }
+ else PhaseTimer -= diff;
+
+ break;
}
-
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- switch (instance->GetData(DATA_CTHUN_PHASE))
- {
- case PHASE_CTHUN_STOMACH:
- //Not weakened so reduce damage by 99%
- damage /= 100;
- if (damage == 0)
- damage = 1;
-
- //Prevent death in non-weakened state
- if (damage >= me->GetHealth())
- damage = 0;
-
- return;
-
- case PHASE_CTHUN_WEAK:
- //Weakened - takes normal damage
- return;
-
- default:
- damage = 0;
- break;
- }
- }
-
- void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
- {
- if (creature->GetEntry() == NPC_FLESH_TENTACLE)
- {
- ++FleshTentaclesKilled;
- }
- }
- };
-};
-
-class npc_eye_tentacle : public CreatureScript
-{
-public:
- npc_eye_tentacle() : CreatureScript("npc_eye_tentacle") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new eye_tentacleAI(creature);
}
- struct eye_tentacleAI : public ScriptedAI
+ void JustDied(Unit* /*killer*/) override
{
- eye_tentacleAI(Creature* creature) : ScriptedAI(creature)
- {
- if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
- {
- portal->SetReactState(REACT_PASSIVE);
- _portalGUID = portal->GetGUID();
- }
+ instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE);
+ }
- SetCombatMovement(false);
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ switch (instance->GetData(DATA_CTHUN_PHASE))
+ {
+ case PHASE_CTHUN_STOMACH:
+ //Not weakened so reduce damage by 99%
+ damage /= 100;
+ if (damage == 0)
+ damage = 1;
+
+ //Prevent death in non-weakened state
+ if (damage >= me->GetHealth())
+ damage = 0;
+
+ return;
+
+ case PHASE_CTHUN_WEAK:
+ //Weakened - takes normal damage
+ return;
+
+ default:
+ damage = 0;
+ break;
+ }
+ }
+
+ void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
+ {
+ if (creature->GetEntry() == NPC_FLESH_TENTACLE)
+ {
+ ++FleshTentaclesKilled;
+ }
+ }
+};
+
+struct npc_eye_tentacle : public ScriptedAI
+{
+ npc_eye_tentacle(Creature* creature) : ScriptedAI(creature)
+ {
+ if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
+ {
+ portal->SetReactState(REACT_PASSIVE);
+ _portalGUID = portal->GetGUID();
}
- void JustDied(Unit* /*killer*/) override
- {
- if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
- {
- Unit::Kill(p, p);
- }
- }
+ SetCombatMovement(false);
+ }
- void Reset() override
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
- _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
+ Unit::Kill(p, p);
+ }
+ }
+
+ void Reset() override
+ {
+ _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_GROUND_RUPTURE);
- }).Schedule(5min, [this](TaskContext /*task*/)
+ })
+ .Schedule(5min, [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
- }).Schedule(1s, 5s, [this](TaskContext context)
+ })
+ .Schedule(1s, 5s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && u->GetTypeId() == TYPEID_PLAYER && !u->HasAura(SPELL_DIGESTIVE_ACID) && !u->HasAura(SPELL_MIND_FLAY); }))
{
- DoCast(target, SPELL_MIND_FLAY);
+ DoCast(target, SPELL_MIND_FLAY);
}
context.Repeat(10s, 15s);
});
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- return;
-
- _scheduler.Update(diff);
- }
-
- private:
- TaskScheduler _scheduler;
- ObjectGuid _portalGUID;
- };
-};
-
-class npc_claw_tentacle : public CreatureScript
-{
-public:
- npc_claw_tentacle() : CreatureScript("npc_claw_tentacle") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new claw_tentacleAI(creature);
}
- struct claw_tentacleAI : public ScriptedAI
+ void EnterCombat(Unit* /*who*/) override
{
- claw_tentacleAI(Creature* creature) : ScriptedAI(creature)
- {
- SetCombatMovement(false);
+ DoZoneInCombat();
+ }
- if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
- {
- portal->SetReactState(REACT_PASSIVE);
- _portalGUID = portal->GetGUID();
- }
+ void UpdateAI(uint32 diff) override
+ {
+ //Check if we have a target
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff);
+ }
+
+private:
+ TaskScheduler _scheduler;
+ ObjectGuid _portalGUID;
+};
+
+struct npc_claw_tentacle : public ScriptedAI
+{
+ npc_claw_tentacle(Creature* creature) : ScriptedAI(creature)
+ {
+ SetCombatMovement(false);
+
+ if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
+ {
+ portal->SetReactState(REACT_PASSIVE);
+ _portalGUID = portal->GetGUID();
}
+ }
- void JustDied(Unit* /*killer*/) override
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
- if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
- {
- Unit::Kill(p, p);
- }
+ Unit::Kill(p, p);
}
+ }
- void Reset() override
- {
- _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/)
+ void Reset() override
+ {
+ _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_GROUND_RUPTURE);
}).Schedule(Minutes(5), [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
});
- }
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
- _scheduler.Schedule(2s, [this](TaskContext context)
+ _scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(5s);
});
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- return;
-
- _scheduler.Update(diff);
-
- DoMeleeAttackIfReady();
- }
-
- private:
- TaskScheduler _scheduler;
- ObjectGuid _portalGUID;
- };
-};
-
-class npc_giant_claw_tentacle : public CreatureScript
-{
-public:
- npc_giant_claw_tentacle() : CreatureScript("npc_giant_claw_tentacle") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new giant_claw_tentacleAI(creature);
}
- struct giant_claw_tentacleAI : public ScriptedAI
+ void UpdateAI(uint32 diff) override
{
- giant_claw_tentacleAI(Creature* creature) : ScriptedAI(creature)
- {
- SetCombatMovement(false);
+ //Check if we have a target
+ if (!UpdateVictim())
+ return;
- if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
- {
- portal->SetReactState(REACT_PASSIVE);
- _portalGUID = portal->GetGUID();
- }
+ _scheduler.Update(diff);
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ TaskScheduler _scheduler;
+ ObjectGuid _portalGUID;
+};
+
+struct npc_giant_claw_tentacle : public ScriptedAI
+{
+ npc_giant_claw_tentacle(Creature* creature) : ScriptedAI(creature)
+ {
+ SetCombatMovement(false);
+
+ if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
+ {
+ portal->SetReactState(REACT_PASSIVE);
+ _portalGUID = portal->GetGUID();
}
+ }
- void JustDied(Unit* /*killer*/) override
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
- if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
- {
- Unit::Kill(p, p);
- }
+ Unit::Kill(p, p);
}
+ }
- void Reset() override
- {
- _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
+ void Reset() override
+ {
+ _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
});
- }
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
- _scheduler.Schedule(2s, [this](TaskContext context)
+ _scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(10s);
- }).Schedule(5s, [this](TaskContext context) {
+ }).Schedule(5s, [this](TaskContext context)
+ {
DoCastSelf(SPELL_THRASH);
context.Repeat(10s);
});
- }
+ }
- void ScheduleMeleeCheck()
- {
- // Check if a target is in melee range
- _scheduler.Schedule(10s, [this](TaskContext task)
+ void ScheduleMeleeCheck()
+ {
+ // Check if a target is in melee range
+ _scheduler.Schedule(10s, [this](TaskContext task)
{
if (Unit* target = me->GetVictim())
{
@@ -1058,108 +1011,98 @@ public:
task.Repeat();
});
+ }
+
+ void Submerge()
+ {
+ if (me->SelectNearestPlayer(5.0f))
+ {
+ return;
}
- void Submerge()
+ // Despawn portal
+ if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID))
{
- if (me->SelectNearestPlayer(5.0f))
- {
- return;
- }
+ p->DespawnOrUnsummon();
+ }
- // Despawn portal
- if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID))
- {
- p->DespawnOrUnsummon();
- }
+ DoCastSelf(SPELL_SUBMERGE_VISUAL);
+ me->SetHealth(me->GetMaxHealth());
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- DoCastSelf(SPELL_SUBMERGE_VISUAL);
- me->SetHealth(me->GetMaxHealth());
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ _scheduler.CancelAll();
- _scheduler.CancelAll();
-
- _scheduler.Schedule(5s, [this](TaskContext /*task*/)
+ _scheduler.Schedule(5s, [this](TaskContext /*task*/)
{
Emerge();
});
- }
-
- void Emerge()
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector()))
- {
- Position pos = target->GetPosition();
- me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0);
- if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN))
- {
- portal->SetReactState(REACT_PASSIVE);
- _portalGUID = portal->GetGUID();
- }
-
- me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL);
- DoCastSelf(SPELL_BIRTH);
- DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
-
- ScheduleMeleeCheck();
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- return;
-
- _scheduler.Update(diff);
-
- DoMeleeAttackIfReady();
- }
-
- private:
- TaskScheduler _scheduler;
- ObjectGuid _portalGUID;
- };
-};
-
-class npc_giant_eye_tentacle : public CreatureScript
-{
-public:
- npc_giant_eye_tentacle() : CreatureScript("npc_giant_eye_tentacle") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new giant_eye_tentacleAI(creature);
}
- struct giant_eye_tentacleAI : public ScriptedAI
+ void Emerge()
{
- giant_eye_tentacleAI(Creature* creature) : ScriptedAI(creature)
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector()))
{
- SetCombatMovement(false);
-
- if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
+ Position pos = target->GetPosition();
+ me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0);
+ if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN))
{
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
- }
- void JustDied(Unit* /*killer*/) override
- {
- if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
- {
- Unit::Kill(p, p);
- }
- }
+ me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL);
+ DoCastSelf(SPELL_BIRTH);
+ DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- void Reset() override
+ ScheduleMeleeCheck();
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ //Check if we have a target
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff);
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ TaskScheduler _scheduler;
+ ObjectGuid _portalGUID;
+};
+
+struct npc_giant_eye_tentacle : public ScriptedAI
+{
+ npc_giant_eye_tentacle(Creature* creature) : ScriptedAI(creature)
+ {
+ SetCombatMovement(false);
+
+ if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
- _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
+ portal->SetReactState(REACT_PASSIVE);
+ _portalGUID = portal->GetGUID();
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
+ {
+ Unit::Kill(p, p);
+ }
+ }
+
+ void Reset() override
+ {
+ _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
- }).Schedule(1s, 5s, [this](TaskContext context) {
+ }).Schedule(1s, 5s, [this](TaskContext context)
+ {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
DoCast(target, SPELL_GREEN_BEAM);
@@ -1167,36 +1110,33 @@ public:
context.Repeat(2100ms);
});
- }
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- DoZoneInCombat();
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ }
- void UpdateAI(uint32 diff) override
- {
- //Check if we have a target
- if (!UpdateVictim())
- return;
+ void UpdateAI(uint32 diff) override
+ {
+ //Check if we have a target
+ if (!UpdateVictim())
+ return;
- _scheduler.Update(diff);
- }
+ _scheduler.Update(diff);
+ }
- private:
- TaskScheduler _scheduler;
- ObjectGuid _portalGUID;
- };
+private:
+ TaskScheduler _scheduler;
+ ObjectGuid _portalGUID;
};
-//GetAIs
-
void AddSC_boss_cthun()
{
- new boss_eye_of_cthun();
- new boss_cthun();
- new npc_eye_tentacle();
- new npc_claw_tentacle();
- new npc_giant_claw_tentacle();
- new npc_giant_eye_tentacle();
+ RegisterTempleOfAhnQirajCreatureAI(boss_eye_of_cthun);
+ RegisterTempleOfAhnQirajCreatureAI(boss_cthun);
+ RegisterTempleOfAhnQirajCreatureAI(npc_eye_tentacle);
+ RegisterTempleOfAhnQirajCreatureAI(npc_claw_tentacle);
+ RegisterTempleOfAhnQirajCreatureAI(npc_giant_claw_tentacle);
+ RegisterTempleOfAhnQirajCreatureAI(npc_giant_eye_tentacle);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp
index fdd08243b..d0ca30daa 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp
@@ -15,154 +15,118 @@
* with this program. If not, see .
*/
-/* ScriptData
-SDName: Boss_Fankriss
-SD%Complete: 100
-SDComment: sound not implemented
-SDCategory: Temple of Ahn'Qiraj
-EndScriptData */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h"
-#define SOUND_SENTENCE_YOU 8588
-#define SOUND_SERVE_TO 8589
-#define SOUND_LAWS 8590
-#define SOUND_TRESPASS 8591
-#define SOUND_WILL_BE 8592
-
enum Spells
{
SPELL_MORTAL_WOUND = 25646,
- SPELL_ROOT = 28858,
+ SPELL_ENTANGLE_RIGHT = 720,
+ SPELL_ENTANGLE_CENTER = 731,
+ SPELL_ENTANGLE_LEFT = 1121,
- // Enrage for his spawns
- SPELL_ENRAGE = 28798
+ SPELL_SUMMON_WORM_1 = 518,
+ SPELL_SUMMON_WORM_2 = 25831,
+ SPELL_SUMMON_WORM_3 = 25832
};
-class boss_fankriss : public CreatureScript
+enum Misc
{
-public:
- boss_fankriss() : CreatureScript("boss_fankriss") { }
+ MAX_HATCHLING_SPAWN = 4,
+ NPC_VEKNISS_HATCHLING = 15962
+};
- CreatureAI* GetAI(Creature* creature) const override
+const std::array hatchlingsSpawnPoints
+{
{
- return GetTempleOfAhnQirajAI(creature);
+ { -8043.6f, 1254.1f, -84.3f }, // Right
+ { -8003.0f, 1222.9f, -82.1f }, // Center
+ { -8022.3f, 1149.0f, -89.1f } // Left
+ }
+};
+
+const std::array entangleSpells = { SPELL_ENTANGLE_RIGHT, SPELL_ENTANGLE_CENTER, SPELL_ENTANGLE_LEFT };
+
+struct boss_fankriss : public BossAI
+{
+ boss_fankriss(Creature* creature) : BossAI(creature, DATA_FANKRISS) { }
+
+ void Reset() override
+ {
+ _scheduler.CancelAll();
+ summonWormSpells = { SPELL_SUMMON_WORM_1, SPELL_SUMMON_WORM_2, SPELL_SUMMON_WORM_3};
+
+ BossAI::Reset();
}
- struct boss_fankrissAI : public ScriptedAI
+ void SummonWorms()
{
- boss_fankrissAI(Creature* creature) : ScriptedAI(creature) { }
+ uint32 amount = urand(1, 3);
+ Acore::Containers::RandomResize(summonWormSpells, amount);
+ for (uint32 summonSpell : summonWormSpells)
+ DoCastAOE(summonSpell, true);
+ summonWormSpells = { SPELL_SUMMON_WORM_1, SPELL_SUMMON_WORM_2, SPELL_SUMMON_WORM_3 };
+ }
- void SummonSpawn()
+ void SummonHatchlingWaves()
+ {
+ for (Position spawnPos : hatchlingsSpawnPoints)
{
- Rand = 10 + (rand() % 10);
- switch (rand() % 2)
+ for (uint8 i = 0; i < MAX_HATCHLING_SPAWN; i++)
{
- case 0:
- RandX = 0.0f - Rand;
- break;
- case 1:
- RandX = 0.0f + Rand;
- break;
+ Position randSpawn = me->GetRandomPoint(spawnPos, 10.f);
+ me->SummonCreature(NPC_VEKNISS_HATCHLING, randSpawn, TEMPSUMMON_CORPSE_DESPAWN);
}
-
- Rand = 10 + (rand() % 10);
- switch (rand() % 2)
- {
- case 0:
- RandY = 0.0f - Rand;
- break;
- case 1:
- RandY = 0.0f + Rand;
- break;
- }
- Rand = 0;
- DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
}
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- _scheduler.CancelAll();
+ void EnterCombat(Unit* who) override
+ {
+ _scheduler.CancelAll();
+ BossAI::EnterCombat(who);
- _scheduler.Schedule(4s, 8s, [this](TaskContext context) {
+ _scheduler
+ .Schedule(7s, 14s, [this](TaskContext context)
+ {
DoCastVictim(SPELL_MORTAL_WOUND);
context.Repeat();
- }).Schedule(15s, 45s, [this](TaskContext context) {
- switch (urand(0, 2))
+ })
+ .Schedule(30s, 50s, [this](TaskContext context)
+ {
+ SummonWorms();
+ context.Repeat(22s, 70s);
+ })
+ .Schedule(15s, 20s, [this](TaskContext context)
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true))
{
- case 0:
- SummonSpawn();
- break;
- case 1:
- SummonSpawn();
- SummonSpawn();
- break;
- case 2:
- SummonSpawn();
- SummonSpawn();
- SummonSpawn();
- break;
+ uint32 spellId = Acore::Containers::SelectRandomContainerElement(entangleSpells);
+ DoCast(target, spellId);
}
- context.Repeat(30s, 60s);
- }).Schedule(15s, 45s, [this](TaskContext context) {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
- {
- DoCast(target, SPELL_ROOT);
- if (DoGetThreat(target))
- DoModifyThreatPercent(target, -100);
-
- switch (urand(0, 2))
- {
- case 0:
- DoTeleportPlayer(target, -8106.0142f, 1289.2900f, -74.419533f, 5.112f);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- break;
- case 1:
- DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- break;
- case 2:
- DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
- break;
- }
- }
- context.Repeat(45s, 60s);
+ SummonHatchlingWaves();
+ context.Repeat(25s, 55s);
});
- }
+ }
- void UpdateAI(uint32 diff) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ void UpdateAI(uint32 diff) override
+ {
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
- _scheduler.Update(diff,
- std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
- }
+ _scheduler.Update(diff,
+ std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
+ }
- private:
- TaskScheduler _scheduler;
- int Rand;
- float RandX;
- float RandY;
- };
+private:
+ TaskScheduler _scheduler;
+ std::vector summonWormSpells;
};
void AddSC_boss_fankriss()
{
- new boss_fankriss();
+ RegisterTempleOfAhnQirajCreatureAI(boss_fankriss);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp
index bdd58744e..5a2d7255b 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp
@@ -41,115 +41,104 @@ enum Huhuran
SPELL_WYVERN_STING_DAMAGE = 26233
};
-class boss_huhuran : public CreatureScript
+struct boss_huhuran : public ScriptedAI
{
-public:
- boss_huhuran() : CreatureScript("boss_huhuran") { }
+ boss_huhuran(Creature* creature) : ScriptedAI(creature) { }
- CreatureAI* GetAI(Creature* creature) const override
+ uint32 Frenzy_Timer;
+ uint32 Wyvern_Timer;
+ uint32 Spit_Timer;
+ uint32 PoisonBolt_Timer;
+ uint32 NoxiousPoison_Timer;
+ uint32 FrenzyBack_Timer;
+
+ bool Frenzy;
+ bool Berserk;
+
+ void Reset() override
{
- return GetTempleOfAhnQirajAI(creature);
+ Frenzy_Timer = urand(25000, 35000);
+ Wyvern_Timer = urand(18000, 28000);
+ Spit_Timer = 8000;
+ PoisonBolt_Timer = 4000;
+ NoxiousPoison_Timer = urand(10000, 20000);
+ FrenzyBack_Timer = 15000;
+
+ Frenzy = false;
+ Berserk = false;
}
- struct boss_huhuranAI : public ScriptedAI
+ void UpdateAI(uint32 diff) override
{
- boss_huhuranAI(Creature* creature) : ScriptedAI(creature) { }
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
- uint32 Frenzy_Timer;
- uint32 Wyvern_Timer;
- uint32 Spit_Timer;
- uint32 PoisonBolt_Timer;
- uint32 NoxiousPoison_Timer;
- uint32 FrenzyBack_Timer;
-
- bool Frenzy;
- bool Berserk;
-
- void Reset() override
+ //Frenzy_Timer
+ if (!Frenzy && Frenzy_Timer <= diff)
{
+ DoCast(me, SPELL_FRENZY);
+ Talk(EMOTE_FRENZY_KILL);
+ Frenzy = true;
+ PoisonBolt_Timer = 3000;
Frenzy_Timer = urand(25000, 35000);
- Wyvern_Timer = urand(18000, 28000);
- Spit_Timer = 8000;
- PoisonBolt_Timer = 4000;
- NoxiousPoison_Timer = urand(10000, 20000);
- FrenzyBack_Timer = 15000;
-
- Frenzy = false;
- Berserk = false;
}
+ else Frenzy_Timer -= diff;
- void UpdateAI(uint32 diff) override
+ // Wyvern Timer
+ if (Wyvern_Timer <= diff)
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- //Frenzy_Timer
- if (!Frenzy && Frenzy_Timer <= diff)
- {
- DoCast(me, SPELL_FRENZY);
- Talk(EMOTE_FRENZY_KILL);
- Frenzy = true;
- PoisonBolt_Timer = 3000;
- Frenzy_Timer = urand(25000, 35000);
- }
- else Frenzy_Timer -= diff;
-
- // Wyvern Timer
- if (Wyvern_Timer <= diff)
- {
- DoCastAOE(SPELL_WYVERNSTING);
- Wyvern_Timer = urand(15000, 32000);
- }
- else Wyvern_Timer -= diff;
-
- //Spit Timer
- if (Spit_Timer <= diff)
- {
- DoCastVictim(SPELL_ACIDSPIT);
- Spit_Timer = urand(5000, 10000);
- }
- else Spit_Timer -= diff;
-
- //NoxiousPoison_Timer
- if (NoxiousPoison_Timer <= diff)
- {
- DoCastVictim(SPELL_NOXIOUSPOISON);
- NoxiousPoison_Timer = urand(12000, 24000);
- }
- else NoxiousPoison_Timer -= diff;
-
- //PoisonBolt only if frenzy or berserk
- if (Frenzy || Berserk)
- {
- if (PoisonBolt_Timer <= diff)
- {
- DoCastVictim(SPELL_POISONBOLT);
- PoisonBolt_Timer = 3000;
- }
- else PoisonBolt_Timer -= diff;
- }
-
- //FrenzyBack_Timer
- if (Frenzy && FrenzyBack_Timer <= diff)
- {
- me->InterruptNonMeleeSpells(false);
- Frenzy = false;
- FrenzyBack_Timer = 15000;
- }
- else FrenzyBack_Timer -= diff;
-
- if (!Berserk && HealthBelowPct(31))
- {
- me->InterruptNonMeleeSpells(false);
- Talk(EMOTE_BERSERK);
- DoCast(me, SPELL_BERSERK);
- Berserk = true;
- }
-
- DoMeleeAttackIfReady();
+ DoCastAOE(SPELL_WYVERNSTING);
+ Wyvern_Timer = urand(15000, 32000);
}
- };
+ else Wyvern_Timer -= diff;
+
+ //Spit Timer
+ if (Spit_Timer <= diff)
+ {
+ DoCastVictim(SPELL_ACIDSPIT);
+ Spit_Timer = urand(5000, 10000);
+ }
+ else Spit_Timer -= diff;
+
+ //NoxiousPoison_Timer
+ if (NoxiousPoison_Timer <= diff)
+ {
+ DoCastVictim(SPELL_NOXIOUSPOISON);
+ NoxiousPoison_Timer = urand(12000, 24000);
+ }
+ else NoxiousPoison_Timer -= diff;
+
+ //PoisonBolt only if frenzy or berserk
+ if (Frenzy || Berserk)
+ {
+ if (PoisonBolt_Timer <= diff)
+ {
+ DoCastVictim(SPELL_POISONBOLT);
+ PoisonBolt_Timer = 3000;
+ }
+ else PoisonBolt_Timer -= diff;
+ }
+
+ //FrenzyBack_Timer
+ if (Frenzy && FrenzyBack_Timer <= diff)
+ {
+ me->InterruptNonMeleeSpells(false);
+ Frenzy = false;
+ FrenzyBack_Timer = 15000;
+ }
+ else FrenzyBack_Timer -= diff;
+
+ if (!Berserk && HealthBelowPct(31))
+ {
+ me->InterruptNonMeleeSpells(false);
+ Talk(EMOTE_BERSERK);
+ DoCast(me, SPELL_BERSERK);
+ Berserk = true;
+ }
+
+ DoMeleeAttackIfReady();
+ }
};
// 26180 - Wyvern Sting
@@ -173,6 +162,6 @@ class spell_huhuran_wyvern_sting : public AuraScript
void AddSC_boss_huhuran()
{
- new boss_huhuran();
+ RegisterTempleOfAhnQirajCreatureAI(boss_huhuran);
RegisterSpellScript(spell_huhuran_wyvern_sting);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp
index 0969f3e53..974620cb8 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp
@@ -15,188 +15,360 @@
* with this program. If not, see .
*/
-/* ScriptData
-SDName: Boss_Ouro
-SD%Complete: 85
-SDComment: No model for submerging. Currently just invisible.
-SDCategory: Temple of Ahn'Qiraj
-EndScriptData */
-
+#include "Cell.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h"
enum Spells
{
+ // Ouro
SPELL_SWEEP = 26103,
- SPELL_SANDBLAST = 26102,
+ SPELL_SAND_BLAST = 26102,
SPELL_GROUND_RUPTURE = 26100,
- SPELL_BIRTH = 26262, // The Birth Animation
+ SPELL_BERSERK = 26615,
+ SPELL_BOULDER = 26616,
+ SPELL_OURO_SUBMERGE_VISUAL = 26063,
+ SPELL_SUMMON_SANDWORM_BASE = 26133,
+
+ // Misc - Mounds, Ouro Spawner
+ SPELL_BIRTH = 26586,
SPELL_DIRTMOUND_PASSIVE = 26092,
- SPELL_SUMMON_OURO = 26061
+ SPELL_SUMMON_OURO = 26061,
+ SPELL_SUMMON_OURO_MOUNDS = 26058,
+ SPELL_QUAKE = 26093,
+ SPELL_SUMMON_SCARABS = 26060,
+ SPELL_SUMMON_OURO_AURA = 26642,
+ SPELL_DREAM_FOG = 24780
};
-class npc_ouro_spawner : public CreatureScript
+enum Misc
{
-public:
- npc_ouro_spawner() : CreatureScript("npc_ouro_spawner") {}
+ GROUP_EMERGED = 0,
+ GROUP_PHASE_TRANSITION = 1,
- CreatureAI* GetAI(Creature* creature) const
- {
- return new npc_ouro_spawnerAI(creature);
- }
+ NPC_DIRT_MOUND = 15712,
+ GO_SANDWORM_BASE = 180795,
- struct npc_ouro_spawnerAI : public ScriptedAI
- {
- npc_ouro_spawnerAI(Creature* creature) : ScriptedAI(creature)
- {
- Reset();
- }
-
- bool hasSummoned;
-
- void Reset() override
- {
- hasSummoned = false;
- DoCast(me, SPELL_DIRTMOUND_PASSIVE);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- // Spawn Ouro on LoS check
- if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f))
- {
- DoCast(me, SPELL_SUMMON_OURO);
- hasSummoned = true;
- }
-
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void JustSummoned(Creature* creature) override
- {
- // Despawn when Ouro is spawned
- if (creature->GetEntry() == NPC_OURO)
- {
- creature->SetInCombatWithZone();
- creature->CastSpell(creature, SPELL_BIRTH, false);
- me->DespawnOrUnsummon();
- }
- }
-
- };
+ DATA_OURO_HEALTH = 0
};
-class boss_ouro : public CreatureScript
+struct npc_ouro_spawner : public ScriptedAI
{
-public:
- boss_ouro() : CreatureScript("boss_ouro") { }
-
- CreatureAI* GetAI(Creature* creature) const override
+ npc_ouro_spawner(Creature* creature) : ScriptedAI(creature)
{
- return GetTempleOfAhnQirajAI(creature);
+ Reset();
}
- struct boss_ouroAI : public ScriptedAI
+ bool hasSummoned;
+
+ void Reset() override
{
- boss_ouroAI(Creature* creature) : ScriptedAI(creature) { }
+ hasSummoned = false;
+ DoCastSelf(SPELL_DIRTMOUND_PASSIVE);
+ }
- uint32 Sweep_Timer;
- uint32 SandBlast_Timer;
- uint32 Submerge_Timer;
- uint32 Back_Timer;
- uint32 ChangeTarget_Timer;
- uint32 Spawn_Timer;
-
- bool Enrage;
- bool Submerged;
-
- void Reset() override
+ void MoveInLineOfSight(Unit* who) override
+ {
+ // Spawn Ouro on LoS check
+ if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f) && !who->ToPlayer()->IsGameMaster())
{
- Sweep_Timer = urand(5000, 10000);
- SandBlast_Timer = urand(20000, 35000);
- Submerge_Timer = urand(90000, 150000);
- Back_Timer = urand(30000, 45000);
- ChangeTarget_Timer = urand(5000, 8000);
- Spawn_Timer = urand(10000, 20000);
-
- Enrage = false;
- Submerged = false;
+ DoCastSelf(SPELL_SUMMON_OURO);
+ hasSummoned = true;
}
- void EnterCombat(Unit* /*who*/) override
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ void JustSummoned(Creature* creature) override
+ {
+ // Despawn when Ouro is spawned
+ if (creature->GetEntry() == NPC_OURO)
{
- DoCastVictim(SPELL_BIRTH);
+ creature->SetInCombatWithZone();
+ me->DespawnOrUnsummon();
+ }
+ }
+};
+
+struct boss_ouro : public BossAI
+{
+ boss_ouro(Creature* creature) : BossAI(creature, DATA_OURO)
+ {
+ SetCombatMovement(false);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ _scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); });
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (me->HealthBelowPctDamaged(20, damage) && !_enraged)
+ {
+ DoCastSelf(SPELL_BERSERK, true);
+ _enraged = true;
+ _scheduler.CancelGroup(GROUP_PHASE_TRANSITION);
+ _scheduler.Schedule(1s, [this](TaskContext context)
+ {
+ if (!IsPlayerWithinMeleeRange())
+ DoSpellAttackToRandomTargetIfReady(SPELL_BOULDER);
+
+ context.Repeat();
+ })
+ .Schedule(20s, [this](TaskContext context)
+ {
+ DoCastSelf(SPELL_SUMMON_OURO_MOUNDS, true);
+ context.Repeat();
+ });
+ }
+ }
+
+ void Submerge()
+ {
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ _submergeMelee = 0;
+ _submerged = true;
+ DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL);
+ _scheduler.CancelGroup(GROUP_EMERGED);
+ _scheduler.CancelGroup(GROUP_PHASE_TRANSITION);
+
+ if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 10.f))
+ {
+ base->Use(me);
+ base->DespawnOrUnsummon(6s);
}
- void UpdateAI(uint32 diff) override
+ DoCastSelf(SPELL_SUMMON_OURO_MOUNDS, true);
+ // According to sniffs, Ouro uses his mounds to respawn. The health management could be a little scuffed.
+ std::list ouroMounds;
+ me->GetCreatureListWithEntryInGrid(ouroMounds, NPC_DIRT_MOUND, 200.f);
+ if (!ouroMounds.empty()) // This can't be possible, but just to be sure.
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- //Sweep_Timer
- if (!Submerged && Sweep_Timer <= diff)
+ if (Creature* mound = Acore::Containers::SelectRandomContainerElement(ouroMounds))
{
- DoCastVictim(SPELL_SWEEP);
- Sweep_Timer = urand(15000, 30000);
+ mound->AddAura(SPELL_SUMMON_OURO_AURA, mound);
+ mound->AI()->SetData(DATA_OURO_HEALTH, me->GetHealth());
}
- else Sweep_Timer -= diff;
-
- //SandBlast_Timer
- if (!Submerged && SandBlast_Timer <= diff)
- {
- DoCastVictim(SPELL_SANDBLAST);
- SandBlast_Timer = urand(20000, 35000);
- }
- else SandBlast_Timer -= diff;
-
- //Submerge_Timer
- if (!Submerged && Submerge_Timer <= diff)
- {
- //Cast
- me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetFaction(FACTION_FRIENDLY);
- DoCast(me, SPELL_DIRTMOUND_PASSIVE);
-
- Submerged = true;
- Back_Timer = urand(30000, 45000);
- }
- else Submerge_Timer -= diff;
-
- //ChangeTarget_Timer
- if (Submerged && ChangeTarget_Timer <= diff)
- {
- Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
-
- if (target)
- me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
-
- ChangeTarget_Timer = urand(10000, 20000);
- }
- else ChangeTarget_Timer -= diff;
-
- //Back_Timer
- if (Submerged && Back_Timer <= diff)
- {
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetFaction(FACTION_MONSTER);
-
- DoCastVictim(SPELL_GROUND_RUPTURE);
-
- Submerged = false;
- Submerge_Timer = urand(60000, 120000);
- }
- else Back_Timer -= diff;
-
- DoMeleeAttackIfReady();
}
- };
+
+ me->DespawnOrUnsummon(1000);
+ }
+
+ void CastGroundRupture()
+ {
+ std::list targets;
+ Acore::AllWorldObjectsInRange checker(me, 10.0f);
+ Acore::WorldObjectListSearcher searcher(me, targets, checker);
+ Cell::VisitAllObjects(me, searcher, 10.0f);
+
+ for (WorldObject* target : targets)
+ {
+ if (Unit* unitTarget = target->ToUnit())
+ {
+ if (unitTarget->IsHostileTo(me))
+ DoCast(unitTarget, SPELL_GROUND_RUPTURE, true);
+ }
+ }
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_SAND_BLAST && target)
+ me->GetThreatMgr().modifyThreatPercent(target, 100);
+ }
+
+ void Emerge()
+ {
+ DoCastSelf(SPELL_BIRTH);
+ DoCastSelf(SPELL_SUMMON_SANDWORM_BASE, true);
+ me->SetReactState(REACT_AGGRESSIVE);
+ CastGroundRupture();
+ _scheduler
+ .Schedule(20s, GROUP_EMERGED, [this](TaskContext context)
+ {
+ DoCastVictim(SPELL_SAND_BLAST);
+ context.Repeat();
+ })
+ .Schedule(22s, GROUP_EMERGED, [this](TaskContext context)
+ {
+ DoCastVictim(SPELL_SWEEP);
+ context.Repeat();
+ })
+ .Schedule(90s, GROUP_PHASE_TRANSITION, [this](TaskContext /*context*/)
+ {
+ Submerge();
+ })
+ .Schedule(3s, GROUP_PHASE_TRANSITION, [this](TaskContext context)
+ {
+ if (!IsPlayerWithinMeleeRange() && !_submerged)
+ {
+ if (_submergeMelee < 10)
+ {
+ _submergeMelee++;
+ }
+ else
+ {
+ if (!_enraged)
+ Submerge();
+ _submergeMelee = 0;
+ }
+ }
+ else
+ {
+ _submergeMelee = 0;
+ }
+
+ if (!_submerged)
+ context.Repeat(1s);
+ });
+ }
+
+ void Reset() override
+ {
+ instance->SetBossState(DATA_OURO, NOT_STARTED);
+ _scheduler.CancelAll();
+ _submergeMelee = 0;
+ _submerged = false;
+ _enraged = false;
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL);
+ me->DespawnOrUnsummon(1000);
+ // Remove after the header file is sorted with the bosses first.
+ if (Creature* ouroSpawner = instance->GetCreature(DATA_OURO_SPAWNER))
+ ouroSpawner->Respawn();
+ instance->SetBossState(DATA_OURO, FAIL);
+ if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f))
+ base->DespawnOrUnsummon();
+ }
+
+ void EnterCombat(Unit* who) override
+ {
+ Emerge();
+
+ BossAI::EnterCombat(who);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, [this]
+ {
+ DoMeleeAttackIfReady();
+ });
+ }
+
+protected:
+ TaskScheduler _scheduler;
+ bool _enraged;
+ uint8 _submergeMelee;
+ bool _submerged;
+
+ bool IsPlayerWithinMeleeRange() const
+ {
+ return me->IsWithinMeleeRange(me->GetVictim());
+ }
+};
+
+struct npc_dirt_mound : ScriptedAI
+{
+ npc_dirt_mound(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = creature->GetInstanceScript();
+ }
+
+ void JustSummoned(Creature* creature) override
+ {
+ if (creature->GetEntry() == NPC_OURO)
+ {
+ creature->SetInCombatWithZone();
+ creature->SetHealth(_ouroHealth);
+ }
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ if (type == DATA_OURO_HEALTH)
+ _ouroHealth = data;
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ DoZoneInCombat();
+ _scheduler.Schedule(30s, [this](TaskContext /*context*/)
+ {
+ DoCastSelf(SPELL_SUMMON_SCARABS, true);
+ me->DespawnOrUnsummon(1000);
+ })
+ .Schedule(100ms, [this](TaskContext context)
+ {
+ ChaseNewTarget();
+ context.Repeat(5s, 10s);
+ });
+ }
+
+ void ChaseNewTarget()
+ {
+ DoResetThreat();
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200.f, true))
+ {
+ me->AddThreat(target, 1000000.f);
+ AttackStart(target);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff);
+ }
+
+ void Reset() override
+ {
+ DoCastSelf(SPELL_DIRTMOUND_PASSIVE, true);
+ DoCastSelf(SPELL_DREAM_FOG, true);
+ DoCastSelf(SPELL_QUAKE, true);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ if (_instance)
+ {
+ _instance->SetBossState(DATA_OURO, FAIL);
+
+ // Remove after the header file is sorted with the bosses first.
+ if (Creature* ouroSpawner = _instance->GetCreature(DATA_OURO_SPAWNER))
+ ouroSpawner->Respawn();
+ }
+
+ if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f))
+ base->DespawnOrUnsummon();
+
+ me->DespawnOrUnsummon();
+ }
+
+protected:
+ TaskScheduler _scheduler;
+ uint32 _ouroHealth;
+ InstanceScript* _instance;
};
void AddSC_boss_ouro()
{
- new npc_ouro_spawner();
- new boss_ouro();
+ RegisterTempleOfAhnQirajCreatureAI(npc_ouro_spawner);
+ RegisterTempleOfAhnQirajCreatureAI(boss_ouro);
+ RegisterTempleOfAhnQirajCreatureAI(npc_dirt_mound);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp
index f851d2b5c..789fe5bcf 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp
@@ -15,301 +15,314 @@
* with this program. If not, see .
*/
-/* ScriptData
-SDName: Boss_Sartura
-SD%Complete: 95
-SDComment:
-SDCategory: Temple of Ahn'Qiraj
-EndScriptData */
-
#include "ScriptMgr.h"
+#include "SpellScript.h"
#include "ScriptedCreature.h"
#include "temple_of_ahnqiraj.h"
-enum Sartura
+enum Says
{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_DEATH = 2,
-
- SPELL_WHIRLWIND = 26083,
- SPELL_ENRAGE = 8269,
- SPELL_BERSERK = 27680,
-
- //Guard Spell
- SPELL_WHIRLWINDADD = 26038,
- SPELL_KNOCKBACK = 26027
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_DEATH = 2
};
-class boss_sartura : public CreatureScript
+enum Spells
{
-public:
- boss_sartura() : CreatureScript("boss_sartura") { }
+ // Battleguard Sartura
+ SPELL_WHIRLWIND = 26083, // MechanicImmunity->Stunned (15sec)
+ SPELL_ENRAGE = 8269,
+ SPELL_BERSERK = 27680,
+ SPELL_SUNDERING_CLEAVE = 25174,
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetTempleOfAhnQirajAI(creature);
- }
-
- struct boss_sarturaAI : public ScriptedAI
- {
- boss_sarturaAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 WhirlWind_Timer;
- uint32 WhirlWindRandom_Timer;
- uint32 WhirlWindEnd_Timer;
- uint32 AggroReset_Timer;
- uint32 AggroResetEnd_Timer;
- uint32 EnrageHard_Timer;
-
- bool Enraged;
- bool EnragedHard;
- bool WhirlWind;
- bool AggroReset;
-
- void Reset() override
- {
- WhirlWind_Timer = 30000;
- WhirlWindRandom_Timer = urand(3000, 7000);
- WhirlWindEnd_Timer = 15000;
- AggroReset_Timer = urand(45000, 55000);
- AggroResetEnd_Timer = 5000;
- EnrageHard_Timer = 10 * 60000;
-
- WhirlWind = false;
- AggroReset = false;
- Enraged = false;
- EnragedHard = false;
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
- }
-
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_SLAY);
- }
-
- void UpdateAI(uint32 diff) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (WhirlWind)
- {
- if (WhirlWindRandom_Timer <= diff)
- {
- //Attack random Gamers
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
- {
- me->AddThreat(target, 1.0f);
- me->TauntApply(target);
- AttackStart(target);
- }
- WhirlWindRandom_Timer = urand(3000, 7000);
- }
- else WhirlWindRandom_Timer -= diff;
-
- if (WhirlWindEnd_Timer <= diff)
- {
- WhirlWind = false;
- WhirlWind_Timer = urand(25000, 40000);
- }
- else WhirlWindEnd_Timer -= diff;
- }
-
- if (!WhirlWind)
- {
- if (WhirlWind_Timer <= diff)
- {
- DoCast(me, SPELL_WHIRLWIND);
- WhirlWind = true;
- WhirlWindEnd_Timer = 15000;
- }
- else WhirlWind_Timer -= diff;
-
- if (AggroReset_Timer <= diff)
- {
- //Attack random Gamers
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
- {
- me->AddThreat(target, 1.0f);
- me->TauntApply(target);
- AttackStart(target);
- }
- AggroReset = true;
- AggroReset_Timer = urand(2000, 5000);
- }
- else AggroReset_Timer -= diff;
-
- if (AggroReset)
- {
- if (AggroResetEnd_Timer <= diff)
- {
- AggroReset = false;
- AggroResetEnd_Timer = 5000;
- AggroReset_Timer = urand(35000, 45000);
- }
- else AggroResetEnd_Timer -= diff;
- }
-
- //If she is 20% enrage
- if (!Enraged)
- {
- if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false))
- {
- DoCast(me, SPELL_ENRAGE, true);
- Enraged = true;
- }
- }
-
- //After 10 minutes hard enrage
- if (!EnragedHard)
- {
- if (EnrageHard_Timer <= diff)
- {
- DoCast(me, SPELL_BERSERK, true);
- EnragedHard = true;
- }
- else EnrageHard_Timer -= diff;
- }
-
- DoMeleeAttackIfReady();
- }
- }
- };
+ // Sartura's Royal Guard
+ SPELL_GUARD_WHIRLWIND = 26038,
+ SPELL_GUARD_KNOCKBACK = 26027
};
-class npc_sartura_royal_guard : public CreatureScript
+enum events
{
-public:
- npc_sartura_royal_guard() : CreatureScript("npc_sartura_royal_guard") { }
+ // Battleguard Sartura
+ EVENT_SARTURA_WHIRLWIND = 1,
+ EVENT_SARTURA_WHIRLWIND_RANDOM = 2,
+ EVENT_SARTURA_WHIRLWIND_END = 3,
+ EVENT_SPELL_BERSERK = 4,
+ EVENT_SARTURA_AGGRO_RESET = 5,
+ EVENT_SARTURA_AGGRO_RESET_END = 6,
- CreatureAI* GetAI(Creature* creature) const override
+ // Sartura's Royal Guard
+ EVENT_GUARD_WHIRLWIND = 7,
+ EVENT_GUARD_WHIRLWIND_RANDOM = 8,
+ EVENT_GUARD_WHIRLWIND_END = 9,
+ EVENT_GUARD_KNOCKBACK = 10,
+ EVENT_GUARD_AGGRO_RESET = 11,
+ EVENT_GUARD_AGGRO_RESET_END = 12
+};
+
+struct boss_sartura : public BossAI
+{
+ boss_sartura(Creature* creature) : BossAI(creature, DATA_SARTURA) {}
+
+ void Reset() override
{
- return GetTempleOfAhnQirajAI(creature);
+ _Reset();
+ whirlwind = false;
+ enraged = false;
+ berserked = false;
+ aggroReset = false;
+ MinionReset();
+ _savedTargetGUID.Clear();
+ _savedTargetThreat = 0.f;
}
- struct npc_sartura_royal_guardAI : public ScriptedAI
+ void MinionReset()
{
- npc_sartura_royal_guardAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 WhirlWind_Timer;
- uint32 WhirlWindRandom_Timer;
- uint32 WhirlWindEnd_Timer;
- uint32 AggroReset_Timer;
- uint32 AggroResetEnd_Timer;
- uint32 KnockBack_Timer;
-
- bool WhirlWind;
- bool AggroReset;
-
- void Reset() override
+ std::list royalGuards;
+ me->GetCreaturesWithEntryInRange(royalGuards, 200.0f, NPC_SARTURA_ROYAL_GUARD);
+ for (Creature* minion : royalGuards)
{
- WhirlWind_Timer = 30000;
- WhirlWindRandom_Timer = urand(3000, 7000);
- WhirlWindEnd_Timer = 15000;
- AggroReset_Timer = urand(45000, 55000);
- AggroResetEnd_Timer = 5000;
- KnockBack_Timer = 10000;
-
- WhirlWind = false;
- AggroReset = false;
+ minion->Respawn();
}
+ }
- void EnterCombat(Unit* /*who*/) override
+ void EnterCombat(Unit* who) override
+ {
+ BossAI::EnterCombat(who);
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 30000);
+ events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(45000, 55000));
+ events.ScheduleEvent(EVENT_SPELL_BERSERK, 10 * 60000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ Talk(SAY_SLAY);
+ }
+
+ void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!enraged && HealthBelowPct(20))
{
+ DoCastSelf(SPELL_ENRAGE);
+ enraged = true;
}
+ }
- void UpdateAI(uint32 diff) override
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if (spell->Id != SPELL_SUNDERING_CLEAVE)
+ return;
+
+ me->RemoveAura(SPELL_SUNDERING_CLEAVE);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (!WhirlWind && WhirlWind_Timer <= diff)
+ switch (eventId)
{
- DoCast(me, SPELL_WHIRLWINDADD);
- WhirlWind = true;
- WhirlWind_Timer = urand(25000, 40000);
- WhirlWindEnd_Timer = 15000;
- }
- else WhirlWind_Timer -= diff;
-
- if (WhirlWind)
- {
- if (WhirlWindRandom_Timer <= diff)
- {
- //Attack random Gamers
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ case EVENT_SARTURA_WHIRLWIND:
+ DoCastSelf(SPELL_WHIRLWIND, true);
+ whirlwind = true;
+ events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND_RANDOM, urand(3000, 7000));
+ events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND_END, 15000);
+ break;
+ case EVENT_SARTURA_WHIRLWIND_RANDOM:
+ if (whirlwind == true)
{
- me->AddThreat(target, 1.0f);
- me->TauntApply(target);
- AttackStart(target);
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ {
+ me->AddThreat(target, 1.0f);
+ me->TauntApply(target);
+ AttackStart(target);
+ }
+ events.RepeatEvent(urand(3000, 7000));
}
-
- WhirlWindRandom_Timer = urand(3000, 7000);
- }
- else WhirlWindRandom_Timer -= diff;
-
- if (WhirlWindEnd_Timer <= diff)
- {
- WhirlWind = false;
- }
- else WhirlWindEnd_Timer -= diff;
- }
-
- if (!WhirlWind)
- {
- if (AggroReset_Timer <= diff)
- {
- //Attack random Gamers
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ break;
+ case EVENT_SARTURA_WHIRLWIND_END:
+ events.CancelEvent(EVENT_SARTURA_WHIRLWIND_RANDOM);
+ whirlwind = false;
+ events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, urand(25000, 40000));
+ break;
+ case EVENT_SARTURA_AGGRO_RESET:
+ if (aggroReset == false)
{
- me->AddThreat(target, 1.0f);
- me->TauntApply(target);
- AttackStart(target);
+ if (Unit* originalTarget = SelectTarget(SelectTargetMethod::Random, 0))
+ {
+ _savedTargetGUID = originalTarget->GetGUID();
+ _savedTargetThreat = me->GetThreatMgr().getThreat(originalTarget);
+ me->GetThreatMgr().modifyThreatPercent(originalTarget, -100);
+ }
+ aggroReset = true;
+ events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET_END, 5000);
}
-
- AggroReset = true;
- AggroReset_Timer = urand(2000, 5000);
- }
- else AggroReset_Timer -= diff;
-
- if (KnockBack_Timer <= diff)
- {
- DoCast(me, SPELL_WHIRLWINDADD);
- KnockBack_Timer = urand(10000, 20000);
- }
- else KnockBack_Timer -= diff;
+ else
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ {
+ me->AddThreat(target, 1.0f);
+ me->TauntApply(target);
+ AttackStart(target);
+ }
+ }
+ events.RepeatEvent(urand(1000, 2000));
+ break;
+ case EVENT_SARTURA_AGGRO_RESET_END:
+ events.CancelEvent(EVENT_SARTURA_AGGRO_RESET);
+ if (Unit* originalTarget = ObjectAccessor::GetUnit(*me, _savedTargetGUID))
+ {
+ me->GetThreatMgr().addThreat(originalTarget, _savedTargetThreat);
+ _savedTargetGUID.Clear();
+ }
+ aggroReset = false;
+ events.RescheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(30000, 40000));
+ break;
+ case EVENT_SPELL_BERSERK:
+ if (!berserked)
+ {
+ DoCastSelf(SPELL_BERSERK);
+ berserked = true;
+ }
+ break;
+ default:
+ break;
}
-
- if (AggroReset)
- {
- if (AggroResetEnd_Timer <= diff)
- {
- AggroReset = false;
- AggroResetEnd_Timer = 5000;
- AggroReset_Timer = urand(30000, 40000);
- }
- else AggroResetEnd_Timer -= diff;
- }
-
- DoMeleeAttackIfReady();
}
+ DoMeleeAttackIfReady();
};
+ private:
+ bool whirlwind;
+ bool enraged;
+ bool berserked;
+ bool aggroReset;
+ ObjectGuid _savedTargetGUID;
+ float _savedTargetThreat;
+};
+
+struct npc_sartura_royal_guard : public ScriptedAI
+{
+ npc_sartura_royal_guard(Creature* creature) : ScriptedAI(creature) {}
+
+ void Reset() override
+ {
+ events.Reset();
+ whirlwind = false;
+ aggroReset = false;
+ _savedTargetGUID.Clear();
+ _savedTargetThreat = 0.f;
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, 30000);
+ events.ScheduleEvent(EVENT_GUARD_AGGRO_RESET, urand(45000, 55000));
+ events.ScheduleEvent(EVENT_GUARD_KNOCKBACK, 10000);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if (spell->Id != SPELL_SUNDERING_CLEAVE)
+ return;
+
+ me->RemoveAura(SPELL_SUNDERING_CLEAVE);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventid = events.ExecuteEvent())
+ {
+ switch (eventid)
+ {
+ case EVENT_GUARD_WHIRLWIND:
+ DoCastSelf(SPELL_GUARD_WHIRLWIND);
+ whirlwind = true;
+ events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_RANDOM, urand(3000, 7000));
+ events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_END, 15000);
+ break;
+ case EVENT_GUARD_WHIRLWIND_RANDOM:
+ if (whirlwind == true)
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ {
+ me->AddThreat(target, 1.0f);
+ me->TauntApply(target);
+ AttackStart(target);
+ }
+ events.RepeatEvent(urand(3000, 7000));
+ }
+ break;
+ case EVENT_GUARD_WHIRLWIND_END:
+ events.CancelEvent(EVENT_GUARD_WHIRLWIND_RANDOM);
+ whirlwind = false;
+ events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, urand(25000, 40000));
+ break;
+ case EVENT_GUARD_AGGRO_RESET:
+ if (aggroReset == true)
+ {
+ if (Unit* originalTarget = SelectTarget(SelectTargetMethod::Random, 0))
+ {
+ _savedTargetGUID = originalTarget->GetGUID();
+ _savedTargetThreat = me->GetThreatMgr().getThreat(originalTarget);
+ me->GetThreatMgr().modifyThreatPercent(originalTarget, -100);
+ }
+ aggroReset = true;
+ events.ScheduleEvent(EVENT_GUARD_AGGRO_RESET_END, 5000);
+ }
+ else
+ {
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
+ {
+ me->AddThreat(target, 1.0f);
+ me->TauntApply(target);
+ AttackStart(target);
+ }
+ }
+ events.RepeatEvent(urand(1000, 2000));
+ break;
+ case EVENT_GUARD_AGGRO_RESET_END:
+ events.CancelEvent(EVENT_GUARD_AGGRO_RESET);
+ if (Unit* originalTarget = ObjectAccessor::GetUnit(*me, _savedTargetGUID))
+ {
+ me->GetThreatMgr().addThreat(originalTarget, _savedTargetThreat);
+ _savedTargetGUID.Clear();
+ }
+ aggroReset = false;
+ events.RescheduleEvent(EVENT_GUARD_AGGRO_RESET, urand(30000, 40000));
+ break;
+ case EVENT_GUARD_KNOCKBACK:
+ DoCastVictim(SPELL_GUARD_KNOCKBACK);
+ events.RepeatEvent(urand(10000, 20000));
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+ }
+ private:
+ bool whirlwind;
+ bool aggroReset;
+ ObjectGuid _savedTargetGUID;
+ float _savedTargetThreat;
};
void AddSC_boss_sartura()
{
- new boss_sartura();
- new npc_sartura_royal_guard();
+ RegisterTempleOfAhnQirajCreatureAI(boss_sartura);
+ RegisterTempleOfAhnQirajCreatureAI(npc_sartura_royal_guard);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
index 5944c9e95..4a9fc1ac3 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
@@ -47,183 +47,161 @@ enum Events
uint32 const BlinkSpells[3] = { 4801, 8195, 20449 };
-class boss_skeram : public CreatureScript
+struct boss_skeram : public BossAI
{
-public:
- boss_skeram() : CreatureScript("boss_skeram") { }
+ boss_skeram(Creature* creature) : BossAI(creature, DATA_SKERAM) { }
- struct boss_skeramAI : public BossAI
+ void Reset() override
{
- boss_skeramAI(Creature* creature) : BossAI(creature, DATA_SKERAM) { }
+ _Reset();
+ _flag = 0;
+ _hpct = 75.0f;
+ me->SetVisible(true);
+ }
- void Reset() override
+ void KilledUnit(Unit* /*victim*/) override
+ {
+ Talk(SAY_SLAY);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ ScriptedAI::EnterEvadeMode(why);
+ if (me->IsSummon())
+ ((TempSummon*)me)->UnSummon();
+ }
+
+ void JustSummoned(Creature* creature) override
+ {
+ // Shift the boss and images (Get it? *Shift*?)
+ uint8 rand = 0;
+ if (_flag != 0)
{
- _Reset();
- _flag = 0;
- _hpct = 75.0f;
- me->SetVisible(true);
- }
-
- void KilledUnit(Unit* /*victim*/) override
- {
- Talk(SAY_SLAY);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- ScriptedAI::EnterEvadeMode(why);
- if (me->IsSummon())
- ((TempSummon*)me)->UnSummon();
- }
-
- void JustSummoned(Creature* creature) override
- {
- // Shift the boss and images (Get it? *Shift*?)
- uint8 rand = 0;
- if (_flag != 0)
- {
- while (_flag & (1 << rand))
- rand = urand(0, 2);
- DoCast(me, BlinkSpells[rand]);
- _flag |= (1 << rand);
- _flag |= (1 << 7);
- }
-
while (_flag & (1 << rand))
rand = urand(0, 2);
- creature->CastSpell(creature, BlinkSpells[rand]);
+ DoCast(me, BlinkSpells[rand]);
_flag |= (1 << rand);
-
- if (_flag & (1 << 7))
- _flag = 0;
-
- float ImageHealthPct;
-
- if (me->GetHealthPct() < 25.0f)
- ImageHealthPct = 0.50f;
- else if (me->GetHealthPct() < 50.0f)
- ImageHealthPct = 0.20f;
- else
- ImageHealthPct = 0.10f;
-
- creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct);
- creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f));
- BossAI::JustSummoned(creature);
+ _flag |= (1 << 7);
}
- void JustDied(Unit* /*killer*/) override
- {
- if (!me->IsSummon())
- {
- _JustDied();
- Talk(SAY_DEATH);
- }
- else
- me->RemoveCorpse();
- }
+ while (_flag & (1 << rand))
+ rand = urand(0, 2);
+ creature->CastSpell(creature, BlinkSpells[rand]);
+ _flag |= (1 << rand);
- void EnterCombat(Unit* /*who*/) override
- {
- _EnterCombat();
- events.Reset();
+ if (_flag & (1 << 7))
+ _flag = 0;
- events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(6000, 12000));
- events.ScheduleEvent(EVENT_FULLFILMENT, 15000);
- events.ScheduleEvent(EVENT_BLINK, urand(30000, 45000));
- events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000);
+ float ImageHealthPct;
- Talk(SAY_AGGRO);
- }
+ if (me->GetHealthPct() < 25.0f)
+ ImageHealthPct = 0.50f;
+ else if (me->GetHealthPct() < 50.0f)
+ ImageHealthPct = 0.20f;
+ else
+ ImageHealthPct = 0.10f;
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_ARCANE_EXPLOSION:
- DoCastAOE(SPELL_ARCANE_EXPLOSION, true);
- events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(8000, 18000));
- break;
- case EVENT_FULLFILMENT:
- /// @todo For some weird reason boss does not cast this
- // Spell actually works, tested in duel
- DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true);
- events.ScheduleEvent(EVENT_FULLFILMENT, urand(20000, 30000));
- break;
- case EVENT_BLINK:
- DoCast(me, BlinkSpells[urand(0, 2)]);
- DoResetThreat();
- me->SetVisible(true);
- events.ScheduleEvent(EVENT_BLINK, urand(10000, 30000));
- break;
- case EVENT_EARTH_SHOCK:
- DoCastVictim(SPELL_EARTH_SHOCK);
- events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000);
- break;
- }
- }
-
- if (!me->IsSummon() && me->GetHealthPct() < _hpct)
- {
- DoCast(me, SPELL_SUMMON_IMAGES, true);
- Talk(SAY_SPLIT);
- _hpct -= 25.0f;
- me->SetVisible(false);
- events.RescheduleEvent(EVENT_BLINK, 2000);
- }
-
- if (me->IsWithinMeleeRange(me->GetVictim()))
- {
- events.RescheduleEvent(EVENT_EARTH_SHOCK, 2000);
- DoMeleeAttackIfReady();
- }
- }
-
- private:
- float _hpct;
- uint8 _flag;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetTempleOfAhnQirajAI(creature);
+ creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct);
+ creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f));
+ BossAI::JustSummoned(creature);
}
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (!me->IsSummon())
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
+ else
+ me->RemoveCorpse();
+ }
+
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _EnterCombat();
+ events.Reset();
+
+ events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 6s, 12s);
+ events.ScheduleEvent(EVENT_FULLFILMENT, 15s);
+ events.ScheduleEvent(EVENT_BLINK, 30s, 45s);
+ events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s);
+
+ Talk(SAY_AGGRO);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_ARCANE_EXPLOSION:
+ DoCastAOE(SPELL_ARCANE_EXPLOSION, true);
+ events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 8s, 18s);
+ break;
+ case EVENT_FULLFILMENT:
+ /// @todo For some weird reason boss does not cast this
+ // Spell actually works, tested in duel
+ DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true);
+ events.ScheduleEvent(EVENT_FULLFILMENT, 20s, 30s);
+ break;
+ case EVENT_BLINK:
+ DoCast(me, BlinkSpells[urand(0, 2)]);
+ DoResetThreat();
+ me->SetVisible(true);
+ events.ScheduleEvent(EVENT_BLINK, 10s, 30s);
+ break;
+ case EVENT_EARTH_SHOCK:
+ DoCastVictim(SPELL_EARTH_SHOCK);
+ events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s);
+ break;
+ }
+ }
+
+ if (!me->IsSummon() && me->GetHealthPct() < _hpct)
+ {
+ DoCast(me, SPELL_SUMMON_IMAGES, true);
+ Talk(SAY_SPLIT);
+ _hpct -= 25.0f;
+ me->SetVisible(false);
+ events.RescheduleEvent(EVENT_BLINK, 2s);
+ }
+
+ if (me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ events.RescheduleEvent(EVENT_EARTH_SHOCK, 2s);
+ DoMeleeAttackIfReady();
+ }
+ }
+
+private:
+ float _hpct;
+ uint8 _flag;
};
-class spell_skeram_arcane_explosion : public SpellScriptLoader
+class spell_skeram_arcane_explosion : public SpellScript
{
-public:
- spell_skeram_arcane_explosion() : SpellScriptLoader("spell_skeram_arcane_explosion") { }
+ PrepareSpellScript(spell_skeram_arcane_explosion);
- class spell_skeram_arcane_explosion_SpellScript : public SpellScript
+ void FilterTargets(std::list& targets)
{
- PrepareSpellScript(spell_skeram_arcane_explosion_SpellScript);
+ targets.remove_if(PlayerOrPetCheck());
+ }
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(PlayerOrPetCheck());
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
+ void Register() override
{
- return new spell_skeram_arcane_explosion_SpellScript();
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
void AddSC_boss_skeram()
{
- new boss_skeram();
- new spell_skeram_arcane_explosion();
+ RegisterTempleOfAhnQirajCreatureAI(boss_skeram);
+ RegisterSpellScript(spell_skeram_arcane_explosion);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
index 841280dcf..33b32fa44 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp
@@ -377,223 +377,203 @@ struct boss_twinemperorsAI : public ScriptedAI
}
};
-class boss_veknilash : public CreatureScript
+struct boss_veknilash : public boss_twinemperorsAI
{
-public:
- boss_veknilash() : CreatureScript("boss_veknilash") { }
+ boss_veknilash(Creature* creature) : boss_twinemperorsAI(creature) { }
- CreatureAI* GetAI(Creature* creature) const override
+ bool IAmVeklor() override { return false; }
+
+ uint32 UpperCut_Timer;
+ uint32 UnbalancingStrike_Timer;
+ uint32 Scarabs_Timer;
+ int Rand;
+ int RandX;
+ int RandY;
+
+ Creature* Summoned;
+
+ void Reset() override
{
- return GetTempleOfAhnQirajAI(creature);
+ TwinReset();
+ UpperCut_Timer = urand(14000, 29000);
+ UnbalancingStrike_Timer = urand(8000, 18000);
+ Scarabs_Timer = urand(7000, 14000);
+
+ //Added. Can be removed if its included in DB.
+ me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
}
- struct boss_veknilashAI : public boss_twinemperorsAI
+ void CastSpellOnBug(Creature* target) override
{
- bool IAmVeklor() override {return false;}
- boss_veknilashAI(Creature* creature) : boss_twinemperorsAI(creature) { }
+ target->SetFaction(FACTION_MONSTER);
+ target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget());
+ target->AddAura(SPELL_MUTATE_BUG, target);
+ target->SetFullHealth();
+ }
- uint32 UpperCut_Timer;
- uint32 UnbalancingStrike_Timer;
- uint32 Scarabs_Timer;
- int Rand;
- int RandX;
- int RandY;
+ void UpdateAI(uint32 diff) override
+ {
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
- Creature* Summoned;
+ if (!TryActivateAfterTTelep(diff))
+ return;
- void Reset() override
+ //UnbalancingStrike_Timer
+ if (UnbalancingStrike_Timer <= diff)
{
- TwinReset();
- UpperCut_Timer = urand(14000, 29000);
- UnbalancingStrike_Timer = urand(8000, 18000);
- Scarabs_Timer = urand(7000, 14000);
-
- //Added. Can be removed if its included in DB.
- me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
+ DoCastVictim(SPELL_UNBALANCING_STRIKE);
+ UnbalancingStrike_Timer = 8000 + rand() % 12000;
}
+ else UnbalancingStrike_Timer -= diff;
- void CastSpellOnBug(Creature* target) override
+ if (UpperCut_Timer <= diff)
{
- target->SetFaction(FACTION_MONSTER);
- target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget());
- target->AddAura(SPELL_MUTATE_BUG, target);
- target->SetFullHealth();
+ Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true);
+ if (randomMelee)
+ DoCast(randomMelee, SPELL_UPPERCUT);
+ UpperCut_Timer = 15000 + rand() % 15000;
}
+ else UpperCut_Timer -= diff;
- void UpdateAI(uint32 diff) override
+ HandleBugs(diff);
+
+ //Heal brother when 60yrds close
+ TryHealBrother(diff);
+
+ //Teleporting to brother
+ if (Teleport_Timer <= diff)
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (!TryActivateAfterTTelep(diff))
- return;
-
- //UnbalancingStrike_Timer
- if (UnbalancingStrike_Timer <= diff)
- {
- DoCastVictim(SPELL_UNBALANCING_STRIKE);
- UnbalancingStrike_Timer = 8000 + rand() % 12000;
- }
- else UnbalancingStrike_Timer -= diff;
-
- if (UpperCut_Timer <= diff)
- {
- Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true);
- if (randomMelee)
- DoCast(randomMelee, SPELL_UPPERCUT);
- UpperCut_Timer = 15000 + rand() % 15000;
- }
- else UpperCut_Timer -= diff;
-
- HandleBugs(diff);
-
- //Heal brother when 60yrds close
- TryHealBrother(diff);
-
- //Teleporting to brother
- if (Teleport_Timer <= diff)
- {
- TeleportToMyBrother();
- }
- else Teleport_Timer -= diff;
-
- CheckEnrage(diff);
-
- DoMeleeAttackIfReady();
+ TeleportToMyBrother();
}
- };
+ else Teleport_Timer -= diff;
+
+ CheckEnrage(diff);
+
+ DoMeleeAttackIfReady();
+ }
};
-class boss_veklor : public CreatureScript
+struct boss_veklor : public boss_twinemperorsAI
{
-public:
- boss_veklor() : CreatureScript("boss_veklor") { }
+ boss_veklor(Creature* creature) : boss_twinemperorsAI(creature) { }
- CreatureAI* GetAI(Creature* creature) const override
+ bool IAmVeklor() override { return true; }
+
+ uint32 ShadowBolt_Timer;
+ uint32 Blizzard_Timer;
+ uint32 ArcaneBurst_Timer;
+ uint32 Scorpions_Timer;
+ int Rand;
+ int RandX;
+
+ Creature* Summoned;
+
+ void Reset() override
{
- return GetTempleOfAhnQirajAI(creature);
+ TwinReset();
+ ShadowBolt_Timer = 0;
+ Blizzard_Timer = urand(15000, 20000);
+ ArcaneBurst_Timer = 1000;
+ Scorpions_Timer = urand(7000, 14000);
+
+ //Added. Can be removed if its included in DB.
+ me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
}
- struct boss_veklorAI : public boss_twinemperorsAI
+ void CastSpellOnBug(Creature* target) override
{
- bool IAmVeklor() override {return true;}
- boss_veklorAI(Creature* creature) : boss_twinemperorsAI(creature) { }
+ target->SetFaction(FACTION_MONSTER);
+ target->AddAura(SPELL_EXPLODEBUG, target);
+ target->SetFullHealth();
+ }
- uint32 ShadowBolt_Timer;
- uint32 Blizzard_Timer;
- uint32 ArcaneBurst_Timer;
- uint32 Scorpions_Timer;
- int Rand;
- int RandX;
+ void UpdateAI(uint32 diff) override
+ {
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
- Creature* Summoned;
+ // reset arcane burst after teleport - we need to do this because
+ // when VL jumps to VN's location there will be a warrior who will get only 2s to run away
+ // which is almost impossible
+ if (AfterTeleport)
+ ArcaneBurst_Timer = 5000;
+ if (!TryActivateAfterTTelep(diff))
+ return;
- void Reset() override
+ //ShadowBolt_Timer
+ if (ShadowBolt_Timer <= diff)
{
- TwinReset();
- ShadowBolt_Timer = 0;
- Blizzard_Timer = urand(15000, 20000);
- ArcaneBurst_Timer = 1000;
- Scorpions_Timer = urand(7000, 14000);
-
- //Added. Can be removed if its included in DB.
- me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
+ if (!me->IsWithinDist(me->GetVictim(), 45.0f))
+ me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
+ else
+ DoCastVictim(SPELL_SHADOWBOLT);
+ ShadowBolt_Timer = 2000;
}
+ else ShadowBolt_Timer -= diff;
- void CastSpellOnBug(Creature* target) override
+ //Blizzard_Timer
+ if (Blizzard_Timer <= diff)
{
- target->SetFaction(FACTION_MONSTER);
- target->AddAura(SPELL_EXPLODEBUG, target);
- target->SetFullHealth();
+ Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true);
+ if (target)
+ {
+ DoCast(target, SPELL_BLIZZARD);
+ }
+ Blizzard_Timer = 15000 + rand() % 15000;
}
+ else Blizzard_Timer -= diff;
- void UpdateAI(uint32 diff) override
+ if (ArcaneBurst_Timer <= diff)
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- // reset arcane burst after teleport - we need to do this because
- // when VL jumps to VN's location there will be a warrior who will get only 2s to run away
- // which is almost impossible
- if (AfterTeleport)
+ Unit* mvic;
+ if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr)
+ {
+ DoCast(mvic, SPELL_ARCANEBURST);
ArcaneBurst_Timer = 5000;
- if (!TryActivateAfterTTelep(diff))
- return;
-
- //ShadowBolt_Timer
- if (ShadowBolt_Timer <= diff)
- {
- if (!me->IsWithinDist(me->GetVictim(), 45.0f))
- me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
- else
- DoCastVictim(SPELL_SHADOWBOLT);
- ShadowBolt_Timer = 2000;
}
- else ShadowBolt_Timer -= diff;
-
- //Blizzard_Timer
- if (Blizzard_Timer <= diff)
- {
- Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true);
- if (target)
- {
- DoCast(target, SPELL_BLIZZARD);
- }
- Blizzard_Timer = 15000 + rand() % 15000;
- }
- else Blizzard_Timer -= diff;
-
- if (ArcaneBurst_Timer <= diff)
- {
- Unit* mvic;
- if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr)
- {
- DoCast(mvic, SPELL_ARCANEBURST);
- ArcaneBurst_Timer = 5000;
- }
- }
- else ArcaneBurst_Timer -= diff;
-
- HandleBugs(diff);
-
- //Heal brother when 60yrds close
- TryHealBrother(diff);
-
- //Teleporting to brother
- if (Teleport_Timer <= diff)
- {
- TeleportToMyBrother();
- }
- else Teleport_Timer -= diff;
-
- CheckEnrage(diff);
-
- //VL doesn't melee
- //DoMeleeAttackIfReady();
}
+ else ArcaneBurst_Timer -= diff;
- void AttackStart(Unit* who) override
+ HandleBugs(diff);
+
+ //Heal brother when 60yrds close
+ TryHealBrother(diff);
+
+ //Teleporting to brother
+ if (Teleport_Timer <= diff)
{
- if (!who)
- return;
+ TeleportToMyBrother();
+ }
+ else Teleport_Timer -= diff;
- if (who->isTargetableForAttack())
+ CheckEnrage(diff);
+
+ //VL doesn't melee
+ //DoMeleeAttackIfReady();
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (!who)
+ return;
+
+ if (who->isTargetableForAttack())
+ {
+ // VL doesn't melee
+ if (me->Attack(who, false))
{
- // VL doesn't melee
- if (me->Attack(who, false))
- {
- me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
- me->AddThreat(who, 0.0f);
- }
+ me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
+ me->AddThreat(who, 0.0f);
}
}
- };
+ }
};
void AddSC_boss_twinemperors()
{
- new boss_veknilash();
- new boss_veklor();
+ RegisterTempleOfAhnQirajCreatureAI(boss_veknilash);
+ RegisterTempleOfAhnQirajCreatureAI(boss_veklor);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp
index a993aa06e..e5e0834d1 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp
@@ -84,223 +84,201 @@ enum MovePoints
Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; /// @todo Visci isn't in room middle
float const RoomRadius = 40.0f; /// @todo Not sure if its correct
-class boss_viscidus : public CreatureScript
+struct boss_viscidus : public BossAI
{
-public:
- boss_viscidus() : CreatureScript("boss_viscidus") { }
+ boss_viscidus(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { }
- struct boss_viscidusAI : public BossAI
+ void Reset() override
{
- boss_viscidusAI(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { }
+ _Reset();
+ _hitcounter = 0;
+ _phase = PHASE_FROST;
+ }
- void Reset() override
+ void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!attacker || _phase != PHASE_MELEE)
+ return;
+
+ ++_hitcounter;
+
+ if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE)
{
- _Reset();
- _hitcounter = 0;
- _phase = PHASE_FROST;
+ Talk(EMOTE_EXPLODE);
+ events.Reset();
+ _phase = PHASE_GLOB;
+ DoCast(me, SPELL_VISCIDUS_EXPLODE);
+ me->SetVisible(false);
+ me->RemoveAura(SPELL_TOXIN);
+ me->RemoveAura(SPELL_VISCIDUS_FREEZE);
+
+ uint8 NumGlobes = me->GetHealthPct() / 5.0f;
+ for (uint8 i = 0; i < NumGlobes; ++i)
+ {
+ float Angle = i * 2 * M_PI / NumGlobes;
+ float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius;
+ float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius;
+ float Z = -35.0f;
+
+ if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z))
+ {
+ Glob->UpdateAllowedPositionZ(X, Y, Z);
+ Glob->NearTeleportTo(X, Y, Z, 0.0f);
+ Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord);
+ }
+ }
}
+ else if (_hitcounter == HITCOUNTER_SHATTER)
+ Talk(EMOTE_SHATTER);
+ else if (_hitcounter == HITCOUNTER_CRACK)
+ Talk(EMOTE_CRACK);
+ }
- void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f)
{
- if (!attacker || _phase != PHASE_MELEE)
- return;
-
++_hitcounter;
- if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE)
+ if (_hitcounter >= HITCOUNTER_FREEZE)
{
- Talk(EMOTE_EXPLODE);
- events.Reset();
- _phase = PHASE_GLOB;
- DoCast(me, SPELL_VISCIDUS_EXPLODE);
- me->SetVisible(false);
- me->RemoveAura(SPELL_TOXIN);
- me->RemoveAura(SPELL_VISCIDUS_FREEZE);
-
- uint8 NumGlobes = me->GetHealthPct() / 5.0f;
- for (uint8 i = 0; i < NumGlobes; ++i)
- {
- float Angle = i * 2 * M_PI / NumGlobes;
- float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius;
- float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius;
- float Z = -35.0f;
-
- if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z))
- {
- Glob->UpdateAllowedPositionZ(X, Y, Z);
- Glob->NearTeleportTo(X, Y, Z, 0.0f);
- Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord);
- }
- }
- }
- else if (_hitcounter == HITCOUNTER_SHATTER)
- Talk(EMOTE_SHATTER);
- else if (_hitcounter == HITCOUNTER_CRACK)
- Talk(EMOTE_CRACK);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f)
- {
- ++_hitcounter;
-
- if (_hitcounter >= HITCOUNTER_FREEZE)
- {
- _hitcounter = 0;
- Talk(EMOTE_FROZEN);
- _phase = PHASE_MELEE;
- DoCast(me, SPELL_VISCIDUS_FREEZE);
- me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE);
- events.ScheduleEvent(EVENT_RESET_PHASE, 15000);
- }
- else if (_hitcounter >= HITCOUNTER_SLOW_MORE)
- {
- Talk(EMOTE_FREEZE);
- me->RemoveAura(SPELL_VISCIDUS_SLOWED);
- DoCast(me, SPELL_VISCIDUS_SLOWED_MORE);
- }
- else if (_hitcounter >= HITCOUNTER_SLOW)
- {
- Talk(EMOTE_SLOW);
- DoCast(me, SPELL_VISCIDUS_SLOWED);
- }
- }
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- _EnterCombat();
- events.Reset();
- InitSpells();
- }
-
- void InitSpells()
- {
- DoCast(me, SPELL_TOXIN);
- events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000));
- events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000));
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- summons.DespawnAll();
- ScriptedAI::EnterEvadeMode(why);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- DoCast(me, SPELL_VISCIDUS_SUICIDE);
- summons.DespawnAll();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (_phase == PHASE_GLOB && summons.empty())
- {
- DoResetThreat();
- me->NearTeleportTo(ViscidusCoord.GetPositionX(),
- ViscidusCoord.GetPositionY(),
- ViscidusCoord.GetPositionZ(),
- ViscidusCoord.GetOrientation());
-
_hitcounter = 0;
- _phase = PHASE_FROST;
- InitSpells();
- me->SetVisible(true);
+ Talk(EMOTE_FROZEN);
+ _phase = PHASE_MELEE;
+ DoCast(me, SPELL_VISCIDUS_FREEZE);
+ me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE);
+ events.ScheduleEvent(EVENT_RESET_PHASE, 15000);
}
-
- events.Update(diff);
-
- while (uint32 eventId = events.ExecuteEvent())
+ else if (_hitcounter >= HITCOUNTER_SLOW_MORE)
{
- switch (eventId)
- {
- case EVENT_POISONBOLT_VOLLEY:
- DoCast(me, SPELL_POISONBOLT_VOLLEY);
- events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000));
- break;
- case EVENT_POISON_SHOCK:
- DoCast(me, SPELL_POISON_SHOCK);
- events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000));
- break;
- case EVENT_RESET_PHASE:
- _hitcounter = 0;
- _phase = PHASE_FROST;
- break;
- default:
- break;
- }
+ Talk(EMOTE_FREEZE);
+ me->RemoveAura(SPELL_VISCIDUS_SLOWED);
+ DoCast(me, SPELL_VISCIDUS_SLOWED_MORE);
}
+ else if (_hitcounter >= HITCOUNTER_SLOW)
+ {
+ Talk(EMOTE_SLOW);
+ DoCast(me, SPELL_VISCIDUS_SLOWED);
+ }
+ }
+ }
- if (_phase != PHASE_GLOB)
- DoMeleeAttackIfReady();
+ void EnterCombat(Unit* /*who*/) override
+ {
+ _EnterCombat();
+ events.Reset();
+ InitSpells();
+ }
+
+ void InitSpells()
+ {
+ DoCast(me, SPELL_TOXIN);
+ events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s);
+ events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ summons.DespawnAll();
+ ScriptedAI::EnterEvadeMode(why);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ DoCast(me, SPELL_VISCIDUS_SUICIDE);
+ summons.DespawnAll();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (_phase == PHASE_GLOB && summons.empty())
+ {
+ DoResetThreat();
+ me->NearTeleportTo(ViscidusCoord.GetPositionX(),
+ ViscidusCoord.GetPositionY(),
+ ViscidusCoord.GetPositionZ(),
+ ViscidusCoord.GetOrientation());
+
+ _hitcounter = 0;
+ _phase = PHASE_FROST;
+ InitSpells();
+ me->SetVisible(true);
}
- private:
- uint8 _hitcounter;
- Phases _phase;
- };
+ events.Update(diff);
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetTempleOfAhnQirajAI(creature);
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_POISONBOLT_VOLLEY:
+ DoCast(me, SPELL_POISONBOLT_VOLLEY);
+ events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s);
+ break;
+ case EVENT_POISON_SHOCK:
+ DoCast(me, SPELL_POISON_SHOCK);
+ events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s);
+ break;
+ case EVENT_RESET_PHASE:
+ _hitcounter = 0;
+ _phase = PHASE_FROST;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_phase != PHASE_GLOB)
+ DoMeleeAttackIfReady();
}
+
+private:
+ uint8 _hitcounter;
+ Phases _phase;
};
-class npc_glob_of_viscidus : public CreatureScript
+struct boss_glob_of_viscidus : public ScriptedAI
{
-public:
- npc_glob_of_viscidus() : CreatureScript("boss_glob_of_viscidus") { }
+ boss_glob_of_viscidus(Creature* creature) : ScriptedAI(creature) { }
- struct npc_glob_of_viscidusAI : public ScriptedAI
+ void JustDied(Unit* /*killer*/) override
{
- npc_glob_of_viscidusAI(Creature* creature) : ScriptedAI(creature) { }
+ InstanceScript* instance = me->GetInstanceScript();
- void JustDied(Unit* /*killer*/) override
+ if (Creature* viscidus = me->GetMap()->GetCreature(instance->GetGuidData(DATA_VISCIDUS)))
{
- InstanceScript* Instance = me->GetInstanceScript();
+ if (BossAI* viscidusAI = dynamic_cast(viscidus->GetAI()))
+ viscidusAI->SummonedCreatureDespawn(me);
- if (Creature* Viscidus = me->GetMap()->GetCreature(Instance->GetGuidData(DATA_VISCIDUS)))
+ if (viscidus->IsAlive() && viscidus->GetHealthPct() < 5.0f)
{
- if (BossAI* ViscidusAI = dynamic_cast(Viscidus->GetAI()))
- ViscidusAI->SummonedCreatureDespawn(me);
-
- if (Viscidus->IsAlive() && Viscidus->GetHealthPct() < 5.0f)
- {
- Viscidus->SetVisible(true);
- Unit::Kill(Viscidus->GetVictim(), Viscidus);
- }
- else
- {
- Viscidus->SetHealth(Viscidus->GetHealth() - Viscidus->GetMaxHealth() / 20);
- Viscidus->CastSpell(Viscidus, SPELL_VISCIDUS_SHRINKS);
- }
+ viscidus->SetVisible(true);
+ Unit::Kill(viscidus->GetVictim(), viscidus);
+ }
+ else
+ {
+ viscidus->SetHealth(viscidus->GetHealth() - viscidus->GetMaxHealth() / 20);
+ viscidus->CastSpell(viscidus, SPELL_VISCIDUS_SHRINKS);
}
}
+ }
- void MovementInform(uint32 /*type*/, uint32 id) override
- {
- if (id == ROOM_CENTER)
- {
- DoCast(me, SPELL_REJOIN_VISCIDUS);
- if (TempSummon* summon = me->ToTempSummon())
- summon->UnSummon();
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
+ void MovementInform(uint32 /*type*/, uint32 id) override
{
- return GetTempleOfAhnQirajAI(creature);
+ if (id == ROOM_CENTER)
+ {
+ DoCast(me, SPELL_REJOIN_VISCIDUS);
+ if (TempSummon* summon = me->ToTempSummon())
+ summon->UnSummon();
+ }
}
};
void AddSC_boss_viscidus()
{
- new boss_viscidus();
- new npc_glob_of_viscidus();
+ RegisterTempleOfAhnQirajCreatureAI(boss_viscidus);
+ RegisterTempleOfAhnQirajCreatureAI(boss_glob_of_viscidus);
}
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/instance_temple_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/instance_temple_of_ahnqiraj.cpp
index 3056a305f..215e4c790 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/instance_temple_of_ahnqiraj.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/instance_temple_of_ahnqiraj.cpp
@@ -30,7 +30,8 @@ EndScriptData */
ObjectData const creatureData[] =
{
{ NPC_SARTURA, DATA_SARTURA },
- { NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN }
+ { NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
+ { NPC_OURO_SPAWNER, DATA_OURO_SPAWNER }
};
class instance_temple_of_ahnqiraj : public InstanceMapScript
@@ -102,6 +103,10 @@ public:
case NPC_VISCIDUS:
ViscidusGUID = creature->GetGUID();
break;
+ case NPC_OURO_SPAWNER:
+ if (GetBossState(DATA_OURO) != DONE)
+ creature->Respawn();
+ break;
}
InstanceScript::OnCreatureCreate(creature);
@@ -177,6 +182,27 @@ public:
break;
}
}
+
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DATA_OURO:
+ if (state == FAIL)
+ {
+ if (Creature* ouroSpawner = GetCreature(DATA_OURO))
+ ouroSpawner->Respawn();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+ }
};
};
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/mob_anubisath_sentinel.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/mob_anubisath_sentinel.cpp
index c2cb324f7..6d1e21635 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/mob_anubisath_sentinel.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/mob_anubisath_sentinel.cpp
@@ -34,25 +34,33 @@ EndScriptData */
enum Spells
{
- SPELL_MENDING_BUFF = 2147,
+ SPELL_MENDING_BUFF = 2147,
- SPELL_KNOCK_BUFF = 21737,
- SPELL_KNOCK = 25778,
- SPELL_MANAB_BUFF = 812,
- SPELL_MANAB = 25779,
+ SPELL_KNOCK_BUFF = 21737,
+ SPELL_KNOCK = 25778,
+ SPELL_MANAB_BUFF = 812,
+ SPELL_MANAB = 25779,
- SPELL_REFLECTAF_BUFF = 13022,
- SPELL_REFLECTSFr_BUFF = 19595,
- SPELL_THORNS_BUFF = 25777,
+ SPELL_REFLECTAF_BUFF = 13022,
+ SPELL_REFLECTSFr_BUFF = 19595,
+ SPELL_THORNS_BUFF = 25777,
- SPELL_THUNDER_BUFF = 2834,
- SPELL_THUNDER = 8732,
+ SPELL_THUNDER_BUFF = 2834,
+ SPELL_THUNDER = 8732,
- SPELL_MSTRIKE_BUFF = 9347,
- SPELL_MSTRIKE = 24573,
+ SPELL_MSTRIKE_BUFF = 9347,
+ SPELL_MSTRIKE = 24573,
- SPELL_STORM_BUFF = 2148,
- SPELL_STORM = 26546
+ SPELL_STORM_BUFF = 2148,
+ SPELL_STORM = 26546,
+
+ SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK = 27627, // Server-side
+
+ SPELL_TRANSFER_POWER = 2400,
+ SPELL_HEAL_BRETHEN = 26565,
+ SPELL_ENRAGE = 8599,
+
+ TALK_ENRAGE = 0
};
class npc_anubisath_sentinel : public CreatureScript
@@ -245,6 +253,7 @@ public:
}
ClearBuddyList();
gatherOthersWhenAggro = true;
+ _enraged = false;
}
void GainSentinelAbility(uint32 id)
@@ -261,6 +270,20 @@ public:
DoZoneInCombat();
}
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_TRANSFER_POWER)
+ {
+ if (Creature* sentinel = target->ToCreature())
+ {
+ if (sentinel->IsAIEnabled)
+ {
+ CAST_AI(aqsentinelAI, sentinel->AI())->GainSentinelAbility(ability);
+ }
+ }
+ }
+ }
+
void JustDied(Unit* /*killer*/) override
{
for (int ni = 0; ni < 3; ++ni)
@@ -270,10 +293,26 @@ public:
continue;
if (sent->isDead())
continue;
- sent->ModifyHealth(int32(sent->CountPctFromMaxHealth(50)));
- CAST_AI(aqsentinelAI, sent->AI())->GainSentinelAbility(ability);
+ DoCast(sent, SPELL_HEAL_BRETHEN, true);
+ DoCast(sent, SPELL_TRANSFER_POWER, true);
+ }
+
+ DoCastSelf(SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK, true);
+ }
+
+ void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
+ {
+ if (!_enraged && me->HealthBelowPctDamaged(50, damage))
+ {
+ _enraged = true;
+ damage = 0;
+ DoCastSelf(SPELL_ENRAGE, true);
+ Talk(TALK_ENRAGE);
}
}
+
+ private:
+ bool _enraged;
};
};
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h
index d32f6dbd9..9301c9503 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h
@@ -35,7 +35,10 @@ enum DataTypes
DATA_VEKNILASH = 9,
DATA_VEKNILASHISDEAD = 10,
DATA_VEKNILASH_DEATH = 11,
- DATA_BUG_TRIO_DEATH = 14,
+ DATA_FANKRISS = 12,
+ DATA_OURO = 13,
+ DATA_OURO_SPAWNER = 14,
+ DATA_BUG_TRIO_DEATH = 15,
DATA_CTHUN_PHASE = 20,
DATA_VISCIDUS = 21,
DATA_SARTURA = 22,
@@ -55,7 +58,7 @@ enum Creatures
NPC_GIANT_EYE_TENTACLE = 15334,
NPC_FLESH_TENTACLE = 15802,
NPC_GIANT_PORTAL = 15910,
-
+ NPC_SARTURA_ROYAL_GUARD = 15984,
NPC_VISCIDUS = 15299,
NPC_GLOB_OF_VISCIDUS = 15667,
@@ -66,6 +69,7 @@ enum Creatures
NPC_VEKLOR = 15276,
NPC_VEKNILASH = 15275,
NPC_OURO = 15517,
+ NPC_OURO_SPAWNER = 15957,
NPC_SARTURA = 15516
};
@@ -75,4 +79,6 @@ inline AI* GetTempleOfAhnQirajAI(T* obj)
return GetInstanceAI(obj, TempleOfAhnQirajScriptName);
}
+#define RegisterTempleOfAhnQirajCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTempleOfAhnQirajAI)
+
#endif
diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
index c3391cbdd..e628322e3 100644
--- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
+++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
@@ -57,6 +57,7 @@ void AddSC_boss_moam();
void AddSC_boss_buru();
void AddSC_boss_ayamiss();
void AddSC_boss_ossirian();
+void AddSC_ruins_of_ahnqiraj();
void AddSC_instance_ruins_of_ahnqiraj();
void AddSC_boss_cthun(); //Temple of ahn'qiraj
void AddSC_boss_viscidus();
@@ -139,6 +140,7 @@ void AddKalimdorScripts()
AddSC_boss_buru();
AddSC_boss_ayamiss();
AddSC_boss_ossirian();
+ AddSC_ruins_of_ahnqiraj();
AddSC_instance_ruins_of_ahnqiraj();
AddSC_boss_cthun(); //Temple of ahn'qiraj
AddSC_boss_viscidus();
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp
index 7daf57746..ebf54535a 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp
@@ -118,11 +118,11 @@ public:
if( pInstance )
pInstance->SetData(TYPE_JARAXXUS, NOT_STARTED);
- // checked for safety
- while( Creature* c = me->FindNearestCreature(NPC_INFERNAL_VOLCANO, 500.0f, true) )
- c->DespawnOrUnsummon();
- while( Creature* c = me->FindNearestCreature(NPC_NETHER_PORTAL, 500.0f, true) )
- c->DespawnOrUnsummon();
+ std::list creatures;
+ me->GetCreatureListWithEntryInGrid(creatures, NPC_INFERNAL_VOLCANO, 500.f);
+ me->GetCreatureListWithEntryInGrid(creatures, NPC_NETHER_PORTAL, 500.f);
+ for (Creature* creature : creatures)
+ creature->DespawnOrUnsummon();
}
void EnterCombat(Unit* /*who*/) override
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 8204f55b4..6036ab00d 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -1199,7 +1199,7 @@ class spell_gen_adaptive_warding : public AuraScript
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (eventInfo.GetSpellInfo())
+ if (!eventInfo.GetSpellInfo())
return false;
// find Mage Armor
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index 0e715bf55..759141d94 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -666,10 +666,13 @@ class spell_hun_readiness : public SpellScript
&& spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER
&& spellInfo->Id != SPELL_HUNTER_READINESS
&& spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH
- && spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU
- && spellInfo->GetRecoveryTime() > 0)
+ && spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU)
{
- caster->RemoveSpellCooldown(spellInfo->Id, itr->second.needSendToClient);
+ if (spellInfo->RecoveryTime > 0)
+ caster->RemoveSpellCooldown(spellInfo->Id, itr->second.needSendToClient);
+
+ if (spellInfo->CategoryRecoveryTime > 0)
+ caster->RemoveCategoryCooldown(spellInfo->GetCategory());
}
}
}
diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp
index 384bee7da..89624091b 100644
--- a/src/server/scripts/Spells/spell_priest.cpp
+++ b/src/server/scripts/Spells/spell_priest.cpp
@@ -428,9 +428,26 @@ class spell_pri_lightwell_renew : public AuraScript
}
}
+ void HandleUpdateSpellclick(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ if (Player* player = GetTarget()->ToPlayer())
+ {
+ UpdateData data;
+ WorldPacket packet;
+ caster->BuildValuesUpdateBlockForPlayer(&data, player);
+ data.BuildPacket(&packet);
+ player->SendDirectMessage(&packet);
+ }
+ }
+ }
+
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_lightwell_renew::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_HEAL);
+ AfterEffectApply += AuraEffectApplyFn(spell_pri_lightwell_renew::HandleUpdateSpellclick, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_pri_lightwell_renew::HandleUpdateSpellclick, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL);
}
};
diff --git a/src/server/scripts/World/boss_emerald_dragons.cpp b/src/server/scripts/World/boss_emerald_dragons.cpp
index 5d0a3d35e..a45f55d13 100644
--- a/src/server/scripts/World/boss_emerald_dragons.cpp
+++ b/src/server/scripts/World/boss_emerald_dragons.cpp
@@ -22,6 +22,7 @@
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
+#include "TaskScheduler.h"
//
// Emerald Dragon NPCs and IDs (kept here for reference)
@@ -34,6 +35,9 @@ enum EmeraldDragonNPC
DRAGON_LETHON = 14888,
DRAGON_EMERISS = 14889,
DRAGON_TAERAR = 14890,
+
+ GUID_DRAGON = 1,
+ GUID_FOG_TARGET = 2
};
//
@@ -64,6 +68,7 @@ enum Events
EVENT_SEEPING_FOG = 1,
EVENT_NOXIOUS_BREATH,
EVENT_TAIL_SWEEP,
+ EVENT_SUMMON_PLAYER,
// Ysondre
EVENT_LIGHTNING_WAVE,
@@ -102,6 +107,7 @@ struct emerald_dragonAI : public WorldBossAI
events.ScheduleEvent(EVENT_TAIL_SWEEP, 4000);
events.ScheduleEvent(EVENT_NOXIOUS_BREATH, urand(7500, 15000));
events.ScheduleEvent(EVENT_SEEPING_FOG, urand(12500, 20000));
+ events.ScheduleEvent(EVENT_SUMMON_PLAYER, 1s);
}
// Target killed during encounter, mark them as suspectible for Aura Of Nature
@@ -133,6 +139,20 @@ struct emerald_dragonAI : public WorldBossAI
DoCast(me, SPELL_TAIL_SWEEP);
events.ScheduleEvent(EVENT_TAIL_SWEEP, 2000);
break;
+ case EVENT_SUMMON_PLAYER:
+ if (Unit* target = me->GetVictim())
+ if (!target->IsWithinRange(me, 50.f))
+ DoCast(target, SPELL_SUMMON_PLAYER);
+ events.ScheduleEvent(EVENT_SUMMON_PLAYER, 500ms);
+ break;
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (summon->GetEntry() == NPC_DREAM_FOG)
+ {
+ summon->AI()->SetGUID(me->GetGUID(), GUID_DRAGON);
}
}
@@ -149,9 +169,6 @@ struct emerald_dragonAI : public WorldBossAI
while (uint32 eventId = events.ExecuteEvent())
ExecuteEvent(eventId);
- if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, -50.0f, true))
- DoCast(target, SPELL_SUMMON_PLAYER);
-
DoMeleeAttackIfReady();
}
};
@@ -167,13 +184,66 @@ public:
struct npc_dream_fogAI : public ScriptedAI
{
- npc_dream_fogAI(Creature* creature) : ScriptedAI(creature)
- {
- }
+ npc_dream_fogAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
- _roamTimer = 0;
+ ScheduleEvents();
+ }
+
+ void ScheduleEvents()
+ {
+ _scheduler.CancelAll();
+
+ _scheduler.Schedule(1s, [this](TaskContext context)
+ {
+ // Chase target, but don't attack - otherwise just roam around
+ if (Unit* chaseTarget = GetRandomUnitFromDragonThreatList())
+ {
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveFollow(chaseTarget, 0.02f, 0.0f);
+ _targetGUID = chaseTarget->GetGUID();
+ context.Repeat(15s, 30s);
+ }
+ else
+ {
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveRandom(25.0f);
+ context.Repeat(2500ms);
+ }
+
+ // Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it
+ me->SetWalk(true);
+ me->SetSpeed(MOVE_WALK, 0.75f);
+ });
+ }
+
+ void SetGUID(ObjectGuid guid, int32 type) override
+ {
+ if (type == GUID_DRAGON)
+ {
+ _dragonGUID = guid;
+ }
+ else if (type == GUID_FOG_TARGET)
+ {
+ if (guid == _targetGUID)
+ {
+ ScheduleEvents();
+ }
+ }
+ }
+
+ Unit* GetRandomUnitFromDragonThreatList()
+ {
+ if (Creature* dragon = ObjectAccessor::GetCreature(*me, _dragonGUID))
+ {
+ if (dragon->GetAI())
+ {
+ return dragon->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true);
+ }
+ }
+
+ return nullptr;
}
void UpdateAI(uint32 diff) override
@@ -181,31 +251,13 @@ public:
if (!UpdateVictim())
return;
- if (!_roamTimer)
- {
- // Chase target, but don't attack - otherwise just roam around
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
- {
- _roamTimer = urand(15000, 30000);
- me->GetMotionMaster()->Clear(false);
- me->GetMotionMaster()->MoveChase(target, 0.2f);
- }
- else
- {
- _roamTimer = 2500;
- me->GetMotionMaster()->Clear(false);
- me->GetMotionMaster()->MoveRandom(25.0f);
- }
- // Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it
- me->SetWalk(true);
- me->SetSpeed(MOVE_WALK, 0.75f);
- }
- else
- _roamTimer -= diff;
+ _scheduler.Update(diff);
}
private:
- uint32 _roamTimer;
+ ObjectGuid _targetGUID;
+ ObjectGuid _dragonGUID;
+ TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -609,6 +661,7 @@ public:
++_stage;
}
}
+
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
@@ -687,6 +740,17 @@ public:
{
PrepareSpellScript(spell_dream_fog_sleep_SpellScript);
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ if (Unit* target = GetHitUnit())
+ {
+ caster->GetAI()->SetGUID(target->GetGUID(), GUID_FOG_TARGET);
+ }
+ }
+ }
+
void FilterTargets(std::list& targets)
{
targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SLEEP));
@@ -694,6 +758,7 @@ public:
void Register() override
{
+ OnEffectHitTarget += SpellEffectFn(spell_dream_fog_sleep_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dream_fog_sleep_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
diff --git a/src/server/scripts/World/npc_stave_of_ancients.cpp b/src/server/scripts/World/npc_stave_of_ancients.cpp
index e8d32856f..8ce88a0d5 100644
--- a/src/server/scripts/World/npc_stave_of_ancients.cpp
+++ b/src/server/scripts/World/npc_stave_of_ancients.cpp
@@ -394,6 +394,14 @@ public:
DoMeleeAttackIfReady();
}
+ void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (attacker == me)
+ {
+ me->LowerPlayerDamageReq(damage);
+ }
+ }
+
void SpellHit(Unit* /*Caster*/, SpellInfo const* Spell) override
{
uint32 serpentStings[12] = { 1978, 13549, 13550, 13551, 13552, 13553, 13554, 13555, 25295, 27016, 49000, 49001 };
@@ -1173,6 +1181,14 @@ public:
}
}
+ void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (attacker == me)
+ {
+ me->LowerPlayerDamageReq(damage);
+ }
+ }
+
void ScheduleEncounterStart(ObjectGuid playerGUID)
{
PrepareForEncounter();
diff --git a/src/server/shared/DataStores/DBCEnums.h b/src/server/shared/DataStores/DBCEnums.h
index ff66f1a8e..525cf05d8 100644
--- a/src/server/shared/DataStores/DBCEnums.h
+++ b/src/server/shared/DataStores/DBCEnums.h
@@ -415,33 +415,33 @@ enum TotemCategoryType
// SummonProperties.dbc, col 1
enum SummonPropGroup
{
- SUMMON_PROP_GROUP_UNKNOWN1 = 0, // 1160 spells in 3.0.3
- SUMMON_PROP_GROUP_UNKNOWN2 = 1, // 861 spells in 3.0.3
- SUMMON_PROP_GROUP_PETS = 2, // 52 spells in 3.0.3, pets mostly
- SUMMON_PROP_GROUP_CONTROLLABLE = 3, // 13 spells in 3.0.3, mostly controllable
- SUMMON_PROP_GROUP_UNKNOWN3 = 4 // 86 spells in 3.0.3, taxi/mounts
+ SUMMON_PROP_GROUP_NONE = 0, // 1160 spells in 3.0.3
+ SUMMON_PROP_GROUP_GUARDIAN = 1, // 861 spells in 3.0.3 TODO: Needs implementation
+ SUMMON_PROP_GROUP_PETS = 2, // 52 spells in 3.0.3, pets mostly TODO: Needs implementation
+ SUMMON_PROP_GROUP_CONTROLLABLE = 3, // 13 spells in 3.0.3, mostly controllable TODO: Needs implementation
+ SUMMON_PROP_GROUP_VEHICLE = 4 // 86 spells in 3.0.3, taxi/mounts TODO: Needs implementation
};
// SummonProperties.dbc, col 5
enum SummonPropFlags
{
- SUMMON_PROP_FLAG_NONE = 0x00000000, // 1342 spells in 3.0.3
- SUMMON_PROP_FLAG_UNK1 = 0x00000001, // 75 spells in 3.0.3, something unfriendly
- SUMMON_PROP_FLAG_UNK2 = 0x00000002, // 616 spells in 3.0.3, something friendly
- SUMMON_PROP_FLAG_UNK3 = 0x00000004, // 22 spells in 3.0.3, no idea...
- SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH = 0x00000008, // 49 spells in 3.0.3, some mounts
- SUMMON_PROP_FLAG_PERSONAL_SPAWN = 0x00000010, // 25 spells in 3.0.3, quest related?
- SUMMON_PROP_FLAG_UNK6 = 0x00000020, // 0 spells in 3.3.5, unused
- SUMMON_PROP_FLAG_UNK7 = 0x00000040, // 12 spells in 3.0.3, no idea
- SUMMON_PROP_FLAG_UNK8 = 0x00000080, // 4 spells in 3.0.3, no idea
- SUMMON_PROP_FLAG_UNK9 = 0x00000100, // 51 spells in 3.0.3, no idea, many quest related
- SUMMON_PROP_FLAG_UNK10 = 0x00000200, // 51 spells in 3.0.3, something defensive
- SUMMON_PROP_FLAG_UNK11 = 0x00000400, // 3 spells, requires something near?
- SUMMON_PROP_FLAG_UNK12 = 0x00000800, // 30 spells in 3.0.3, no idea
- SUMMON_PROP_FLAG_UNK13 = 0x00001000, // Lightwell, Jeeves, Gnomish Alarm-o-bot, Build vehicles(wintergrasp)
- SUMMON_PROP_FLAG_UNK14 = 0x00002000, // Guides, player follows
- SUMMON_PROP_FLAG_UNK15 = 0x00004000, // Force of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental
- SUMMON_PROP_FLAG_UNK16 = 0x00008000, // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related?
+ SUMMON_PROP_FLAG_NONE = 0x00000000, // 1342 spells in 3.0.3
+ SUMMON_PROP_FLAG_ATTACK_SUMMONER = 0x00000001, // 75 spells in 3.0.3, something unfriendly TODO: Needs implementation
+ SUMMON_PROP_FLAG_ASSIST_COMBAT_SUMMON = 0x00000002, // 616 spells in 3.0.3, something friendly TODO: Needs implementation
+ SUMMON_PROP_FLAG_USE_LEVEL_OFFSET = 0x00000004, // 22 spells in 3.0.3, no idea... TODO: Needs implementation
+ SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH = 0x00000008, // 49 spells in 3.0.3, some mounts TODO: Needs implementation
+ SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SUMMONER = 0x00000010, // 25 spells in 3.0.3, quest related? TODO: Needs implementation
+ SUMMON_PROP_FLAG_CANNOT_DISMISS_PET = 0x00000020, // 0 spells in 3.3.5, unused TODO: Needs implementation
+ SUMMON_PROP_FLAG_USE_DEMON_TIMEOUT = 0x00000040, // 12 spells in 3.0.3, no idea TODO: Needs implementation
+ SUMMON_PROP_FLAG_UNLIMITED_SUMMONS = 0x00000080, // 4 spells in 3.0.3, no idea TODO: Needs implementation
+ SUMMON_PROP_FLAG_USE_CREATURE_LEVEL = 0x00000100, // 51 spells in 3.0.3, no idea, many quest related TODO: Needs implementation
+ SUMMON_PROP_FLAG_JOIN_SUMMONER_SPAWN_GROUP = 0x00000200, // 51 spells in 3.0.3, something defensive TODO: Needs implementation
+ SUMMON_PROP_FLAG_DO_NOT_TOGGLE = 0x00000400, // 3 spells, requires something near? TODO: Needs implementation
+ SUMMON_PROP_FLAG_DESPAWN_WHEN_EXPIRED = 0x00000800, // 30 spells in 3.0.3, no idea TODO: Needs implementation
+ SUMMON_PROP_FLAG_USE_SUMMONER_FACTION = 0x00001000, // Lightwell, Jeeves, Gnomish Alarm-o-bot, Build vehicles(wintergrasp) TODO: Needs implementation
+ SUMMON_PROP_FLAG_DO_NOT_FOLLOW_MOUNTED_SUMMONER = 0x00002000, // Guides, player follows TODO: Needs implementation
+ SUMMON_PROP_FLAG_SAVE_PET_AUTOCAST = 0x00004000, // Force of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental TODO: Needs implementation
+ SUMMON_PROP_FLAG_IGNORE_SUMMONER_PHASE = 0x00008000, // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related? TODO: Needs implementation
};
enum VehicleSeatFlags
diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h
index 249167c0e..0370f9c95 100644
--- a/src/server/shared/DataStores/DBCStructure.h
+++ b/src/server/shared/DataStores/DBCStructure.h
@@ -22,6 +22,7 @@
#include "Define.h"
#include "SharedDefines.h"
#include "Util.h"
+#include
#include