aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--sql/updates/world/2014_09_08_00_world_conditions.sql2
-rw-r--r--sql/updates/world/2014_09_09_00_world_sai.sql162
-rw-r--r--sql/updates/world/2014_09_09_01_world_sai.sql8
-rw-r--r--sql/updates/world/2014_09_09_03_world_misc.sql14
-rw-r--r--sql/updates/world/2014_09_10_00_world_locales_creature_335.sql44
-rw-r--r--sql/updates/world/2014_09_10_01_world_misc.sql10
-rw-r--r--sql/updates/world/2014_09_10_02_world_locales_quest_335.sql7
-rw-r--r--sql/updates/world/2014_09_11_00_world_conditions.sql1
-rw-r--r--sql/updates/world/2014_09_11_01_world_creature_template.sql1
-rw-r--r--sql/updates/world/2014_09_11_02_world_misc.sql123
-rw-r--r--sql/updates/world/2014_09_11_03_world_misc.sql5
-rw-r--r--sql/updates/world/2014_09_12_00_world_misc.sql34
-rw-r--r--sql/updates/world/2014_09_12_01_world_misc.sql4
-rw-r--r--sql/updates/world/2014_09_12_02_world_misc.sql9
-rw-r--r--src/server/authserver/CMakeLists.txt1
-rw-r--r--src/server/authserver/Main.cpp13
-rw-r--r--src/server/authserver/Server/AuthSession.cpp121
-rw-r--r--src/server/authserver/Server/AuthSession.h13
-rw-r--r--src/server/authserver/Server/AuthSocketMgr.h61
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h2
-rw-r--r--src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp7
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp6
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Groups/Group.h14
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp24
-rw-r--r--src/server/game/Loot/LootMgr.cpp7
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSocket.cpp141
-rw-r--r--src/server/game/Server/WorldSocket.h76
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp115
-rw-r--r--src/server/game/Server/WorldSocketMgr.h66
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp130
-rw-r--r--src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp133
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp4
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp1
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp6
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp98
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp18
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp142
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp6
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp129
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h70
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp282
-rw-r--r--src/server/scripts/Kalimdor/zone_the_barrens.cpp8
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_eck.cpp146
-rw-r--r--src/server/scripts/Northrend/Gundrak/gundrak.h6
-rw-r--r--src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp21
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp182
-rw-r--r--src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp2
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp1
-rw-r--r--src/server/scripts/Outland/zone_shattrath_city.cpp69
-rw-r--r--src/server/scripts/World/npcs_special.cpp101
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp6
-rw-r--r--src/server/shared/Networking/AsyncAcceptor.h55
-rw-r--r--src/server/shared/Networking/MessageBuffer.h67
-rw-r--r--src/server/shared/Networking/NetworkThread.h166
-rw-r--r--src/server/shared/Networking/Socket.h255
-rw-r--r--src/server/shared/Networking/SocketMgr.h111
-rw-r--r--src/server/worldserver/Main.cpp18
63 files changed, 2045 insertions, 1291 deletions
diff --git a/.travis.yml b/.travis.yml
index f6e085b58be..e8ff00f425f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ install:
- mysql -uroot -e 'create database test_mysql;'
- mkdir bin
- cd bin
- - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=1 -DUSE_COREPCH=0 -DUSE_SCRIPTPCH=0 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release
+ - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release
script:
- cd ..
diff --git a/sql/updates/world/2014_09_08_00_world_conditions.sql b/sql/updates/world/2014_09_08_00_world_conditions.sql
index 492d6b5a981..469f5d5aecd 100644
--- a/sql/updates/world/2014_09_08_00_world_conditions.sql
+++ b/sql/updates/world/2014_09_08_00_world_conditions.sql
@@ -8,7 +8,7 @@ UPDATE `quest_template` SET `PrevQuestId`=0 WHERE `Id` IN(13682,13809); -- Clea
UPDATE `quest_template` SET `PrevQuestId`=0 WHERE `Id` IN(13788,13812); -- Clear prev quest from Threat from above as this needs more than one quest complete to become available so will be dealt with by conditions instead
UPDATE `quest_template` SET `PrevQuestId`=0 WHERE `Id`=13664; -- Clear prev quest for the Black Knight's Fall as this quest had multiple requirements and will be dealt with by conditions instead
-DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(19,20) AND `SourceId` IN(13794,13795,13682,13809,13788,13812,13664);
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(19,20) AND `SourceEntry` IN(13794,13795,13682,13809,13788,13812,13664);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(19, 0, 13794, 0, 0, 8, 0, 13737, 0, 0, 0, 0, 0, '', 'Eadric the Pure requires A Champion Rises'),
(20, 0, 13794, 0, 0, 8, 0, 13737, 0, 0, 0, 0, 0, '', 'Eadric the Pure requires A Champion Rises'),
diff --git a/sql/updates/world/2014_09_09_00_world_sai.sql b/sql/updates/world/2014_09_09_00_world_sai.sql
new file mode 100644
index 00000000000..4037b19df09
--- /dev/null
+++ b/sql/updates/world/2014_09_09_00_world_sai.sql
@@ -0,0 +1,162 @@
+SET @CGUID := 29979;
+
+DELETE FROM `creature_text` WHERE `entry` IN(26097,25380,25602,25834,25849,25983,25380,25401);
+DELETE FROM `creature_text` WHERE `entry` =23837 AND `groupid`=1;
+
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(26097, 0, 0, 'Thank you for saving us. We accidentally uncovered the pieces of Gearmaster Mechazod and reassembled him.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25205),
+(26097, 1, 0, 'In return, he ''de-cursed'' us, saying that we were being ''fixed'' by returning us to the state of being mechanical constructs.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25207),
+(26097, 2, 0, 'He claims that all creations of the Titans fall prey to what he calls, ''The Curse of Flesh''. He says that the original gnomes were once mechagnomes.', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25208),
+(26097, 3, 0, 'He''s quite insane! Someone must put a stop to his madness before it''s too late for everyone!', 12, 0, 100, 0, 0, 0, 'Fizzcrank Gnome Ghost',25209),
+(25602, 0, 0, 'Now, $n, let us release their souls and hear what they have to say.', 12, 0, 100, 1, 0, 0, 'Greatmother Taiga',25204),
+(25602, 1, 0, 'This is dire news indeed!', 12, 0, 100, 1, 0, 0, 'Greatmother Taiga',25211),
+(25380, 0, 0, 'And remember, $n, the bloodspore powder can be used to weaken all magnataur in Gammoth.', 15, 0, 100, 0, 0, 0, 'Primal Mighthorn',24994),
+(25834, 0, 0, 'You were looking for me, child? Why do you come to kill me, $n? I only wish to help.', 12, 0, 100, 6, 0, 0, 'Gearmaster Mechazod',25024),
+(25834, 1, 0, 'Now that I have been reassembled, we can return to a time of perfection... the time of the Titans!', 12, 0, 100, 1, 0, 0, 'Gearmaster Mechazod',25025),
+(25834, 2, 0, 'But, I can see it in your eyes, hear it in your pulse rate. You would destroy me despite my offer of immortality!', 12, 0, 100, 25, 0, 0, 'Gearmaster Mechazod',25026),
+(25834, 3, 0, 'Very well. It saddens me that it has come to this. I look upon all of you as if you were my children. I will slay you if I must!', 12, 0, 100, 25, 0, 0, 'Gearmaster Mechazod',25027),
+(23837, 1, 0, 'There is a noise from behind you!', 41, 0, 100, 0, 0, 0, 'ELM General Purpose Bunny',25215),
+(25849, 0, 0, 'It''s really going to work this time... right?', 12, 0, 100, 6, 0, 0, 'Fezzix Geartwist',25143),
+(25849, 1, 0, 'It works, Dorain! Look! It actually works...', 12, 0, 100, 4, 0, 0, 'Fezzix Geartwist',25148),
+(25849, 2, 0, 'Here I goooooooooo!', 12, 0, 100, 0, 0, 0, 'Fezzix Geartwist',25150),
+(25849, 3, 0, 'OUCH!', 12, 0, 100, 0, 0, 0, 'Fezzix Geartwist',25151),
+(25849, 4, 0, 'I give up! So much for goblin ingenuity!', 12, 0, 100, 5, 0, 0, 'Fezzix Geartwist',25152),
+(25983, 0, 0, 'Fezzix, I think we''ve solved your little engine problem.', 12, 0, 100, 1, 0, 0, 'Dorain Frosthoof',25132),
+(25401, 0, 0, '%s armed.', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24590),
+(25401, 1, 0, 'Detonation in 5...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24591),
+(25401, 2, 0, '4...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24592),
+(25401, 3, 0, '3...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24593),
+(25401, 4, 0, '2...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24594),
+(25401, 5, 0, '1...', 16, 0, 100, 0, 0, 0, 'Seaforium Depth Charge',24595);
+
+UPDATE `creature_template` SET `unit_flags`=33024 WHERE `entry`=25834;
+UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` IN(26097,35426,25602,25983,25849,25834,25380,25401);
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN(26097,35426,25602,25983,25849,25834,25380,25401) AND `source_type`=0;
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN(2560200,2598300,2584900,2584901,2583400,2540100) 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
+(25401, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - On Just Summoned - Store Targetlist'),
+(25401, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2540100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - On Just Summoned - Run Script'),
+(25401, 0, 2, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45506, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (SW) '),
+(25401, 0, 3, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45508, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (SE)'),
+(25401, 0, 4, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45510, 2, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (NW)'),
+(25401, 0, 5, 0, 1, 2, 100, 1, 100, 100, 0, 0, 11, 45512, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - OOC (Phase 2/No repeat) - Cast Nerub ar Sinkhole Credit (NE)'),
+(25834, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Just Summoned - Store Targetlist'),
+(25834, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 80, 2583400, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Just Summoned - Run Script'),
+(25834, 0, 2, 0, 7, 0, 100, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - On Evade Despawn'),
+(25380, 0, 0, 0, 19, 0, 100, 0, 11721, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Primal Mighthorn - On Quest Accept (Gammothra the Tormentor) - Say Line 1'),
+(26097, 0, 0, 0, 1, 0, 100, 1, 1000, 1000, 0, 0, 11, 35426, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Gnome Ghost - OOC (No Repeat) - Cast Arcane Explosion Visual'),
+(26097, 0, 1, 0, 54, 0, 100, 0, 0, 0, 0, 0, 11, 32423, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Gnome Ghost - On Just Summoned - Cast Blue Radiation'),
+(25602, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Reset Set Phase 1'),
+(25602, 0, 1, 2, 20, 1, 100, 0, 11899, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Quest Reward (Souls of the Decursed) - Say Line 1 (Phase 1)'),
+(25602, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2560200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - On Quest Reward (Souls of the Decursed) - Run Script (Phase 1)'),
+(25983, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - On Reset Set Phase 1'),
+(25983, 0, 1, 2, 20, 1, 100, 0, 11893, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - - On Quest Reward (The Power of the Elements) - Say Line 1'),
+(25983, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2598300, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - - On Quest Reward (The Power of the Elements) - Run Script'),
+(25849, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - On Reset Set Phase 1'),
+(25849, 0, 1, 2, 20, 1, 100, 0, 11894, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Quest Reward (Patching Up) - Say Line 1'),
+(25849, 0, 2, 0, 61, 1, 100, 0, 0, 0, 0, 0, 80, 2584900, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Quest Reward (Patching Up) - Run Script'),
+(25849, 0, 3, 0, 40, 2, 100, 0, 11, 25849, 0, 0, 80, 2584901, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Reached WP11 - Run Script (Phase 2)'),
+(25849, 0, 4, 5, 40, 2, 100, 0, 12, 25849, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - - On Reached WP12 - Set Phase 1'),
+(25849, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 4.06662, 'Fezzix Geartwist - - On Reached WP12 - Set Orientation'),
+(2540100, 9, 0, 0, 0, 0, 100, 0, 0, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 0'),
+(2540100, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 1'),
+(2540100, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 3, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 5, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Say Line 2'),
+(2540100, 9, 6, 0, 0, 0, 100, 0, 900, 900, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Set Phase 2'),
+(2540100, 9, 7, 0, 0, 0, 100, 0, 100, 100, 0, 0, 11, 45502, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Cast Seaforium Depth Charge Explosion'),
+(2540100, 9, 8, 0, 0, 0, 100, 0, 500, 500, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Seaforium Depth Charge - Script - Cast Seaforium Depth Charge Explosion'),
+(2584900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Set Phase 2'),
+(2584900, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 12, 26040, 1, 13000, 0, 0, 0, 8, 0, 0, 0, 3481.329, 4099.854, 17.83902, 3.351032, 'Fezzix Geartwist - Script - Spawn Fezzixs Flying Machine'),
+(2584900, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60069, 188087, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage A'),
+(2584900, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60080, 188088, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage B'),
+(2584900, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 70, 60, 0, 0, 0, 0, 0, 14, 60095, 188089, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Despawn Wreckage C'),
+(2584900, 9, 5, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Say Line 2'),
+(2584900, 9, 6, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 43, 0, 22719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Mount Display ID 22719'),
+(2584900, 9, 7, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Say Line 3'),
+(2584900, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Set Fly On'),
+(2584900, 9, 9, 0, 0, 0, 100, 0, 0, 0, 0, 0, 53, 0, 25849, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script - Start WP'),
+(2583400, 9, 0, 0, 0, 0, 100, 0, 500, 500, 0, 0, 11, 34427, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Cast Ethereal Teleport'),
+(2583400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 10, @CGUID+0, 23837, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line on Bunny'),
+(2583400, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 1'),
+(2583400, 9, 3, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Set Orientation'),
+(2583400, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 2'),
+(2583400, 9, 5, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 3'),
+(2583400, 9, 6, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Say Line 4'),
+(2583400, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 19, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Remove Unit Flag (Immune to PC)'),
+(2583400, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gearmaster Mechazod - Script - Start Attack'),
+(2584901, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 46419, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Cast Cosmetic - Explosion'),
+(2584901, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Dismount'),
+(2584901, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Turn Fly Off'),
+(2584901, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 11, 42963, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Cast Cosmetic - Combat Knockdown Self'),
+(2584901, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Say Line 4'),
+(2584901, 9, 5, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Fezzix Geartwist - Script 2 - Say Line 5'),
+(2598300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Set Phase 2'),
+(2598300, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 11, 46399, 0, 0, 0, 0, 0, 14, 113431, 26041, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Cast Energy Transfer'),
+(2598300, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Dorain Frosthoof - Script - Set Phase 1'),
+(2560200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Set Phase 2'),
+(2560200, 9, 1, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 11, 28892, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Cast Nature Channeling'),
+(2560200, 9, 2, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 28, 28892, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Remove Aura Nature Channeling'),
+(2560200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Summon Group 0'),
+(2560200, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 1 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 5, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 2 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 6, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 3 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 7, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 26097, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 4 on Closest Fizzcrank Gnome Ghost'),
+(2560200, 9, 8, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 5, 3, 0, 0, 0, 0, 0, 9, 26097, 0, 200, 0, 0, 0, 0, 'Greatmother Taiga - Script - Play emote OneShotWave on all Fizzcrank Gnome Ghost'),
+(2560200, 9, 9, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Say Line 2'),
+(2560200, 9, 10, 0, 0, 0, 100, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Greatmother Taiga - Script - Set Phase 1');
+
+
+DELETE FROM `creature_summon_groups` WHERE `summonerId`=25602;
+INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`) VALUES
+(25602, 0, 0, 26097, 3483.047, 4114.145, 18.48475, 3.193953, 1, 40000),
+(25602, 0, 0, 26097, 3486.638, 4116.401, 18.48475, 3.403392, 1, 40000),
+(25602, 0, 0, 26097, 3483.65, 4112.257, 18.48475, 2.9147, 1, 40000),
+(25602, 0, 0, 26097, 3481.733, 4118.205, 18.48475, 3.926991, 1, 40000),
+(25602, 0, 0, 26097, 3485.337, 4117.493, 18.48475, 3.543018, 1, 40000),
+(25602, 0, 0, 26097, 3482.166, 4116.395, 18.48475, 3.612832, 1, 40000),
+(25602, 0, 0, 26097, 3485.657, 4113.342, 18.48475, 3.124139, 1, 40000),
+(25602, 0, 0, 26097, 3483.949, 4118.282, 18.48475, 3.682645, 1, 40000),
+(25602, 0, 0, 26097, 3484.028, 4115.051, 18.48475, 3.316126, 1, 40000),
+(25602, 0, 0, 26097, 3484.057, 4116.235, 18.48474, 3.560472, 1, 40000);
+
+
+DELETE FROM `waypoints` WHERE `entry` =25849;
+
+INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES
+(25849, 1,3476.835, 4099.595, 20.46597, 'Fezzix Geartwist'),
+(25849, 2,3469.259, 4098.425, 23.37573, 'Fezzix Geartwist'),
+(25849, 3,3464.057, 4092.921, 28.09206, 'Fezzix Geartwist'),
+(25849, 4,3468.28, 4083.907, 34.53652, 'Fezzix Geartwist'),
+(25849, 5,3471.045, 4079.119, 38.06437, 'Fezzix Geartwist'),
+(25849, 6,3476.159, 4076.131, 41.48104, 'Fezzix Geartwist'),
+(25849, 7,3483.686, 4077.679, 42.78663, 'Fezzix Geartwist'),
+(25849, 8,3487.812, 4082.535, 42.78663, 'Fezzix Geartwist'),
+(25849, 9,3488.05, 4090.021, 42.78663, 'Fezzix Geartwist'),
+(25849, 10,3486.571, 4098.099, 42.78663, 'Fezzix Geartwist'),
+(25849, 11,3479.899, 4100.219, 42.78663, 'Fezzix Geartwist'),
+(25849, 12,3477.16, 4103.97, 17.9091, 'Fezzix Geartwist');
+
+DELETE FROM `creature` WHERE `guid`=@CGUID+0;
+INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES
+(@CGUID+0, 23837, 571, 1, 1, 4000.194, 4853.576, 26.05447, 5.585053, 120, 0, 0); -- 23837 (Area: 3537)
+
+DELETE FROM `event_scripts` WHERE `id`=17209;
+INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES
+(17209, 3, 10, 25834, 3000000, 0, 4004.175, 4850.362, 26.05081,2.391101);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=45502;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 2, 45502, 0, 0, 31, 0, 3, 25402, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (South)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25403, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (East)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25404, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (West)'),
+(13, 2, 45502, 0, 0, 31, 0, 3, 25405, 0, 1, 0, 0, '', 'Seaforium Depth Charge Explosion does not knock back Nerub ar Sinkhole (North)');
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=25401;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(22, 3, 25401, 0, 0, 29, 1, 25402, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (South) within 20 yards'),
+(22, 4, 25401, 0, 0, 29, 1, 25403, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (East) within 20 yards'),
+(22, 5, 25401, 0, 0, 29, 1, 25404, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (West) within 20 yards'),
+(22, 6, 25401, 0, 0, 29, 1, 25405, 20, 0, 0, 0, 0, '', 'Seaforium Depth Charge - Only run SAI if Nerub ar Sinkhole (North) within 20 yards');
diff --git a/sql/updates/world/2014_09_09_01_world_sai.sql b/sql/updates/world/2014_09_09_01_world_sai.sql
new file mode 100644
index 00000000000..b286b0ad03f
--- /dev/null
+++ b/sql/updates/world/2014_09_09_01_world_sai.sql
@@ -0,0 +1,8 @@
+UPDATE `creature_template` SET `ainame`='SmartAI', `scriptname`='' WHERE `entry` =25969;
+DELETE FROM `smart_scripts` WHERE `entryorguid` =25969 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
+(25969, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 11, 46340, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Just Summoned - Cast Crates Carried'),
+(25969, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Just Summoned - Set Passive'),
+(25969, 0, 2, 0, 32, 0, 100, 0, 50, 20000, 3000, 5000, 11, 46342, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Damage - Cast Drop Crate'),
+(25969, 0, 3, 0, 23, 0, 100, 0, 46340, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Jenny - On Has No Aura (Crates Carried) - Despawn'),
+(25969, 0, 4, 0, 75, 0, 100, 0, 0, 25849, 30, 0, 11, 46358, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 'Jenny - Within 30 yards of Fezzix Geartwist - Give Kill credit');
diff --git a/sql/updates/world/2014_09_09_03_world_misc.sql b/sql/updates/world/2014_09_09_03_world_misc.sql
new file mode 100644
index 00000000000..0936e6087a0
--- /dev/null
+++ b/sql/updates/world/2014_09_09_03_world_misc.sql
@@ -0,0 +1,14 @@
+DELETE FROM `creature_text` WHERE `entry` =19228 AND `groupid`IN(47,48);
+DELETE FROM `creature_text` WHERE `entry` =19228 AND `groupid`=0 AND `id`=4;
+
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(19228, 0, 4, 'Whoa! Is all that applause for me? Thanks for coming out!', 12, 0, 100, 6, 0, 0, 'Perry Gatner',16326),
+(19228, 47, 0, 'Used to be you couldn''t trust a goblin...', 12, 0, 100, 1, 0, 0, 'Perry Gatner',16671),
+(19228, 48, 0, 'Who am I kiddin''? If you trade with goblins you''d better have iron plating in your coinpurse.', 12, 0, 100, 6, 0, 0, 'Perry Gatner',16672);
+
+DELETE FROM `smart_scripts` WHERE `entryorguid`=1927115 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
+(1927115, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 47, 0, 0, 0, 0, 0, 19, 19228, 0, 0, 0, 0, 0, 0, 'Albert Quarksprocket - - Script 15 - Say Line 47 (Perry Gatner'),
+(1927115, 9, 1, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 1, 48, 0, 0, 0, 0, 0, 19, 19228, 0, 0, 0, 0, 0, 0, 'Albert Quarksprocket - - Script 15 - Say Line 48 (Perry Gatner');
+
+UPDATE `smart_scripts` SET `action_param3`=192715 WHERE `entryorguid`=19271 AND `source_type`=0 AND `id`=13;
diff --git a/sql/updates/world/2014_09_10_00_world_locales_creature_335.sql b/sql/updates/world/2014_09_10_00_world_locales_creature_335.sql
new file mode 100644
index 00000000000..86f0e99b219
--- /dev/null
+++ b/sql/updates/world/2014_09_10_00_world_locales_creature_335.sql
@@ -0,0 +1,44 @@
+-- BLIZZ, CONSISTENCY PLS.
+UPDATE `locales_creature` SET `name_loc1` = REPLACE(`name_loc1`, "[4.x 미사용]", "");
+UPDATE `locales_creature` SET `name_loc1` = REPLACE(`name_loc1`, "[4.x 폐기] ", "");
+UPDATE `locales_creature` SET `name_loc1` = REPLACE(`name_loc1`, " (4.x 미사용)", "");
+UPDATE `locales_creature` SET `name_loc1` = REPLACE(`name_loc1`, "zzOLD", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
+
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[DEPRECATED 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[DEPRECATED 4.0] ", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[DEPRECATED 4.x]", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[DEPRECATED 4.0]", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[INUTILISÉ 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[Inutilisé pour 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[INUTILISÉ pour 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc2` = REPLACE(`name_loc2`, "[VIEUX]", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
+
+UPDATE `locales_creature` SET `name_loc3` = REPLACE(`name_loc3`, "[Deprecated for 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc3` = REPLACE(`name_loc3`, "[DEPRECATED 4.0] ", "");
+UPDATE `locales_creature` SET `name_loc3` = REPLACE(`name_loc3`, "[INUTILISÉ 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc3` = REPLACE(`name_loc3`, "[Inutilisé pour 4.x] ", "");
+
+UPDATE `locales_creature` SET `name_loc5` = REPLACE(`name_loc5`, "[Deprecated for 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc5` = REPLACE(`name_loc5`, "[Deprecated for 4.x]", "");
+UPDATE `locales_creature` SET `name_loc5` = REPLACE(`name_loc5`, "[UNUSED 4.x ]", "");
+UPDATE `locales_creature` SET `name_loc5` = REPLACE(`name_loc5`, "(Deprecated in 4.x)", "");
+UPDATE `locales_creature` SET `name_loc5` = REPLACE(`name_loc5`, "zzOLD", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
+
+UPDATE `locales_creature` SET `name_loc6` = REPLACE(`name_loc6`, "[Deprecated for 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc6` = REPLACE(`name_loc6`, "[Deprecated for 4.x]", "");
+UPDATE `locales_creature` SET `name_loc6` = REPLACE(`name_loc6`, "[UNUSED 4.x ]", "");
+UPDATE `locales_creature` SET `name_loc6` = REPLACE(`name_loc6`, " (Deprecated in 4.x)", "");
+UPDATE `locales_creature` SET `name_loc6` = REPLACE(`name_loc6`, "zzOLD", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
+
+UPDATE `locales_creature` SET `name_loc7` = REPLACE(`name_loc7`, "[Deprecated for 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc7` = REPLACE(`name_loc7`, "[Deprecated for 4.x]", "");
+UPDATE `locales_creature` SET `name_loc7` = REPLACE(`name_loc7`, "[UNUSED 4.x ]", "");
+UPDATE `locales_creature` SET `name_loc7` = REPLACE(`name_loc7`, " (Deprecated in 4.x)", "");
+UPDATE `locales_creature` SET `name_loc7` = REPLACE(`name_loc7`, "zzOLD", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
+
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, "[Deprecated for 4.x] ", "");
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, "[Deprecated for 4.x]", "");
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, "[UNUSED 4.x ]", "");
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, "[UNUSED] ", "") WHERE `entry` IN (4318, 4115);
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, " (Deprecated in 4.x)", "");
+UPDATE `locales_creature` SET `name_loc8` = REPLACE(`name_loc8`, "zzOLD", "") WHERE `entry` NOT IN (22970, 22971, 15384, 21122);
diff --git a/sql/updates/world/2014_09_10_01_world_misc.sql b/sql/updates/world/2014_09_10_01_world_misc.sql
new file mode 100644
index 00000000000..0aaec188e09
--- /dev/null
+++ b/sql/updates/world/2014_09_10_01_world_misc.sql
@@ -0,0 +1,10 @@
+UPDATE `creature_template` SET `AIName`='' WHERE `entry`=18490;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=18490 AND `source_type`=0;
+UPDATE `creature_template` SET `unit_flags`=536871680, `unit_flags2`=2049, `dynamicflags`=0 WHERE `entry`=18490;
+UPDATE `creature_template_addon` SET `auras`='29266 32423' WHERE `entry`=18490;
+
+DELETE FROM `spell_area` WHERE `spell`=32407;
+INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES
+(32407, 3674, 0, 0, 0, 0, 2, 1, 64, 11);
+
+UPDATE `smart_scripts` SET `action_param3`=1927115 WHERE `entryorguid`=19271 AND `source_type`=0 AND `id`=13;
diff --git a/sql/updates/world/2014_09_10_02_world_locales_quest_335.sql b/sql/updates/world/2014_09_10_02_world_locales_quest_335.sql
new file mode 100644
index 00000000000..bf532ef130a
--- /dev/null
+++ b/sql/updates/world/2014_09_10_02_world_locales_quest_335.sql
@@ -0,0 +1,7 @@
+UPDATE `locales_quest` SET `Title_loc2` = REPLACE(`Title_loc2`, "[PÉRIMÉ 4.x]", "");
+UPDATE `locales_quest` SET `Title_loc6` = REPLACE(`Title_loc6`, "[DEPRECATED in 4.x] ", "");
+UPDATE `locales_quest` SET `Title_loc6` = REPLACE(`Title_loc6`, "[DEPRECATED 4.x] ", "");
+UPDATE `locales_quest` SET `Title_loc7` = REPLACE(`Title_loc7`, "[DEPRECATED in 4.x] ", "");
+UPDATE `locales_quest` SET `Title_loc7` = REPLACE(`Title_loc7`, "[DEPRECATED 4.x] ", "");
+UPDATE `locales_quest` SET `Title_loc8` = REPLACE(`Title_loc8`, "[DEPRECATED in 4.x] ", "");
+UPDATE `locales_quest` SET `Title_loc8` = REPLACE(`Title_loc8`, "[DEPRECATED 4.x] ", "");
diff --git a/sql/updates/world/2014_09_11_00_world_conditions.sql b/sql/updates/world/2014_09_11_00_world_conditions.sql
new file mode 100644
index 00000000000..c66d570900a
--- /dev/null
+++ b/sql/updates/world/2014_09_11_00_world_conditions.sql
@@ -0,0 +1 @@
+UPDATE `conditions` SET `ConditionValue1` = 46 WHERE `SourceEntry` IN (63989, 63997, 63998) AND `SourceTypeOrReferenceId` = 18;
diff --git a/sql/updates/world/2014_09_11_01_world_creature_template.sql b/sql/updates/world/2014_09_11_01_world_creature_template.sql
new file mode 100644
index 00000000000..59d0bf9d3dd
--- /dev/null
+++ b/sql/updates/world/2014_09_11_01_world_creature_template.sql
@@ -0,0 +1 @@
+UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 29920;
diff --git a/sql/updates/world/2014_09_11_02_world_misc.sql b/sql/updates/world/2014_09_11_02_world_misc.sql
new file mode 100644
index 00000000000..5c5fab0ecfd
--- /dev/null
+++ b/sql/updates/world/2014_09_11_02_world_misc.sql
@@ -0,0 +1,123 @@
+-- Set Values
+-- Human
+SET @HRace := 1;
+SET @HFaction := 72;
+-- Dwarf
+SET @DWRace := 4;
+SET @DWFaction := 47;
+-- Orc
+SET @ORace := 2;
+SET @OFaction := 76;
+-- Tauren
+SET @TARace := 32;
+SET @TAFaction := 81;
+-- Night Elf
+SET @NRace := 8;
+SET @NFaction := 69;
+-- Undead
+SET @URace := 16;
+SET @UFaction := 68;
+-- Troll
+SET @TRRace := 128;
+SET @TRFaction := 530;
+-- Gnome (Milli Featherwhistle already uses db gossip and conditions as has sai script
+-- Blood Elf
+SET @BRace := 512;
+SET @BFaction := 911;
+-- Dreanei
+SET @DRRace := 1024;
+SET @DRFaction := 930;
+
+UPDATE `creature_template` SET `ScriptName`='' WHERE `entry` IN(384,1261,1460,2357,3662,3685,4730,4731,4885,7952,16264,17584);
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(14,15) AND `SourceGroup` IN(4004,4001,3161,3162,4006,4005,3185,8098,8213,3185);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(15, 4004, 0, 0, 0, 16, 0, @HRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Human'),
+(15, 4004, 0, 0, 1, 5, 0, @HFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Stormwind'),
+(15, 4001, 0, 0, 0, 16, 0, @DWRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Dwarf'),
+(15, 4001, 0, 0, 1, 5, 0, @DWFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Ironforge'),
+(15, 3161, 0, 0, 0, 16, 0, @ORace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Orc'),
+(15, 3161, 0, 0, 1, 5, 0, @OFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Orgrimmar'),
+(15, 4006, 0, 0, 0, 16, 0, @TARace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Tauren'),
+(15, 4006, 0, 0, 1, 5, 0, @TAFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Thunderbluff'),
+(15, 3185, 0, 0, 0, 16, 0, @NRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Night Elf'),
+(15, 3185, 0, 0, 1, 5, 0, @NFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Darnassus'),
+(15, 4005, 0, 0, 0, 16, 0, @URace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Undead'),
+(15, 4005, 0, 0, 1, 5, 0, @UFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Undercity'),
+(15, 3162, 0, 0, 0, 16, 0, @TRRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Troll'),
+(15, 3162, 0, 0, 1, 5, 0, @TRFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Sen Jin'),
+(15, 8098, 0, 0, 0, 16, 0, @BRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Blood Elf'),
+(15, 8098, 0, 0, 1, 5, 0, @BFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Silvermoon City'),
+(15, 8213, 0, 0, 0, 16, 0, @DRRace, 0, 0, 0, 0, 0, '', 'Gossip Option - Show Option if Player is Dreanei'),
+(15, 8213, 0, 0, 1, 5, 0, @DRFaction, 128, 0, 0, 0, 0, '', 'Gossip Option - Show Option if player is Exalted with Exodar'),
+
+(14, 4004, 4855, 0, 0, 16, 0, @HRace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is Human'),
+(14, 4004, 4855, 0, 0, 5, 0, @HFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Stormwind'),
+(14, 4006, 4840, 0, 0, 16, 0, @TARace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Tauren'),
+(14, 4006, 4840, 0, 0, 5, 0, @TAFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Thunderbluff'),
+(14, 8098, 10305, 0, 0, 16, 0, @BRace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Blood Elf'),
+(14, 8098, 10305, 0, 0, 5, 0, @BFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Silvermoon'),
+(14, 4005, 5840, 0, 0, 16, 0, @URace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Undead'),
+(14, 4005, 5840, 0, 0, 5, 0, @UFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Undercity'),
+(14, 3161, 3841, 0, 0, 16, 0, @ORace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Orc'),
+(14, 3161, 3841, 0, 0, 5, 0, @OFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Ogrimmar'),
+(14, 3185, 5844, 0, 0, 16, 0, @NRace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Night Elf'),
+(14, 3185, 5844, 0, 0, 5, 0, @NFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Darnassus'),
+(14, 3162, 5842, 0, 0, 16, 0, @TRRace, 0, 0, 1, 0, 0, '', 'NPC Text - Show text if Player is not Troll'),
+(14, 3162, 5842, 0, 0, 5, 0, @TRFaction, 128, 0, 1, 0, 0, '', 'NPC Text - Show text if player is not Exalted with Darkspear Trolls'),
+
+
+(14, 4004, 4859, 0, 0, 16, 0, @HRace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Human'),
+(14, 4004, 4859, 0, 1, 5, 0, @HFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Stormwind'),
+(14, 4006, 4862, 0, 0, 16, 0, @TARace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Tauren'),
+(14, 4006, 4862, 0, 1, 5, 0, @TAFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Thunderbluff'),
+(14, 8098, 10011, 0, 0, 16, 0, @BRace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Blood Elf'),
+(14, 8098, 10011, 0, 1, 5, 0, @BFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Silvermoon'),
+(14, 4005, 4869, 0, 0, 16, 0, @URace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Undead'),
+(14, 4005, 4869, 0, 1, 5, 0, @UFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Undercity'),
+(14, 3161, 3893, 0, 0, 16, 0, @ORace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Orc'),
+(14, 3161, 3893, 0, 1, 5, 0, @OFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Ogrimmar'),
+(14, 3185, 3942, 0, 0, 16, 0, @NRace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Night Elf'),
+(14, 3185, 3942, 0, 1, 5, 0, @NFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Darnassus'),
+(14, 3162, 3896, 0, 0, 16, 0, @TRRace, 0, 0, 0, 0, 0, '', 'NPC Text - Show text if Player is Troll'),
+(14, 3162, 3896, 0, 1, 5, 0, @TRFaction, 128, 0, 0, 0, 0, '', 'NPC Text - Show text if player is Exalted with Darkspear Trolls');
+
+UPDATE `creature_template` SET `gossip_menu_id`=4001 WHERE `entry`=1261;
+UPDATE `creature_template` SET `gossip_menu_id`=4004 WHERE `entry`=2357;
+
+DELETE FROM `gossip_menu_option` WHERE `menu_id` IN(4004,4001,3161,3162,4006,4005,3185,8098,8213,3185);
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(3185, 1, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(4001, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(3161, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(3162, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(4004, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(4005, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(4006, 0, 1, 'I would like to buy from you.', 14967, 3, 128, 0, 0, 0, 0, '', 0),
+(8098, 0, 1, 'I wish to purchase one of these creatures.', 17909, 3, 128, 0, 0, 0, 0, '', 0),
+(8213, 0, 1, 'I wish to purchase one of these creatures.', 17909, 3, 128, 0, 0, 0, 0, '', 0);
+
+DELETE FROM `gossip_menu` WHERE `entry`=4001;
+INSERT INTO `gossip_menu` (`entry`, `text_id`) VALUES
+(4001, 5856); -- 1261
+
+DELETE FROM `gossip_menu` WHERE `entry` IN(4004,4001,3161,3162,4006,4005,3185,8098,8213,3185);
+INSERT INTO `gossip_menu` (`entry`, `text_id`) VALUES
+(3161, 3893),
+(3161, 3841),
+(3162, 3896),
+(3162, 5842),
+(3185, 3942),
+(3185, 5844),
+(4001, 5856),
+(4004, 4859),
+(4004, 5855),
+(4005, 4869),
+(4005, 5840),
+(4006, 4862),
+(4006, 5843),
+(8098, 10011),
+(8098, 10305),
+(8213, 10239);
+
+UPDATE `smart_scripts` SET `target_type`=10 WHERE `entryorguid`=2598300 AND `ID`=1;
diff --git a/sql/updates/world/2014_09_11_03_world_misc.sql b/sql/updates/world/2014_09_11_03_world_misc.sql
new file mode 100644
index 00000000000..b6cd07998ef
--- /dev/null
+++ b/sql/updates/world/2014_09_11_03_world_misc.sql
@@ -0,0 +1,5 @@
+DELETE FROM `npc_text` WHERE `ID`=5841;
+INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `prob0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `prob1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `prob2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `prob3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `prob4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `prob5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `prob6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `prob7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES
+(5841, 'I only make my mounts available to those who are considered exalted to Orgrimmar and the Orcish race. Go prove yourself to us, and I''ll make my mighty wolves available for your inspection.', 'I only make my mounts available to those who are considered exalted to Orgrimmar and the Orcish race. Go prove yourself to us, and I''ll make my mighty wolves available for your inspection.', 8414, 0, 1, 0, 1, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+UPDATE `gossip_menu_option` SET `id`=0 WHERE `menu_id`=3185 AND `id`=1;
diff --git a/sql/updates/world/2014_09_12_00_world_misc.sql b/sql/updates/world/2014_09_12_00_world_misc.sql
new file mode 100644
index 00000000000..e36e4012ca9
--- /dev/null
+++ b/sql/updates/world/2014_09_12_00_world_misc.sql
@@ -0,0 +1,34 @@
+UPDATE `creature_template` SET `ScriptName`='' WHERE `entry` =3362;
+
+DELETE FROM `creature_text` WHERE `entry` IN(18407,18166);
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
+(18407, 0, 0, 'Damn those ogres. Damn them to the Nether. Won''t someone save us from these savages! This is the fifth kidnapping in as many days.', 12, 1, 100, 0, 0, 0, 'Warden Bullrok',15371),
+(18407, 1, 0, 'That''s the best reward we''re going to be able to offer. Hopefully someone accepts the mission.', 12, 1, 100, 1, 0, 0, 'Warden Bullrok',15372),
+(18166, 0, 0, 'Do not burden A''dal with mundane questions, $r. This being''s will is all that keeps our enemies from crushing this city.', 12, 0, 100, 0, 0, 0, 'Khadgar',17238),
+(18166, 1, 0, 'Show our guest around Shattrath, will you? Keep an eye out for pickpockets in the Lower City.', 12, 0, 100, 0, 0, 0, 'Khadgar',17266);
+
+UPDATE `creature_template` SET `AIName`='SmartAI', `ScriptName`='' WHERE `entry`=18166;
+
+DELETE FROM `smart_scripts` WHERE `entryorguid`IN(18407,18166) AND `source_type`=0;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=18481 AND `source_type`=0 AND `id`=2;
+
+DELETE FROM `smart_scripts` WHERE `entryorguid`=1840700 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
+(18407, 0, 0, 0, 1, 0, 100, 0, 60000, 60000, 120000, 240000, 80, 1840700, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Out of Combat - Run Script'),
+(18481, 0, 2, 0, 20, 0, 100, 0, 10210, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 18166, 0, 0, 0, 0, 0, 0, 'A\'dal - On Quest Reward (A''DAL) - Say line 0 on Khadgar'),
+(18166, 0, 0, 0, 19, 0, 100, 0, 10211, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Khadgar - On Quest Accept (City of Lights) - Say Line 1'),
+(1840700, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 71, 0, 0, 1903, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Equip Virtual Item 1903 to Slot 1'),
+(1840700, 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, 2.96706, 'Warden Bullrok - Script - Set Orientation'),
+(1840700, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Play emote STATE_WORK_CHOPWOOD'),
+(1840700, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 17, 234, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Say Line 1'),
+(1840700, 9, 4, 0, 0, 0, 100, 0, 15000, 15000, 0, 0, 17, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Play emote ONESHOT_NONE'),
+(1840700, 9, 5, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Say Line 1'),
+(1840700, 9, 6, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0.6283185, 'Warden Bullrok - Script - Set Orientation'),
+(1840700, 9, 7, 0, 0, 0, 100, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Warden Bullrok - Script - Unequip Virtual Item');
+
+UPDATE `gossip_menu` SET `text_id`=5841 WHERE `entry`=3161 AND `text_id`=3841;
+UPDATE `conditions` SET `SourceEntry`=5843 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=4006 AND `SourceEntry`=4840 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=5 AND `ConditionTarget`=0 AND `ConditionValue1`=81 AND `ConditionValue2`=128 AND `ConditionValue3`=0;
+UPDATE `conditions` SET `SourceEntry`=5843 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=4006 AND `SourceEntry`=4840 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=16 AND `ConditionTarget`=0 AND `ConditionValue1`=32 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
+UPDATE `conditions` SET `SourceEntry`=5855 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=4004 AND `SourceEntry`=4855 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=5 AND `ConditionTarget`=0 AND `ConditionValue1`=72 AND `ConditionValue2`=128 AND `ConditionValue3`=0;
+UPDATE `conditions` SET `SourceEntry`=5855 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=4004 AND `SourceEntry`=4855 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=16 AND `ConditionTarget`=0 AND `ConditionValue1`=1 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
diff --git a/sql/updates/world/2014_09_12_01_world_misc.sql b/sql/updates/world/2014_09_12_01_world_misc.sql
new file mode 100644
index 00000000000..71cb62477d4
--- /dev/null
+++ b/sql/updates/world/2014_09_12_01_world_misc.sql
@@ -0,0 +1,4 @@
+UPDATE `conditions` SET `SourceEntry`=5841 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=3161 AND `SourceEntry`=3841 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=16 AND `ConditionTarget`=0 AND `ConditionValue1`=2 AND `ConditionValue2`=0 AND `ConditionValue3`=0;
+UPDATE `conditions` SET `SourceEntry`=5841 WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=3161 AND `SourceEntry`=3841 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=5 AND `ConditionTarget`=0 AND `ConditionValue1`=76 AND `ConditionValue2`=128 AND `ConditionValue3`=0;
+
+UPDATE `creature_template` SET `flags_extra`=0 WHERE `entry` IN(24928,25115);
diff --git a/sql/updates/world/2014_09_12_02_world_misc.sql b/sql/updates/world/2014_09_12_02_world_misc.sql
new file mode 100644
index 00000000000..535ecb90367
--- /dev/null
+++ b/sql/updates/world/2014_09_12_02_world_misc.sql
@@ -0,0 +1,9 @@
+DELETE FROM `creature_text` WHERE `entry`=26527;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextId`) VALUES
+(26527, 0, 0, 'Oh, no! Adventurers, something awful has happened! A colleague of mine has been captured by the Infinite Dragonflight, and they''re doing something horrible to him! Keeping Arthas is still your highest priority, but if you act fast you could help save a Guardian of Time!', 15, 0, 100, 0, 0, 0, 'Chromie', 32670),
+(26527, 1, 0, 'Adventurers, you must hurry! The Guardian of Time cannot last for much longer!', 15, 0, 100, 0, 0, 0, 'Chromie', 32678),
+(26527, 2, 0, 'I can barely sense the Guardian of Time! His timeline is fading quickly!', 15, 0, 100, 0, 0, 0, 'Chromie', 32679);
+
+DELETE FROM `conditions` WHERE `SourceEntry`=60422;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `Comment`) VALUES
+(13, 1, 60422, 0, 0, 31, 1, 3, 32281, 0, 0, 0, 0, 'Corruption of Time (60422) can hit only Guardian of Time');
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt
index d6f0515a8e1..d7f1eb4fa30 100644
--- a/src/server/authserver/CMakeLists.txt
+++ b/src/server/authserver/CMakeLists.txt
@@ -44,6 +44,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src/server/shared
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp
index af7ecd15160..5c06a1e1c34 100644
--- a/src/server/authserver/Main.cpp
+++ b/src/server/authserver/Main.cpp
@@ -24,23 +24,21 @@
* authentication server
*/
-
-#include "AsyncAcceptor.h"
-#include "AuthSession.h"
+#include "AuthSocketMgr.h"
#include "BattlenetManager.h"
#include "BattlenetSessionManager.h"
#include "Common.h"
-#include "Configuration/Config.h"
-#include "Database/DatabaseEnv.h"
+#include "Config.h"
+#include "DatabaseEnv.h"
#include "Log.h"
#include "ProcessPriority.h"
#include "RealmList.h"
#include "SystemConfig.h"
#include "Util.h"
#include <cstdlib>
+#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>
-#include <iostream>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
@@ -128,9 +126,10 @@ int main(int argc, char** argv)
}
std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port);
AsyncAcceptor<Battlenet::Session> bnetServer(_ioService, bindIp, bnport);
+ sAuthSocketMgr.StartNetwork(_ioService, bindIp, port);
+
// Set signal handlers
boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM);
#if PLATFORM == PLATFORM_WINDOWS
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index 91a2ff9757a..0ba832af483 100644
--- a/src/server/authserver/Server/AuthSession.cpp
+++ b/src/server/authserver/Server/AuthSession.cpp
@@ -53,6 +53,7 @@ enum eStatus
typedef struct AUTH_LOGON_CHALLENGE_C
{
+ uint8 cmd;
uint8 error;
uint16 size;
uint8 gamename[4];
@@ -71,6 +72,7 @@ typedef struct AUTH_LOGON_CHALLENGE_C
typedef struct AUTH_LOGON_PROOF_C
{
+ uint8 cmd;
uint8 A[32];
uint8 M1[20];
uint8 crc_hash[20];
@@ -98,6 +100,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
typedef struct AUTH_RECONNECT_PROOF_C
{
+ uint8 cmd;
uint8 R1[16];
uint8 R2[20];
uint8 R3[20];
@@ -112,79 +115,88 @@ enum class BufferSizes : uint32
SRP_6_S = 0x20,
};
-#define REALM_LIST_PACKET_SIZE 4
-#define XFER_ACCEPT_SIZE 0
-#define XFER_RESUME_SIZE 8
-#define XFER_CANCEL_SIZE 0
+#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4
+#define REALM_LIST_PACKET_SIZE 5
+#define XFER_ACCEPT_SIZE 1
+#define XFER_RESUME_SIZE 9
+#define XFER_CANCEL_SIZE 1
std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
{
std::unordered_map<uint8, AuthHandler> handlers;
- handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleLogonChallenge };
- handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
- handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleReconnectChallenge };
- handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
- handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };
- handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept };
- handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume };
- handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel };
+ handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge };
+ handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
+ handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge };
+ handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof };
+ handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList };
+ handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept };
+ handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume };
+ handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel };
return handlers;
}
std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers();
-void AuthSession::ReadHeaderHandler()
+void AuthSession::ReadHandler()
{
- uint8 cmd = GetHeaderBuffer()[0];
- auto itr = Handlers.find(cmd);
- if (itr != Handlers.end())
+ MessageBuffer& packet = GetReadBuffer();
+ while (packet.GetActiveSize())
{
- // Handle dynamic size packet
+ uint8 cmd = packet.GetReadPointer()[0];
+ auto itr = Handlers.find(cmd);
+ if (itr == Handlers.end())
+ {
+ // well we dont handle this, lets just ignore it
+ packet.Reset();
+ break;
+ }
+
+ uint16 size = uint16(itr->second.packetSize);
+ if (packet.GetActiveSize() < size)
+ break;
+
if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE)
{
- ReadData(sizeof(uint8) + sizeof(uint16)); //error + size
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(packet.GetReadPointer());
+ size += challenge->size;
+ }
- AsyncReadData(challenge->size);
+ if (packet.GetActiveSize() < size)
+ break;
+
+ if (!(*this.*Handlers.at(cmd).handler)())
+ {
+ CloseSocket();
+ return;
}
- else
- AsyncReadData(itr->second.packetSize);
- }
- else
- CloseSocket();
-}
-void AuthSession::ReadDataHandler()
-{
- if (!(*this.*Handlers.at(GetHeaderBuffer()[0]).handler)())
- {
- CloseSocket();
- return;
+ packet.ReadCompleted(size);
}
- AsyncReadHeader();
+ AsyncRead();
}
-void AuthSession::AsyncWrite(ByteBuffer& packet)
+void AuthSession::SendPacket(ByteBuffer& packet)
{
if (!IsOpen())
return;
- std::lock_guard<std::mutex> guard(_writeLock);
-
- bool needsWriteStart = _writeQueue.empty();
+ if (!packet.empty())
+ {
+ MessageBuffer buffer;
+ buffer.Write(packet.contents(), packet.size());
- _writeQueue.push(std::move(packet));
+ std::unique_lock<std::mutex> guard(_writeLock);
- if (needsWriteStart)
- AuthSocket::AsyncWrite(_writeQueue.front());
+ QueuePacket(std::move(buffer), guard);
+ }
}
bool AuthSession::HandleLogonChallenge()
{
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
@@ -395,7 +407,7 @@ bool AuthSession::HandleLogonChallenge()
pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
}
- AsyncWrite(pkt);
+ SendPacket(pkt);
return true;
}
@@ -405,7 +417,7 @@ bool AuthSession::HandleLogonProof()
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
// Read the packet
- sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetDataBuffer());
+ sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer());
// If the client has no valid version
if (_expversion == NO_VALID_EXP_FLAG)
@@ -512,10 +524,9 @@ bool AuthSession::HandleLogonProof()
// Check auth token
if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
{
- ReadData(1);
- uint8 size = *(GetDataBuffer() + sizeof(sAuthLogonProof_C));
- ReadData(size);
- std::string token(reinterpret_cast<char*>(GetDataBuffer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size);
+ uint8 size = *(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C));
+ std::string token(reinterpret_cast<char*>(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size);
+ GetReadBuffer().ReadCompleted(sizeof(size) + size);
uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str());
uint32 incomingToken = atoi(token.c_str());
if (validToken != incomingToken)
@@ -525,7 +536,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
packet << uint8(3);
packet << uint8(0);
- AsyncWrite(packet);
+ SendPacket(packet);
return false;
}
}
@@ -556,7 +567,7 @@ bool AuthSession::HandleLogonProof()
std::memcpy(packet.contents(), &proof, sizeof(proof));
}
- AsyncWrite(packet);
+ SendPacket(packet);
_isAuthenticated = true;
}
else
@@ -566,7 +577,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
packet << uint8(3);
packet << uint8(0);
- AsyncWrite(packet);
+ SendPacket(packet);
TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str());
@@ -635,7 +646,7 @@ bool AuthSession::HandleLogonProof()
bool AuthSession::HandleReconnectChallenge()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge");
- sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
+ sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
@@ -679,14 +690,14 @@ bool AuthSession::HandleReconnectChallenge()
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros
- AsyncWrite(pkt);
+ SendPacket(pkt);
return true;
}
bool AuthSession::HandleReconnectProof()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
- sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetDataBuffer());
+ sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer());
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
return false;
@@ -707,7 +718,7 @@ bool AuthSession::HandleReconnectProof()
pkt << uint8(AUTH_RECONNECT_PROOF);
pkt << uint8(0x00);
pkt << uint16(0x00); // 2 bytes zeros
- AsyncWrite(pkt);
+ SendPacket(pkt);
_isAuthenticated = true;
return true;
}
@@ -832,7 +843,7 @@ bool AuthSession::HandleRealmList()
hdr << uint16(pkt.size() + RealmListSizeBuffer.size());
hdr.append(RealmListSizeBuffer); // append RealmList's size buffer
hdr.append(pkt); // append realms in the realmlist
- AsyncWrite(hdr);
+ SendPacket(hdr);
return true;
}
diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h
index 04ee339df8e..07af61d9c1d 100644
--- a/src/server/authserver/Server/AuthSession.h
+++ b/src/server/authserver/Server/AuthSession.h
@@ -30,14 +30,12 @@ using boost::asio::ip::tcp;
struct AuthHandler;
-class AuthSession : public Socket<AuthSession, ByteBuffer>
+class AuthSession : public Socket<AuthSession>
{
- typedef Socket<AuthSession, ByteBuffer> AuthSocket;
-
public:
static std::unordered_map<uint8, AuthHandler> InitHandlers();
- AuthSession(tcp::socket&& socket) : Socket(std::move(socket), 1),
+ AuthSession(tcp::socket&& socket) : Socket(std::move(socket)),
_isAuthenticated(false), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
@@ -46,14 +44,13 @@ public:
void Start() override
{
- AsyncReadHeader();
+ AsyncRead();
}
- void AsyncWrite(ByteBuffer& packet);
+ void SendPacket(ByteBuffer& packet);
protected:
- void ReadHeaderHandler() override;
- void ReadDataHandler() override;
+ void ReadHandler() override;
private:
bool HandleLogonChallenge();
diff --git a/src/server/authserver/Server/AuthSocketMgr.h b/src/server/authserver/Server/AuthSocketMgr.h
new file mode 100644
index 00000000000..a14ee26ed56
--- /dev/null
+++ b/src/server/authserver/Server/AuthSocketMgr.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AuthSocketMgr_h__
+#define AuthSocketMgr_h__
+
+#include "SocketMgr.h"
+#include "AuthSession.h"
+
+void OnSocketAccept(tcp::socket&& sock);
+
+class AuthSocketMgr : public SocketMgr<AuthSession>
+{
+ typedef SocketMgr<AuthSession> BaseSocketMgr;
+
+public:
+ static AuthSocketMgr& Instance()
+ {
+ static AuthSocketMgr instance;
+ return instance;
+ }
+
+ bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override
+ {
+ if (!BaseSocketMgr::StartNetwork(service, bindIp, port))
+ return false;
+
+ _acceptor->AsyncAcceptManaged(&OnSocketAccept);
+ return true;
+ }
+
+protected:
+ NetworkThread<AuthSession>* CreateThreads() const override
+ {
+ return new NetworkThread<AuthSession>[1];
+ }
+};
+
+#define sAuthSocketMgr AuthSocketMgr::Instance()
+
+void OnSocketAccept(tcp::socket&& sock)
+{
+ sAuthSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+
+#endif // AuthSocketMgr_h__
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
index 9c9a39cf567..df930367878 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h
@@ -72,7 +72,7 @@ class AuctionBotBuyer : public AuctionBotAgent
{
public:
AuctionBotBuyer();
- ~AuctionBotBuyer() override;
+ ~AuctionBotBuyer();
bool Initialize() override;
bool Update(AuctionHouseType houseType) override;
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
index 014fe23f71a..42677a52f49 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
@@ -118,7 +118,7 @@ public:
typedef std::vector<uint32> ItemPool;
AuctionBotSeller();
- ~AuctionBotSeller() override;
+ ~AuctionBotSeller();
bool Initialize() override;
bool Update(AuctionHouseType houseType) override;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ee8fee198bf..bab96b15292 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3878,7 +3878,8 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
if (!pSkill)
continue;
- if (_spell_idx->second->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id))
+ ///@todo: confirm if rogues start with lockpicking skill at level 1 but only receive the spell to use it at level 16
+ if ((_spell_idx->second->AutolearnType == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id)) || (pSkill->id == SKILL_LOCKPICKING && _spell_idx->second->max_value == 0))
LearnDefaultSkill(pSkill->id, 0);
}
}
@@ -17943,6 +17944,7 @@ bool Player::isAllowedToLoot(const Creature* creature)
switch (thisGroup->GetLootMethod())
{
+ case MASTER_LOOT:
case FREE_FOR_ALL:
return true;
case ROUND_ROBIN:
@@ -17952,7 +17954,6 @@ bool Player::isAllowedToLoot(const Creature* creature)
return true;
return loot->hasItemFor(this);
- case MASTER_LOOT:
case GROUP_LOOT:
case NEED_BEFORE_GREED:
// may only loot if the player is the loot roundrobin player
@@ -23664,6 +23665,8 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
skillValue = std::min(std::max<uint16>({ 1, uint16((getLevel() - 1) * 5) }), maxValue);
else if (skillId == SKILL_FIST_WEAPONS)
skillValue = std::max<uint16>(1, GetSkillValue(SKILL_UNARMED));
+ else if (skillId == SKILL_LOCKPICKING)
+ skillValue = std::max<uint16>(1, GetSkillValue(SKILL_LOCKPICKING));
SetSkill(skillId, 0, skillValue, maxValue);
break;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index f6615d67c99..6f37f74b607 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -14108,7 +14108,8 @@ void Unit::SetFeared(bool apply)
}
if (Player* player = ToPlayer())
- player->SetClientControl(this, !apply);
+ if(!player->HasUnitState(UNIT_STATE_POSSESSED))
+ player->SetClientControl(this, !apply);
}
void Unit::SetConfused(bool apply)
@@ -14130,7 +14131,8 @@ void Unit::SetConfused(bool apply)
}
if (Player* player = ToPlayer())
- player->SetClientControl(this, !apply);
+ if (!player->HasUnitState(UNIT_STATE_POSSESSED))
+ player->SetClientControl(this, !apply);
}
bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 638cc19784a..fd89ed80429 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -226,7 +226,7 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup,
void Group::ConvertToLFG()
{
- m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_UNK1);
+ m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_LFG_RESTRICTED);
m_lootMethod = NEED_BEFORE_GREED;
if (!isBGGroup() && !isBFGroup())
{
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 4559c5841ae..84e3a5454cd 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -82,13 +82,15 @@ enum GroupMemberAssignment
enum GroupType
{
- GROUPTYPE_NORMAL = 0x00,
- GROUPTYPE_BG = 0x01,
- GROUPTYPE_RAID = 0x02,
- GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask
- GROUPTYPE_UNK1 = 0x04,
- GROUPTYPE_LFG = 0x08
+ GROUPTYPE_NORMAL = 0x00,
+ GROUPTYPE_BG = 0x01,
+ GROUPTYPE_RAID = 0x02,
+ GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask
+ GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions()
+ GROUPTYPE_LFG = 0x08,
// 0x10, leave/change group?, I saw this flag when leaving group and after leaving BG while in group
+ // GROUPTYPE_ONE_PERSON_PARTY = 0x20, 4.x Script_IsOnePersonParty()
+ // GROUPTYPE_EVERYONE_ASSISTANT = 0x40 4.x Script_IsEveryoneAssistant()
};
enum GroupUpdateFlags
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index cfb7df6c34e..ac18a10c9a9 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -310,10 +310,14 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
-
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, true))
+ {
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
+
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ }
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
@@ -334,10 +338,14 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
- if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
- _player->AddQuestAndCheckCompletion(nextQuest, object);
-
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ // Only send the quest to the player if the conditions are met
+ if (_player->CanTakeQuest(nextQuest, true))
+ {
+ if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
+ _player->AddQuestAndCheckCompletion(nextQuest, object);
+
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ }
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 60475382d5e..26d348737ab 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -902,8 +902,13 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING;
break;
case MASTER_PERMISSION:
- slot_type = LOOT_SLOT_TYPE_MASTER;
+ {
+ if (lv.viewer->GetGroup() && lv.viewer->GetGroup()->GetMasterLooterGuid() == lv.viewer->GetGUID())
+ slot_type = LOOT_SLOT_TYPE_MASTER;
+ else
+ slot_type = LOOT_SLOT_TYPE_LOCKED;
break;
+ }
case RESTRICTED_PERMISSION:
slot_type = LOOT_SLOT_TYPE_LOCKED;
break;
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index feef22c8a21..6d0ea9ea7a4 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -268,7 +268,7 @@ void WorldSession::SendPacket(WorldPacket* packet, bool forced /*= false*/)
sScriptMgr->OnPacketSend(this, *packet);
- m_Socket->AsyncWrite(*packet);
+ m_Socket->SendPacket(*packet);
}
/// Add an incoming packet to the queue
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 9a7b212da04..6cf406f21fa 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -32,19 +32,24 @@ std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CON
std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER");
-WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket), sizeof(ClientPktHeader)),
- _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false)
+
+WorldSocket::WorldSocket(tcp::socket&& socket)
+ : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false)
{
+ _headerBuffer.Resize(sizeof(ClientPktHeader));
}
void WorldSocket::Start()
{
- sScriptMgr->OnSocketOpen(shared_from_this());
+ AsyncRead();
- AsyncReadData(ClientConnectionInitialize.length() + 2 /*sizeof(ClientPktHeader::size)*/ + 1 /*null terminator*/);
+ MessageBuffer initializer;
+ ServerPktHeader header(ServerConnectionInitialize.size(), 0);
+ initializer.Write(header.header, header.getHeaderLength() - 2);
+ initializer.Write((void*)ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length());
- _writeQueue.emplace(ServerConnectionInitialize);
- AsyncWrite(_writeQueue.front());
+ std::unique_lock<std::mutex> dummy(_writeLock, std::defer_lock);
+ QueuePacket(std::move(initializer), dummy);
}
void WorldSocket::HandleSendAuthSession()
@@ -60,14 +65,69 @@ void WorldSocket::HandleSendAuthSession()
packet << uint32(_authSeed);
packet << uint8(1);
- AsyncWrite(packet);
+ SendPacket(packet);
+}
+
+void WorldSocket::ReadHandler()
+{
+ if (!IsOpen())
+ return;
+
+ MessageBuffer& packet = GetReadBuffer();
+ while (packet.GetActiveSize() > 0)
+ {
+ if (_headerBuffer.GetRemainingSpace() > 0)
+ {
+ // need to receive the header
+ std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
+ _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
+ packet.ReadCompleted(readHeaderSize);
+
+ if (_headerBuffer.GetRemainingSpace() > 0)
+ {
+ // Couldn't receive the whole header this time.
+ ASSERT(packet.GetActiveSize() == 0);
+ break;
+ }
+
+ // We just received nice new header
+ if (!ReadHeaderHandler())
+ return;
+ }
+
+ // We have full read header, now check the data payload
+ if (_packetBuffer.GetRemainingSpace() > 0)
+ {
+ // need more data in the payload
+ std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
+ _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
+ packet.ReadCompleted(readDataSize);
+
+ if (_packetBuffer.GetRemainingSpace() > 0)
+ {
+ // Couldn't receive the whole data this time.
+ ASSERT(packet.GetActiveSize() == 0);
+ break;
+ }
+ }
+
+ // just received fresh new payload
+ if (!ReadDataHandler())
+ return;
+
+ _headerBuffer.Reset();
+ }
+
+ AsyncRead();
}
-void WorldSocket::ReadHeaderHandler()
+bool WorldSocket::ReadHeaderHandler()
{
- _authCrypt.DecryptRecv(GetHeaderBuffer(), sizeof(ClientPktHeader));
+ ASSERT(_headerBuffer.GetActiveSize() == sizeof(ClientPktHeader));
+
+ _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader));
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
EndianConvertReverse(header->size);
EndianConvert(header->cmd);
@@ -81,26 +141,28 @@ void WorldSocket::ReadHeaderHandler()
}
else
TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
- GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
+ GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
CloseSocket();
- return;
+ return false;
}
- AsyncReadData(header->size - sizeof(header->cmd));
+ header->size -= sizeof(header->cmd);
+ _packetBuffer.Resize(header->size);
+ return true;
}
-void WorldSocket::ReadDataHandler()
+bool WorldSocket::ReadDataHandler()
{
if (_initialized)
{
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(header->cmd));
std::string opcodeName = GetOpcodeNameForLogging(opcode);
- WorldPacket packet(opcode, MoveData());
+ WorldPacket packet(opcode, std::move(_packetBuffer));
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
@@ -129,7 +191,7 @@ void WorldSocket::ReadDataHandler()
packet.rfinish(); // contains uint32 disconnectReason;
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
sScriptMgr->OnPacketReceive(_worldSession, packet);
- return;
+ return true;
case CMSG_ENABLE_NAGLE:
{
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
@@ -144,7 +206,7 @@ void WorldSocket::ReadDataHandler()
{
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
CloseSocket();
- return;
+ return false;
}
// Our Idle timer will reset on any non PING opcodes.
@@ -159,23 +221,23 @@ void WorldSocket::ReadDataHandler()
}
else
{
- ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetDataBuffer());
+ ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
- std::string initializer(reinterpret_cast<char const*>(header) + sizeof(header->size));
+ std::string initializer(reinterpret_cast<char const*>(_packetBuffer.GetReadPointer()), header->size);
if (initializer != ClientConnectionInitialize)
{
CloseSocket();
- return;
+ return false;
}
_initialized = true;
HandleSendAuthSession();
}
- AsyncReadHeader();
+ return true;
}
-void WorldSocket::AsyncWrite(WorldPacket& packet)
+void WorldSocket::SendPacket(WorldPacket& packet)
{
if (!IsOpen())
return;
@@ -190,15 +252,27 @@ void WorldSocket::AsyncWrite(WorldPacket& packet)
ServerPktHeader header(packet.size() + 2, packet.GetOpcode());
- std::lock_guard<std::mutex> guard(_writeLock);
+ std::unique_lock<std::mutex> guard(_writeLock);
- bool needsWriteStart = _writeQueue.empty();
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
- _writeQueue.emplace(header, packet);
+#ifndef BOOST_ASIO_HAS_IOCP
+ if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size())
+ {
+ _writeBuffer.Write(header.header, header.getHeaderLength());
+ if (!packet.empty())
+ _writeBuffer.Write(packet.contents(), packet.size());
+ }
+ else
+#endif
+ {
+ MessageBuffer buffer(header.getHeaderLength() + packet.size());
+ buffer.Write(header.header, header.getHeaderLength());
+ if (!packet.empty())
+ buffer.Write(packet.contents(), packet.size());
- if (needsWriteStart)
- AsyncWrite(_writeQueue.front());
+ QueuePacket(std::move(buffer), guard);
+ }
}
void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
@@ -480,7 +554,7 @@ void WorldSocket::SendAuthResponseError(uint8 code)
packet.WriteBit(0); // has account info
packet << uint8(code);
- AsyncWrite(packet);
+ SendPacket(packet);
}
void WorldSocket::HandlePing(WorldPacket& recvPacket)
@@ -541,12 +615,5 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
WorldPacket packet(SMSG_PONG, 4);
packet << ping;
- return AsyncWrite(packet);
-}
-
-void WorldSocket::CloseSocket()
-{
- sScriptMgr->OnSocketClose(shared_from_this());
-
- Socket::CloseSocket();
+ return SendPacket(packet);
}
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index 9e5f785d939..6ba76584909 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -19,16 +19,6 @@
#ifndef __WORLDSOCKET_H__
#define __WORLDSOCKET_H__
-// Forward declare buffer function here - Socket.h must know about it
-struct WorldPacketBuffer;
-namespace boost
-{
- namespace asio
- {
- WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf);
- }
-}
-
#include "Common.h"
#include "WorldPacketCrypt.h"
#include "ServerPktHeader.h"
@@ -54,58 +44,8 @@ struct ClientPktHeader
#pragma pack(pop)
-struct WorldPacketBuffer
-{
- typedef boost::asio::const_buffer value_type;
-
- typedef boost::asio::const_buffer const* const_iterator;
-
- WorldPacketBuffer(ServerPktHeader header, WorldPacket const& packet) : _header(header), _packet(packet), _bufferCount(0)
- {
- _buffers[_bufferCount++] = boost::asio::const_buffer(_header.header, _header.getHeaderLength());
- if (!_packet.empty())
- _buffers[_bufferCount++] = boost::asio::const_buffer(_packet.contents(), _packet.size());
- }
-
- WorldPacketBuffer(std::string const& str) : _header(str.length() + 1 /*null terminator*/, 0), _packet(), _bufferCount(0)
- {
- _buffers[_bufferCount++] = boost::asio::const_buffer(_header.header, _header.getHeaderLength() - 2 /*sizeof(opcode)*/);
- if (!str.empty())
- _buffers[_bufferCount++] = boost::asio::const_buffer(str.c_str(), _header.size);
- }
-
- const_iterator begin() const
- {
- return _buffers;
- }
-
- const_iterator end() const
- {
- return _buffers + _bufferCount;
- }
-
-private:
- boost::asio::const_buffer _buffers[2];
- ServerPktHeader _header;
- WorldPacket _packet;
- uint32 _bufferCount;
-};
-
-namespace boost
-{
- namespace asio
- {
- inline WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf)
- {
- return buf;
- }
- }
-}
-
-class WorldSocket : public Socket<WorldSocket, WorldPacketBuffer>
+class WorldSocket : public Socket<WorldSocket>
{
- typedef Socket<WorldSocket, WorldPacketBuffer> Base;
-
static std::string const ServerConnectionInitialize;
static std::string const ClientConnectionInitialize;
@@ -118,14 +58,12 @@ public:
void Start() override;
- void CloseSocket() override;
-
- using Base::AsyncWrite;
- void AsyncWrite(WorldPacket& packet);
+ void SendPacket(WorldPacket& packet);
protected:
- void ReadHeaderHandler() override;
- void ReadDataHandler() override;
+ void ReadHandler() override;
+ bool ReadHeaderHandler();
+ bool ReadDataHandler();
private:
void HandleSendAuthSession();
@@ -141,6 +79,10 @@ private:
uint32 _OverSpeedPings;
WorldSession* _worldSession;
+
+ MessageBuffer _headerBuffer;
+ MessageBuffer _packetBuffer;
+
bool _initialized;
};
diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp
new file mode 100644
index 00000000000..21f62fa265c
--- /dev/null
+++ b/src/server/game/Server/WorldSocketMgr.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Config.h"
+#include "NetworkThread.h"
+#include "ScriptMgr.h"
+#include "WorldSocket.h"
+#include "WorldSocketMgr.h"
+#include <boost/system/error_code.hpp>
+
+static void OnSocketAccept(tcp::socket&& sock)
+{
+ sWorldSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+class WorldSocketThread : public NetworkThread<WorldSocket>
+{
+public:
+ void SocketAdded(std::shared_ptr<WorldSocket> sock) override
+ {
+ sScriptMgr->OnSocketOpen(sock);
+ }
+
+ void SocketRemoved(std::shared_ptr<WorldSocket> sock) override
+ {
+ sScriptMgr->OnSocketClose(sock);
+ }
+};
+
+WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m_SockOutUBuff(65536), _tcpNoDelay(true)
+{
+}
+
+bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
+{
+ _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
+
+ TC_LOG_DEBUG("misc", "Max allowed socket connections %d", boost::asio::socket_base::max_connections);
+
+ // -1 means use default
+ _socketSendBufferSize = sConfigMgr->GetIntDefault("Network.OutKBuff", -1);
+
+ m_SockOutUBuff = sConfigMgr->GetIntDefault("Network.OutUBuff", 65536);
+
+ if (m_SockOutUBuff <= 0)
+ {
+ TC_LOG_ERROR("misc", "Network.OutUBuff is wrong in your config file");
+ return false;
+ }
+
+ BaseSocketMgr::StartNetwork(service, bindIp, port);
+
+ _acceptor->AsyncAcceptManaged(&OnSocketAccept);
+
+ sScriptMgr->OnNetworkStart();
+ return true;
+}
+
+void WorldSocketMgr::StopNetwork()
+{
+ BaseSocketMgr::StopNetwork();
+
+ sScriptMgr->OnNetworkStop();
+}
+
+void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock)
+{
+ // set some options here
+ if (_socketSendBufferSize >= 0)
+ {
+ boost::system::error_code err;
+ sock.set_option(boost::asio::socket_base::send_buffer_size(_socketSendBufferSize), err);
+ if (err && err != boost::system::errc::not_supported)
+ {
+ TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen sock.set_option(boost::asio::socket_base::send_buffer_size) err = %s", err.message().c_str());
+ return;
+ }
+ }
+
+ // Set TCP_NODELAY.
+ if (_tcpNoDelay)
+ {
+ boost::system::error_code err;
+ sock.set_option(boost::asio::ip::tcp::no_delay(true), err);
+ if (err)
+ {
+ TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen sock.set_option(boost::asio::ip::tcp::no_delay) err = %s", err.message().c_str());
+ return;
+ }
+ }
+
+ //sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff);
+
+ BaseSocketMgr::OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+NetworkThread<WorldSocket>* WorldSocketMgr::CreateThreads() const
+{
+ return new WorldSocketThread[GetNetworkThreadCount()];
+}
diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h
new file mode 100644
index 00000000000..92a28d0c135
--- /dev/null
+++ b/src/server/game/Server/WorldSocketMgr.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \addtogroup u2w User to World Communication
+ * @{
+ * \file WorldSocketMgr.h
+ * \author Derex <derex101@gmail.com>
+ */
+
+#ifndef __WORLDSOCKETMGR_H
+#define __WORLDSOCKETMGR_H
+
+#include "SocketMgr.h"
+
+class WorldSocket;
+
+/// Manages all sockets connected to peers and network threads
+class WorldSocketMgr : public SocketMgr<WorldSocket>
+{
+ typedef SocketMgr<WorldSocket> BaseSocketMgr;
+
+public:
+ static WorldSocketMgr& Instance()
+ {
+ static WorldSocketMgr instance;
+ return instance;
+ }
+
+ /// Start network, listen at address:port .
+ bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override;
+
+ /// Stops all network threads, It will wait for all running threads .
+ void StopNetwork() override;
+
+ void OnSocketOpen(tcp::socket&& sock) override;
+
+protected:
+ WorldSocketMgr();
+
+ NetworkThread<WorldSocket>* CreateThreads() const override;
+
+private:
+ int32 _socketSendBufferSize;
+ int32 m_SockOutUBuff;
+ bool _tcpNoDelay;
+};
+
+#define sWorldSocketMgr WorldSocketMgr::Instance()
+
+#endif
+/// @}
diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
index ca46ff36079..651e487522d 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp
@@ -72,7 +72,7 @@ public:
void Reset() override
{
Initialize();
-
+ events.Reset();
summons.DespawnAll();
}
diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
index 49c5a61b7d0..d9b0c1490b5 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp
@@ -30,12 +30,21 @@ enum Spells
SPELL_STORMPIKE = 51876 // not sure
};
-enum Yells
+enum Texts
{
- YELL_AGGRO = 0,
- YELL_EVADE = 1,
- YELL_RESPAWN = 2,
- YELL_RANDOM = 3
+ SAY_AGGRO = 0,
+ SAY_EVADE = 1,
+ SAY_RESPAWN = 2,
+ SAY_RANDOM = 3
+};
+
+enum Events
+{
+ EVENT_WHIRLWIND = 1,
+ EVENT_WHIRLWIND2,
+ EVENT_KNOCKDOWN,
+ EVENT_FRENZY,
+ EVENT_RANDOM_YELL
};
class boss_drekthar : public CreatureScript
@@ -45,92 +54,85 @@ public:
struct boss_drektharAI : public ScriptedAI
{
- boss_drektharAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- WhirlwindTimer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- Whirlwind2Timer = urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- KnockdownTimer = 12 * IN_MILLISECONDS;
- FrenzyTimer = 6 * IN_MILLISECONDS;
- ResetTimer = 5 * IN_MILLISECONDS;
- YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
- }
-
- uint32 WhirlwindTimer;
- uint32 Whirlwind2Timer;
- uint32 KnockdownTimer;
- uint32 FrenzyTimer;
- uint32 YellTimer;
- uint32 ResetTimer;
+ boss_drektharAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
- Initialize();
+ events.Reset();
}
void EnterCombat(Unit* /*who*/) override
{
- Talk(YELL_AGGRO);
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(1 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_KNOCKDOWN, 12 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_FRENZY, 6 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_RANDOM_YELL, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS)); //20 to 30 seconds
}
void JustRespawned() override
{
Reset();
- Talk(YELL_RESPAWN);
+ Talk(SAY_RESPAWN);
}
- void UpdateAI(uint32 diff) override
+ bool CheckInRoom()
{
- if (!UpdateVictim())
- return;
-
- if (WhirlwindTimer <= diff)
+ if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{
- DoCastVictim(SPELL_WHIRLWIND);
- WhirlwindTimer = urand(8 * IN_MILLISECONDS, 18 * IN_MILLISECONDS);
- } else WhirlwindTimer -= diff;
+ EnterEvadeMode();
+ Talk(SAY_EVADE);
+ return false;
+ }
- if (Whirlwind2Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND2);
- Whirlwind2Timer = urand(7 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
- } else Whirlwind2Timer -= diff;
+ return true;
+ }
- if (KnockdownTimer <= diff)
- {
- DoCastVictim(SPELL_KNOCKDOWN);
- KnockdownTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
- } else KnockdownTimer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || !CheckInRoom())
+ return;
- if (FrenzyTimer <= diff)
- {
- DoCastVictim(SPELL_FRENZY);
- FrenzyTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
- } else FrenzyTimer -= diff;
+ events.Update(diff);
- if (YellTimer <= diff)
- {
- Talk(YELL_RANDOM);
- YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds
- } else YellTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- // check if creature is not outside of building
- if (ResetTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
+ switch (eventId)
{
- EnterEvadeMode();
- Talk(YELL_EVADE);
+ case EVENT_WHIRLWIND:
+ DoCastVictim(SPELL_WHIRLWIND);
+ events.ScheduleEvent(EVENT_WHIRLWIND, urand(8 * IN_MILLISECONDS, 18 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND2:
+ DoCastVictim(SPELL_WHIRLWIND2);
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(7 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
+ break;
+ case EVENT_KNOCKDOWN:
+ DoCastVictim(SPELL_KNOCKDOWN);
+ events.ScheduleEvent(EVENT_KNOCKDOWN, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
+ break;
+ case EVENT_FRENZY:
+ DoCastVictim(SPELL_FRENZY);
+ events.ScheduleEvent(EVENT_FRENZY, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ case EVENT_RANDOM_YELL:
+ Talk(SAY_RANDOM);
+ events.ScheduleEvent(EVENT_RANDOM_YELL, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ default:
+ break;
}
- ResetTimer = 5 * IN_MILLISECONDS;
- } else ResetTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
index e422975bd1a..0c029537add 100644
--- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
+++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp
@@ -27,11 +27,20 @@ enum Spells
SPELL_MORTAL_STRIKE = 16856
};
-enum Yells
+enum Texts
{
- YELL_AGGRO = 0,
- YELL_EVADE = 1,
- YELL_BUFF = 2
+ SAY_AGGRO = 0,
+ SAY_EVADE = 1,
+ SAY_BUFF = 2
+};
+
+enum Events
+{
+ EVENT_CLEAVE = 1,
+ EVENT_FRIGHTENING_SHOUT,
+ EVENT_WHIRLWIND1,
+ EVENT_WHIRLWIND2,
+ EVENT_MORTAL_STRIKE
};
enum Action
@@ -46,97 +55,85 @@ public:
struct boss_galvangarAI : public ScriptedAI
{
- boss_galvangarAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- }
-
- void Initialize()
- {
- CleaveTimer = urand(1 * IN_MILLISECONDS, 9 * IN_MILLISECONDS);
- FrighteningShoutTimer = urand(2 * IN_MILLISECONDS, 19 * IN_MILLISECONDS);
- Whirlwind1Timer = urand(1 * IN_MILLISECONDS, 13 * IN_MILLISECONDS);
- Whirlwind2Timer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- MortalStrikeTimer = urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS);
- ResetTimer = 5 * IN_MILLISECONDS;
- }
-
- uint32 CleaveTimer;
- uint32 FrighteningShoutTimer;
- uint32 Whirlwind1Timer;
- uint32 Whirlwind2Timer;
- uint32 MortalStrikeTimer;
- uint32 ResetTimer;
+ boss_galvangarAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
- Initialize();
+ events.Reset();
}
void EnterCombat(Unit* /*who*/) override
{
- Talk(YELL_AGGRO);
- }
-
- void JustRespawned() override
- {
- Reset();
+ Talk(SAY_AGGRO);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(1 * IN_MILLISECONDS, 9 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(2 * IN_MILLISECONDS, 19 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND1, urand(1 * IN_MILLISECONDS, 13 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(5 * IN_MILLISECONDS, 20 * IN_MILLISECONDS));
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_BUFF_YELL)
- Talk(YELL_BUFF);
+ Talk(SAY_BUFF);
}
- void UpdateAI(uint32 diff) override
+ bool CheckInRoom()
{
- if (!UpdateVictim())
- return;
-
- if (CleaveTimer <= diff)
+ if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
{
- DoCastVictim(SPELL_CLEAVE);
- CleaveTimer = urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS);
- } else CleaveTimer -= diff;
+ EnterEvadeMode();
+ Talk(SAY_EVADE);
+ return false;
+ }
- if (FrighteningShoutTimer <= diff)
- {
- DoCastVictim(SPELL_FRIGHTENING_SHOUT);
- FrighteningShoutTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS);
- } else FrighteningShoutTimer -= diff;
+ return true;
+ }
- if (Whirlwind1Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND1);
- Whirlwind1Timer = urand(6 * IN_MILLISECONDS, 10 * IN_MILLISECONDS);
- } else Whirlwind1Timer -= diff;
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || !CheckInRoom())
+ return;
- if (Whirlwind2Timer <= diff)
- {
- DoCastVictim(SPELL_WHIRLWIND2);
- Whirlwind2Timer = urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS);
- } else Whirlwind2Timer -= diff;
+ events.Update(diff);
- if (MortalStrikeTimer <= diff)
- {
- DoCastVictim(SPELL_MORTAL_STRIKE);
- MortalStrikeTimer = urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS);
- } else MortalStrikeTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- // check if creature is not outside of building
- if (ResetTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50)
+ switch (eventId)
{
- EnterEvadeMode();
- Talk(YELL_EVADE);
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, urand(10 * IN_MILLISECONDS, 16 * IN_MILLISECONDS));
+ break;
+ case EVENT_FRIGHTENING_SHOUT:
+ DoCastVictim(SPELL_FRIGHTENING_SHOUT);
+ events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND1:
+ DoCastVictim(SPELL_WHIRLWIND1);
+ events.ScheduleEvent(EVENT_WHIRLWIND1, urand(6 * IN_MILLISECONDS, 10 * IN_MILLISECONDS));
+ break;
+ case EVENT_WHIRLWIND2:
+ DoCastVictim(SPELL_WHIRLWIND2);
+ events.ScheduleEvent(EVENT_WHIRLWIND2, urand(10 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
+ break;
+ case EVENT_MORTAL_STRIKE:
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(10 * IN_MILLISECONDS, 30 * IN_MILLISECONDS));
+ break;
+ default:
+ break;
}
- ResetTimer = 5 * IN_MILLISECONDS;
- } else ResetTimer -= diff;
+ }
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
index b218e3f2978..c5f7a5da6d7 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp
@@ -21,7 +21,7 @@
enum Spells
{
SPELL_CURSE_OF_BLOOD = 24673,
- SPELL_ILLUSION = 17773,
+ SPELL_ILLUSION = 17773
};
enum Events
@@ -113,7 +113,7 @@ public:
CreatureAI* GetAI(Creature* creature) const override
{
- return new boss_jandicebarovAI(creature);
+ return GetInstanceAI<boss_jandicebarovAI>(creature);
}
};
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
index 897799a708c..348e2212870 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
@@ -81,7 +81,7 @@ public:
events.ScheduleEvent(EVENT_ICE_ARMOR, 180000);
break;
case EVENT_FROSTBOLT:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
DoCast(target, SPELL_FROSTBOLT);
events.ScheduleEvent(EVENT_FROSTBOLT, 8000);
break;
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
index 792649f2998..dcb212eead8 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp
@@ -106,7 +106,6 @@ public:
EventMap events;
};
-
CreatureAI* GetAI(Creature* creature) const override
{
return new boss_vectusAI(creature);
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
index 0a666488e84..fa87247f19f 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp
@@ -87,14 +87,14 @@ public:
{
Initialize();
- instance->SetData(DATA_EPOCH_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_EPOCH, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_EPOCH_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_EPOCH, IN_PROGRESS);
}
void UpdateAI(uint32 diff) override
@@ -136,7 +136,7 @@ public:
{
Talk(SAY_DEATH);
- instance->SetData(DATA_EPOCH_EVENT, DONE);
+ instance->SetBossState(DATA_EPOCH, DONE);
}
void KilledUnit(Unit* victim) override
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
index f3333c0b0b6..d693ec38e44 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp
@@ -22,7 +22,9 @@
enum Spells
{
SPELL_CORRUPTING_BLIGHT = 60588,
- SPELL_VOID_STRIKE = 60590
+ SPELL_VOID_STRIKE = 60590,
+ SPELL_CORRUPTION_OF_TIME_CHANNEL = 60422,
+ SPELL_CORRUPTION_OF_TIME_TARGET = 60451
};
enum Yells
@@ -32,52 +34,78 @@ enum Yells
SAY_FAIL = 2
};
-class boss_infinite_corruptor : public CreatureScript
+enum Events
{
-public:
- boss_infinite_corruptor() : CreatureScript("boss_infinite_corruptor") { }
+ EVENT_CORRUPTING_BLIGHT = 1,
+ EVENT_VOID_STRIKE
+};
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_infinite_corruptorAI>(creature);
- }
+class boss_infinite_corruptor : public CreatureScript
+{
+ public:
+ boss_infinite_corruptor() : CreatureScript("boss_infinite_corruptor") { }
- struct boss_infinite_corruptorAI : public ScriptedAI
- {
- boss_infinite_corruptorAI(Creature* creature) : ScriptedAI(creature)
+ struct boss_infinite_corruptorAI : public BossAI
{
- instance = creature->GetInstanceScript();
- }
+ boss_infinite_corruptorAI(Creature* creature) : BossAI(creature, DATA_INFINITE) { }
- InstanceScript* instance;
+ void Reset() override
+ {
+ _Reset();
- void Reset() override
- {
- instance->SetData(DATA_INFINITE_EVENT, NOT_STARTED);
- }
+ if (Creature* guardian = me->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ {
+ DoCast((Unit*)NULL, SPELL_CORRUPTION_OF_TIME_CHANNEL, false);
+ guardian->CastSpell(guardian, SPELL_CORRUPTION_OF_TIME_TARGET, false);
+ }
+ }
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
- instance->SetData(DATA_INFINITE_EVENT, IN_PROGRESS);
- }
+ void EnterCombat(Unit* /*who*/) override
+ {
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_CORRUPTING_BLIGHT, 7000);
+ events.ScheduleEvent(EVENT_VOID_STRIKE, 5000);
+ }
- void UpdateAI(uint32 /*diff*/) override
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
- DoMeleeAttackIfReady();
- }
+ if (Creature* guardian = me->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ {
+ guardian->RemoveAurasDueToSpell(SPELL_CORRUPTION_OF_TIME_TARGET);
+ guardian->DespawnOrUnsummon(5000);
+ }
- void JustDied(Unit* /*killer*/) override
+ if (Creature* rift = me->FindNearestCreature(NPC_TIME_RIFT, 100.0f))
+ rift->DespawnOrUnsummon();
+ }
+
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
+ {
+ case EVENT_CORRUPTING_BLIGHT:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
+ DoCast(target, SPELL_CORRUPTING_BLIGHT);
+ events.ScheduleEvent(EVENT_CORRUPTING_BLIGHT, 17000);
+ break;
+ case EVENT_VOID_STRIKE:
+ DoCastVictim(SPELL_VOID_STRIKE);
+ events.ScheduleEvent(EVENT_VOID_STRIKE, 5000);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
{
- Talk(SAY_DEATH);
- instance->SetData(DATA_INFINITE_EVENT, DONE);
+ return GetInstanceAI<boss_infinite_corruptorAI>(creature);
}
- };
-
};
void AddSC_boss_infinite_corruptor()
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
index d9356b724c0..3d1e9363cd8 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp
@@ -26,15 +26,13 @@ Script Data End */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "culling_of_stratholme.h"
+#include "Player.h"
enum Spells
{
SPELL_CARRION_SWARM = 52720, //A cresting wave of chaotic magic splashes over enemies in front of the caster, dealing 3230 to 3570 Shadow damage and 380 to 420 Shadow damage every 3 sec. for 15 sec.
- H_SPELL_CARRION_SWARM = 58852,
SPELL_MIND_BLAST = 52722, //Inflicts 4163 to 4837 Shadow damage to an enemy.
- H_SPELL_MIND_BLAST = 58850,
SPELL_SLEEP = 52721, //Puts an enemy to sleep for up to 10 sec. Any damage caused will awaken the target.
- H_SPELL_SLEEP = 58849,
SPELL_VAMPIRIC_TOUCH = 52723, //Heals the caster for half the damage dealt by a melee attack.
SPELL_MAL_GANIS_KILL_CREDIT = 58124, // Quest credit
SPELL_KILL_CREDIT = 58630 // Non-existing spell as encounter credit, created in spell_dbc
@@ -75,7 +73,6 @@ public:
{
Initialize();
instance = creature->GetInstanceScript();
- uiOutroStep = 0;
}
void Initialize()
@@ -108,14 +105,13 @@ public:
void Reset() override
{
Initialize();
-
- instance->SetData(DATA_MAL_GANIS_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_MAL_GANIS, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_MAL_GANIS_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_MAL_GANIS, IN_PROGRESS);
}
void DamageTaken(Unit* done_by, uint32 &damage) override
@@ -159,7 +155,7 @@ public:
{
EnterEvadeMode();
me->DisappearAndDie();
- instance->SetData(DATA_MAL_GANIS_EVENT, FAIL);
+ instance->SetBossState(DATA_MAL_GANIS, FAIL);
}
if (uiCarrionSwarmTimer < diff)
@@ -197,7 +193,7 @@ public:
switch (uiOutroStep)
{
case 1:
- Talk(SAY_ESCAPE_SPEECH_1);
+ Talk(SAY_OUTRO);
me->GetMotionMaster()->MoveTargetedHome();
++uiOutroStep;
uiOutroTimer = 8000;
@@ -212,7 +208,7 @@ public:
case 3:
Talk(SAY_OUTRO);
++uiOutroStep;
- uiOutroTimer = 16000;
+ //uiOutroTimer = 16000;
break;
case 4:
me->HandleEmoteCommand(33);
@@ -232,7 +228,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
- instance->SetData(DATA_MAL_GANIS_EVENT, DONE);
+ instance->SetBossState(DATA_MAL_GANIS, DONE);
DoCastAOE(SPELL_MAL_GANIS_KILL_CREDIT);
// give achievement credit and LFG rewards to players. criteria use spell 58630 which doesn't exist, but it was created in spell_dbc
DoCastAOE(SPELL_KILL_CREDIT);
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
index c961bf9b2c6..143f901ec0b 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp
@@ -15,14 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* Script Data Start
-SDName: Boss meathook
-SDAuthor: Tartalo
-SD%Complete: 100
-SDComment: It may need timer adjustment
-SDCategory:
-Script Data End */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "culling_of_stratholme.h"
@@ -30,9 +22,7 @@ Script Data End */
enum Spells
{
SPELL_CONSTRICTING_CHAINS = 52696, //Encases the targets in chains, dealing 1800 Physical damage every 1 sec. and stunning the target for 5 sec.
- H_SPELL_CONSTRICTING_CHAINS = 58823,
SPELL_DISEASE_EXPULSION = 52666, //Meathook belches out a cloud of disease, dealing 1710 to 1890 Nature damage and interrupting the spell casting of nearby enemy targets for 4 sec.
- H_SPELL_DISEASE_EXPULSION = 58824,
SPELL_FRENZY = 58841 //Increases the caster's Physical damage by 10% for 30 sec.
};
@@ -44,96 +34,72 @@ enum Yells
SAY_DEATH = 3
};
-class boss_meathook : public CreatureScript
+enum Events
{
-public:
- boss_meathook() : CreatureScript("boss_meathook") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_meathookAI>(creature);
- }
-
- struct boss_meathookAI : public ScriptedAI
- {
- boss_meathookAI(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- Talk(SAY_SPAWN);
- }
-
- void Initialize()
- {
- uiChainTimer = urand(12000, 17000); //seen on video 13, 17, 15, 12, 16
- uiDiseaseTimer = urand(2000, 4000); //approx 3s
- uiFrenzyTimer = urand(21000, 26000); //made it up
- }
-
- uint32 uiChainTimer;
- uint32 uiDiseaseTimer;
- uint32 uiFrenzyTimer;
-
- InstanceScript* instance;
-
- void Reset() override
- {
- Initialize();
-
- instance->SetData(DATA_MEATHOOK_EVENT, NOT_STARTED);
- }
-
- void EnterCombat(Unit* /*who*/) override
- {
- Talk(SAY_AGGRO);
+ EVENT_CHAIN = 1,
+ EVENT_DISEASE,
+ EVENT_FRENZY
+};
- instance->SetData(DATA_MEATHOOK_EVENT, IN_PROGRESS);
- }
+class boss_meathook : public CreatureScript
+{
+ public:
+ boss_meathook() : CreatureScript("boss_meathook") { }
- void UpdateAI(uint32 diff) override
+ struct boss_meathookAI : public BossAI
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (uiDiseaseTimer <= diff)
+ boss_meathookAI(Creature* creature) : BossAI(creature, DATA_MEATHOOK)
{
- DoCastAOE(SPELL_DISEASE_EXPULSION);
- uiDiseaseTimer = urand(1500, 4000);
- } else uiDiseaseTimer -= diff;
+ Talk(SAY_SPAWN);
+ }
- if (uiFrenzyTimer <= diff)
+ void EnterCombat(Unit* /*who*/) override
{
- DoCast(me, SPELL_FRENZY);
- uiFrenzyTimer = urand(21000, 26000);
- } else uiFrenzyTimer -= diff;
-
- if (uiChainTimer <= diff)
+ Talk(SAY_AGGRO);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_CHAIN, urand(12000, 17000));
+ events.ScheduleEvent(EVENT_DISEASE, urand(2000, 4000));
+ events.ScheduleEvent(EVENT_FRENZY, urand(21000, 26000));
+ }
+
+ void ExecuteEvent(uint32 eventId) override
{
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
- DoCast(target, SPELL_CONSTRICTING_CHAINS); //anyone but the tank
- uiChainTimer = urand(2000, 4000);
- } else uiChainTimer -= diff;
-
- DoMeleeAttackIfReady();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
+ switch (eventId)
+ {
+ case EVENT_CHAIN:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_CONSTRICTING_CHAINS);
+ events.ScheduleEvent(EVENT_CHAIN, urand(2000, 4000));
+ case EVENT_DISEASE:
+ DoCastAOE(SPELL_DISEASE_EXPULSION);
+ events.ScheduleEvent(EVENT_DISEASE, urand(1500, 4000));
+ break;
+ case EVENT_FRENZY:
+ DoCast(me, SPELL_FRENZY);
+ events.ScheduleEvent(EVENT_FRENZY, urand(21000, 26000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
- instance->SetData(DATA_MEATHOOK_EVENT, DONE);
- }
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+ };
- void KilledUnit(Unit* victim) override
+ CreatureAI* GetAI(Creature* creature) const override
{
- if (victim->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_SLAY);
+ return GetInstanceAI<boss_meathookAI>(creature);
}
- };
-
};
void AddSC_boss_meathook()
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
index 1c35a38a5e3..6925badf272 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp
@@ -89,14 +89,14 @@ public:
{
Initialize();
- instance->SetData(DATA_SALRAMM_EVENT, NOT_STARTED);
+ instance->SetBossState(DATA_SALRAMM, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
- instance->SetData(DATA_SALRAMM_EVENT, IN_PROGRESS);
+ instance->SetBossState(DATA_SALRAMM, IN_PROGRESS);
}
void UpdateAI(uint32 diff) override
@@ -145,7 +145,7 @@ public:
{
Talk(SAY_DEATH);
- instance->SetData(DATA_SALRAMM_EVENT, DONE);
+ instance->SetBossState(DATA_SALRAMM, DONE);
}
void KilledUnit(Unit* victim) override
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
index b8a9b295161..3c80be2734a 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
@@ -103,7 +103,7 @@ enum Says
//Drakonian
SAY_PHASE302 = 0,
- SAY_PHASE305 = 1,
+ SAY_PHASE305 = 1
};
enum NPCs
@@ -111,7 +111,6 @@ enum NPCs
NPC_INFINITE_ADVERSARY = 27742,
NPC_INFINITE_HUNTER = 27743,
NPC_INFINITE_AGENT = 27744,
- NPC_TIME_RIFT = 28409,
NPC_ZOMBIE = 27737,
NPC_GHOUL = 28249,
NPC_NECROMANCER = 28200,
@@ -128,7 +127,7 @@ enum NPCs
NPC_CITY_MAN = 28167,
NPC_CITY_MAN2 = 28169,
NPC_CITY_MAN3 = 31126,
- NPC_CITY_MAN4 = 31127,
+ NPC_CITY_MAN4 = 31127
};
enum Spells
@@ -138,7 +137,7 @@ enum Spells
SPELL_EXORCISM_N = 52445,
SPELL_EXORCISM_H = 58822,
SPELL_HOLY_LIGHT = 52444,
- SPELL_ARCANE_DISRUPTION = 49590,
+ SPELL_ARCANE_DISRUPTION = 49590
};
enum GossipMenuArthas
@@ -392,6 +391,7 @@ public:
uint32 gossipStep;
uint32 bossEvent;
uint32 wave;
+ uint32 WavesCounter;
uint64 utherGUID;
uint64 jainaGUID;
@@ -411,17 +411,19 @@ public:
{
Initialize();
- instance->SetData(DATA_ARTHAS_EVENT, NOT_STARTED);
- switch (instance->GetData(DATA_ARTHAS_EVENT))
- {
- case NOT_STARTED:
- bStepping = true;
- step = 0;
- me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- bossEvent = DATA_MEATHOOK_EVENT;
- gossipStep = 0;
- break;
- }
+ instance->SetBossState(DATA_ARTHAS, NOT_STARTED);
+
+ bStepping = true;
+ step = 0;
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ bossEvent = DATA_MEATHOOK;
+ gossipStep = 0;
+ }
+
+ void AttackStart(Unit* who)
+ {
+ if (who && !who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC))
+ npc_escortAI::AttackStart(who);
}
void EnterCombat(Unit* /*who*/) override
@@ -431,7 +433,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
- instance->SetData(DATA_ARTHAS_EVENT, FAIL);
+ instance->SetBossState(DATA_ARTHAS, FAIL);
}
void SpawnTimeRift(uint32 timeRiftID, uint64* guidVector)
@@ -488,16 +490,15 @@ public:
case 11:
case 22:
case 23:
- case 26:
case 55:
case 56:
SetHoldState(true);
bStepping = true;
break;
case 7:
- if (Unit* cityman0 = me->SummonCreature(NPC_CITY_MAN, 2091.977f, 1275.021f, 140.757f, 0.558f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000))
+ if (Unit* cityman0 = me->FindNearestCreature(NPC_CITY_MAN, 160.0f))
citymenGUID[0] = cityman0->GetGUID();
- if (Unit* cityman1 = me->SummonCreature(NPC_CITY_MAN2, 2093.514f, 1275.842f, 140.408f, 3.801f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000))
+ if (Unit* cityman1 = me->FindNearestCreature(NPC_CITY_MAN2, 160.0f))
citymenGUID[1] = cityman1->GetGUID();
break;
case 8:
@@ -534,10 +535,12 @@ public:
case 21:
Talk(SAY_PHASE301);
break;
- case 25:
+ case 26:
SetRun(false);
SpawnTimeRift(0, &infiniteDraconianGUID[0]);
Talk(SAY_PHASE307);
+ SetHoldState(true);
+ bStepping = true;
break;
case 29:
SetRun(false);
@@ -565,8 +568,8 @@ public:
Talk(SAY_PHASE403);
break;
case 36:
- if (GameObject* pGate = instance->instance->GetGameObject(instance->GetData64(DATA_SHKAF_GATE)))
- pGate->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_SHKAF_GATE)))
+ gate->SetGoState(GO_STATE_ACTIVE);
break;
case 45:
SetRun(true);
@@ -575,18 +578,18 @@ public:
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
SetHoldState(true);
break;
- case 47:
+ case 48:
SetRun(false);
Talk(SAY_PHASE405);
break;
- case 48:
+ case 49:
SetRun(true);
Talk(SAY_PHASE406);
break;
- case 53:
+ case 50:
Talk(SAY_PHASE407);
break;
- case 54:
+ case 51:
gossipStep = 5;
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
SetHoldState(true);
@@ -598,8 +601,6 @@ public:
{
npc_escortAI::UpdateAI(diff);
- DoMeleeAttackIfReady();
-
if (bStepping)
{
if (phaseTimer <= diff)
@@ -765,6 +766,9 @@ public:
stalkerGUID = pStalker->GetGUID();
me->SetTarget(stalkerGUID);
}
+
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, 0);
+
JumpToNextStep(1000);
break;
case 25:
@@ -892,14 +896,15 @@ public:
}
Talk(SAY_PHASE209);
- bossEvent = DATA_MEATHOOK_EVENT;
- instance->SetData(DATA_ARTHAS_EVENT, IN_PROGRESS);
+ bossEvent = DATA_MEATHOOK;
+ instance->SetBossState(DATA_ARTHAS, IN_PROGRESS);
me->SetReactState(REACT_DEFENSIVE);
SetDespawnAtFar(false);
JumpToNextStep(5000);
break;
- case 41: //Summon wave group
+ // Summon wave groups - start the Infinite Corruptor timer
+ case 41:
case 43:
case 45:
case 47:
@@ -907,10 +912,15 @@ public:
case 53:
case 55:
case 57:
- if (instance->GetData(bossEvent) != DONE)
+ if (!wave && IsHeroic() && instance->GetData(DATA_INFINITE_COUNTER) == NOT_STARTED)
+ instance->SetData(DATA_INFINITE_COUNTER, IN_PROGRESS);
+
+ if (instance->GetBossState(bossEvent) != DONE)
{
SpawnWaveGroup(wave, waveGUID);
wave++;
+ WavesCounter++;
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, WavesCounter);
}
JumpToNextStep(500);
break;
@@ -922,7 +932,7 @@ public:
case 54:
case 56:
case 58:
- if (instance->GetData(bossEvent) != DONE)
+ if (instance->GetBossState(bossEvent) != DONE)
{
uint32 mobCounter = 0;
uint32 deadCounter = 0;
@@ -946,12 +956,14 @@ public:
break;
case 49: //Summon Boss
case 59:
- if (instance->GetData(bossEvent) != DONE)
+ if (instance->GetBossState(bossEvent) != DONE)
{
+ WavesCounter++;
+ instance->DoUpdateWorldState(WORLDSTATE_WAVE_COUNT, WavesCounter);
uint32 uiBossID = 0;
- if (bossEvent == DATA_MEATHOOK_EVENT)
+ if (bossEvent == DATA_MEATHOOK)
uiBossID = NPC_MEATHOOK;
- else if (bossEvent == DATA_SALRAMM_EVENT)
+ else if (bossEvent == DATA_SALRAMM)
uiBossID = NPC_SALRAMM;
if (Unit* pBoss = me->SummonCreature(uiBossID, 2232.19f, 1331.933f, 126.662f, 3.15f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000))
@@ -965,19 +977,19 @@ public:
break;
case 50: //Wait Boss death
case 60:
- if (instance->GetData(bossEvent) == DONE)
+ if (instance->GetBossState(bossEvent) == DONE)
{
JumpToNextStep(1000);
- if (bossEvent == DATA_MEATHOOK_EVENT)
- bossEvent = DATA_SALRAMM_EVENT;
- else if (bossEvent == DATA_SALRAMM_EVENT)
+ if (bossEvent == DATA_MEATHOOK)
+ bossEvent = DATA_SALRAMM;
+ else if (bossEvent == DATA_SALRAMM)
{
SetHoldState(false);
bStepping = false;
- bossEvent = DATA_EPOCH_EVENT;
+ bossEvent = DATA_EPOCH;
}
}
- else if (instance->GetData(bossEvent) == FAIL)
+ else if (instance->GetBossState(bossEvent) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1074,9 +1086,12 @@ public:
phaseTimer = 1000;
else
{
- if (step == 72) Talk(SAY_PHASE308);
- if (step == 74) Talk(SAY_PHASE308);
- if (step == 76) Talk(SAY_PHASE310);
+ if (step == 72)
+ Talk(SAY_PHASE308);
+ if (step == 74)
+ Talk(SAY_PHASE308);
+ if (step == 76)
+ Talk(SAY_PHASE310);
SetHoldState(false);
bStepping = false;
SetRun(true);
@@ -1097,7 +1112,7 @@ public:
JumpToNextStep(1000);
break;
case 80:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
{
SpawnTimeRift(17, &epochGUID);
if (Creature* epoch = ObjectAccessor::GetCreature(*me, epochGUID))
@@ -1107,12 +1122,12 @@ public:
JumpToNextStep(18000);
break;
case 81:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
Talk(SAY_PHASE315);
JumpToNextStep(6000);
break;
case 82:
- if (instance->GetData(DATA_EPOCH_EVENT) != DONE)
+ if (instance->GetBossState(DATA_EPOCH) != DONE)
{
if (Creature* epoch = ObjectAccessor::GetCreature(*me, epochGUID))
{
@@ -1126,15 +1141,15 @@ public:
JumpToNextStep(1000);
break;
case 83:
- if (instance->GetData(DATA_EPOCH_EVENT) == DONE)
+ if (instance->GetBossState(DATA_EPOCH) == DONE)
{
gossipStep = 3;
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
bStepping = false;
- bossEvent = DATA_MAL_GANIS_EVENT;
+ bossEvent = DATA_MAL_GANIS;
JumpToNextStep(15000);
}
- else if (instance->GetData(DATA_EPOCH_EVENT) == FAIL)
+ else if (instance->GetBossState(DATA_EPOCH) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1153,8 +1168,8 @@ public:
malganisGUID = malganis->GetGUID();
malganis->SetReactState(REACT_PASSIVE);
}
- if (GameObject* pGate = instance->instance->GetGameObject(instance->GetData64(DATA_MAL_GANIS_GATE_1)))
- pGate->SetGoState(GO_STATE_ACTIVE);
+ if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MAL_GANIS_GATE_1)))
+ gate->SetGoState(GO_STATE_ACTIVE);
SetHoldState(false);
bStepping = false;
JumpToNextStep(0);
@@ -1174,12 +1189,12 @@ public:
JumpToNextStep(1000);
break;
case 88:
- if (instance->GetData(DATA_MAL_GANIS_EVENT) == DONE)
+ if (instance->GetBossState(DATA_MAL_GANIS) == DONE)
{
SetHoldState(false);
JumpToNextStep(1000);
}
- else if (instance->GetData(DATA_MAL_GANIS_EVENT) == FAIL)
+ else if (instance->GetBossState(DATA_MAL_GANIS) == FAIL)
npc_escortAI::EnterEvadeMode();
else
phaseTimer = 10000;
@@ -1192,7 +1207,7 @@ public:
JumpToNextStep(7000);
break;
case 90:
- instance->SetData(DATA_ARTHAS_EVENT, DONE); //Rewards: Achiev & Chest ;D
+ instance->SetBossState(DATA_ARTHAS, DONE); //Rewards: Achiev & Chest ;D
me->SetTarget(instance->GetData64(DATA_MAL_GANIS_GATE_2)); //Look behind
Talk(SAY_PHASE504);
bStepping = false;
@@ -1214,6 +1229,8 @@ public:
if (HealthBelowPct(40))
DoCast(me, SPELL_HOLY_LIGHT);
+
+ DoMeleeAttackIfReady();
}
};
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
index e7d1033e55f..192654c87f1 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h
@@ -19,19 +19,10 @@
#define DEF_CULLING_OF_STRATHOLME_H
#define DataHeader "CS"
+#define CoSScriptName "instance_culling_of_stratholme"
+uint32 const EncounterCount = 5;
-enum Data
-{
- DATA_MEATHOOK_EVENT,
- DATA_SALRAMM_EVENT,
- DATA_EPOCH_EVENT,
- DATA_MAL_GANIS_EVENT,
- DATA_INFINITE_EVENT,
- DATA_ARTHAS_EVENT,
- DATA_CRATE_COUNT,
-};
-
-enum Data64
+enum DataTypes
{
DATA_ARTHAS,
DATA_MEATHOOK,
@@ -39,28 +30,35 @@ enum Data64
DATA_EPOCH,
DATA_MAL_GANIS,
DATA_INFINITE,
+ DATA_CRATE_COUNT,
DATA_SHKAF_GATE,
DATA_MAL_GANIS_GATE_1,
DATA_MAL_GANIS_GATE_2,
DATA_EXIT_GATE,
- DATA_MAL_GANIS_CHEST
+ DATA_MAL_GANIS_CHEST,
+ DATA_INFINITE_COUNTER
};
-enum Creatures
+enum CreatureIds
{
- NPC_MEATHOOK = 26529,
- NPC_SALRAMM = 26530,
- NPC_EPOCH = 26532,
- NPC_MAL_GANIS = 26533,
- NPC_INFINITE = 32273,
- NPC_ARTHAS = 26499,
- NPC_JAINA = 26497,
- NPC_UTHER = 26528,
- NPC_CHROMIE_2 = 27915,
- NPC_GENERIC_BUNNY = 28960,
+ NPC_MEATHOOK = 26529,
+ NPC_SALRAMM = 26530,
+ NPC_EPOCH = 26532,
+ NPC_MAL_GANIS = 26533,
+ NPC_INFINITE = 32273,
+ NPC_ARTHAS = 26499,
+ NPC_JAINA = 26497,
+ NPC_UTHER = 26528,
+ NPC_CHROMIE = 26527,
+ NPC_CHROMIE_2 = 27915,
+ NPC_CHROMIE_3 = 30997,
+ NPC_GENERIC_BUNNY = 28960,
+
+ NPC_TIME_RIFT = 28409,
+ NPC_GUARDIAN_OF_TIME = 32281
};
-enum GameObjects
+enum GameObjectIds
{
GO_SHKAF_GATE = 188686,
GO_MALGANIS_GATE_1 = 187711,
@@ -69,7 +67,7 @@ enum GameObjects
GO_MALGANIS_CHEST_N = 190663,
GO_MALGANIS_CHEST_H = 193597,
GO_SUSPICIOUS_CRATE = 190094,
- GO_PLAGUED_CRATE = 190095,
+ GO_PLAGUED_CRATE = 190095
};
enum WorldStatesCoT
@@ -78,12 +76,28 @@ enum WorldStatesCoT
WORLDSTATE_CRATES_REVEALED = 3480,
WORLDSTATE_WAVE_COUNT = 3504,
WORLDSTATE_TIME_GUARDIAN = 3931,
- WORLDSTATE_TIME_GUARDIAN_SHOW = 3932,
+ WORLDSTATE_TIME_GUARDIAN_SHOW = 3932
};
enum CrateSpells
{
- SPELL_CRATES_CREDIT = 58109,
+ SPELL_CRATES_CREDIT = 58109
+};
+
+enum Texts
+{
+ SAY_CRATES_COMPLETED = 0,
+ // Chromie
+ SAY_INFINITE_START = 0, // On Infinite Corruptor event start
+ SAY_INFINITE = 1, // On Infinite Corruptor event at 5 minutes
+ SAY_INFINITE_FAIL = 2, // On Infinite Corruptor event fail
+ // Infinite Corruptor
+ SAY_FAIL_EVENT = 2 // On Infinite Corruptor event fail
+};
+
+enum InstanceEvents
+{
+ EVENT_INFINITE_TIMER = 1
};
#endif
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
index 7af2b3f63aa..b3e8d88bc2a 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp
@@ -23,8 +23,6 @@
#include "TemporarySummon.h"
#include "SpellInfo.h"
-#define MAX_ENCOUNTER 5
-
/* Culling of Stratholme encounters:
0 - Meathook
1 - Salramm the Fleshcrafter
@@ -33,51 +31,51 @@
4 - Infinite Corruptor (Heroic only)
*/
-enum Texts
+Position const ChromieSummonPos[] =
{
- SAY_CRATES_COMPLETED = 0,
+ { 1813.298f, 1283.578f, 142.3258f, 3.878161f },
+ { 2273.725f, 1483.684f, 128.7205f, 6.057528f }
};
-Position const ChromieSummonPos = {1813.298f, 1283.578f, 142.3258f, 3.878161f};
+Position const InfiniteCorruptorPos = { 2335.47f, 1262.04f, 132.921f, 1.42079f };
+Position const TimeRiftPos = { 2334.626f, 1280.45f, 133.0066f, 1.727876f };
+Position const GuardianOfTimePos = { 2321.489f, 1268.383f, 132.8507f, 0.418879f };
+
+DoorData const doorData[] =
+{
+ { GO_MALGANIS_GATE_2, DATA_MAL_GANIS, DOOR_TYPE_ROOM, BOUNDARY_NONE },
+ { GO_EXIT_GATE, DATA_MAL_GANIS, DOOR_TYPE_PASSAGE, BOUNDARY_NONE },
+ { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
+};
class instance_culling_of_stratholme : public InstanceMapScript
{
public:
- instance_culling_of_stratholme() : InstanceMapScript("instance_culling_of_stratholme", 595) { }
-
- InstanceScript* GetInstanceScript(InstanceMap* map) const override
- {
- return new instance_culling_of_stratholme_InstanceMapScript(map);
- }
+ instance_culling_of_stratholme() : InstanceMapScript(CoSScriptName, 595) { }
struct instance_culling_of_stratholme_InstanceMapScript : public InstanceScript
{
instance_culling_of_stratholme_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
- _arthasGUID = 0;
- _meathookGUID = 0;
- _salrammGUID = 0;
- _epochGUID = 0;
- _malGanisGUID = 0;
- _infiniteGUID = 0;
- _shkafGateGUID = 0;
+ SetBossNumber(EncounterCount);
+ LoadDoorData(doorData);
+
+ _chromieGUID = 0;
+ _arthasGUID = 0;
+ _meathookGUID = 0;
+ _salrammGUID = 0;
+ _epochGUID = 0;
+ _malGanisGUID = 0;
+ _infiniteGUID = 0;
+ _shkafGateGUID = 0;
_malGanisGate1GUID = 0;
_malGanisGate2GUID = 0;
- _exitGateGUID = 0;
+ _exitGateGUID = 0;
_malGanisChestGUID = 0;
- _genericBunnyGUID = 0;
- memset(&_encounterState[0], 0, sizeof(uint32) * MAX_ENCOUNTER);
- _crateCount = 0;
- }
-
- bool IsEncounterInProgress() const override
- {
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (_encounterState[i] == IN_PROGRESS)
- return true;
-
- return false;
+ _genericBunnyGUID = 0;
+ _crateCount = 0;
+ _eventTimer = 0;
}
void FillInitialWorldStates(WorldPacket& data) override
@@ -93,6 +91,9 @@ class instance_culling_of_stratholme : public InstanceMapScript
{
switch (creature->GetEntry())
{
+ case NPC_CHROMIE:
+ _chromieGUID = creature->GetGUID();
+ break;
case NPC_ARTHAS:
_arthasGUID = creature->GetGUID();
break;
@@ -110,10 +111,13 @@ class instance_culling_of_stratholme : public InstanceMapScript
break;
case NPC_INFINITE:
_infiniteGUID = creature->GetGUID();
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 1);
break;
case NPC_GENERIC_BUNNY:
_genericBunnyGUID = creature->GetGUID();
break;
+ default:
+ break;
}
}
@@ -129,55 +133,38 @@ class instance_culling_of_stratholme : public InstanceMapScript
break;
case GO_MALGANIS_GATE_2:
_malGanisGate2GUID = go->GetGUID();
+ AddDoor(go, true);
break;
case GO_EXIT_GATE:
_exitGateGUID = go->GetGUID();
- if (_encounterState[3] == DONE)
- HandleGameObject(_exitGateGUID, true);
+ AddDoor(go, true);
break;
case GO_MALGANIS_CHEST_N:
case GO_MALGANIS_CHEST_H:
_malGanisChestGUID = go->GetGUID();
- if (_encounterState[3] == DONE)
- go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
+ break;
+ default:
break;
}
}
- void SetData(uint32 type, uint32 data) override
+ void OnGameObjectRemove(GameObject* go) override
{
- switch (type)
+ switch (go->GetEntry())
{
- case DATA_MEATHOOK_EVENT:
- _encounterState[0] = data;
- break;
- case DATA_SALRAMM_EVENT:
- _encounterState[1] = data;
+ case GO_MALGANIS_GATE_2:
+ case GO_EXIT_GATE:
+ AddDoor(go, false);
break;
- case DATA_EPOCH_EVENT:
- _encounterState[2] = data;
+ default:
break;
- case DATA_MAL_GANIS_EVENT:
- _encounterState[3] = data;
+ }
+ }
- switch (_encounterState[3])
- {
- case NOT_STARTED:
- HandleGameObject(_malGanisGate2GUID, true);
- break;
- case IN_PROGRESS:
- HandleGameObject(_malGanisGate2GUID, false);
- break;
- case DONE:
- HandleGameObject(_exitGateGUID, true);
- if (GameObject* go = instance->GetGameObject(_malGanisChestGUID))
- go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
- break;
- }
- break;
- case DATA_INFINITE_EVENT:
- _encounterState[4] = data;
- break;
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
case DATA_CRATE_COUNT:
_crateCount = data;
if (_crateCount == 5)
@@ -186,34 +173,70 @@ class instance_culling_of_stratholme : public InstanceMapScript
bunny->CastSpell(bunny, SPELL_CRATES_CREDIT, true);
// Summon Chromie and global whisper
- if (Creature* chromie = instance->SummonCreature(NPC_CHROMIE_2, ChromieSummonPos))
+ if (Creature* chromie = instance->SummonCreature(NPC_CHROMIE_2, ChromieSummonPos[0]))
if (!instance->GetPlayers().isEmpty())
chromie->AI()->TalkToMap(SAY_CRATES_COMPLETED);
}
DoUpdateWorldState(WORLDSTATE_CRATES_REVEALED, _crateCount);
break;
+ case DATA_INFINITE_COUNTER:
+ _infiniteCouterState = data;
+ if (data == IN_PROGRESS)
+ {
+ if (!_infiniteGUID)
+ {
+ _eventTimer = 25;
+ instance->SummonCreature(NPC_INFINITE, InfiniteCorruptorPos);
+ instance->SummonCreature(NPC_TIME_RIFT, TimeRiftPos);
+ instance->SummonCreature(NPC_GUARDIAN_OF_TIME, GuardianOfTimePos);
+ events.ScheduleEvent(EVENT_INFINITE_TIMER, 1);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DATA_INFINITE:
+ if (state == DONE)
+ {
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 0);
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN, 0);
+ }
+ break;
+ case DATA_MAL_GANIS:
+ if (state == DONE)
+ {
+ if (GameObject* go = instance->GetGameObject(_malGanisChestGUID))
+ go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
+ instance->SummonCreature(NPC_CHROMIE_3, ChromieSummonPos[1]);
+ }
+ break;
+ default:
+ break;
}
- if (data == DONE)
- SaveToDB();
+ return true;
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
- case DATA_MEATHOOK_EVENT:
- return _encounterState[0];
- case DATA_SALRAMM_EVENT:
- return _encounterState[1];
- case DATA_EPOCH_EVENT:
- return _encounterState[2];
- case DATA_MAL_GANIS_EVENT:
- return _encounterState[3];
- case DATA_INFINITE_EVENT:
- return _encounterState[4];
case DATA_CRATE_COUNT:
return _crateCount;
+ case DATA_INFINITE_COUNTER:
+ return _infiniteCouterState;
+ default:
+ break;
}
return 0;
}
@@ -244,58 +267,70 @@ class instance_culling_of_stratholme : public InstanceMapScript
return _exitGateGUID;
case DATA_MAL_GANIS_CHEST:
return _malGanisChestGUID;
+ default:
+ break;
}
return 0;
}
- std::string GetSaveData() override
+ void Update(uint32 diff) override
{
- OUT_SAVE_INST_DATA;
+ events.Update(diff);
- std::ostringstream saveStream;
- saveStream << "C S " << _encounterState[0] << ' ' << _encounterState[1] << ' '
- << _encounterState[2] << ' ' << _encounterState[3] << ' ' << _encounterState[4];
-
- OUT_SAVE_INST_DATA_COMPLETE;
- return saveStream.str();
- }
-
- void Load(const char* in) override
- {
- if (!in)
+ while (uint32 eventId = events.ExecuteEvent())
{
- OUT_LOAD_INST_DATA_FAIL;
- return;
- }
-
- OUT_LOAD_INST_DATA(in);
-
- char dataHead1, dataHead2;
- uint16 data0, data1, data2, data3, data4;
-
- std::istringstream loadStream(in);
- loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4;
-
- if (dataHead1 == 'C' && dataHead2 == 'S')
- {
- _encounterState[0] = data0;
- _encounterState[1] = data1;
- _encounterState[2] = data2;
- _encounterState[3] = data3;
- _encounterState[4] = data4;
-
- for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (_encounterState[i] == IN_PROGRESS)
- _encounterState[i] = NOT_STARTED;
-
+ switch (eventId)
+ {
+ case EVENT_INFINITE_TIMER:
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN, _eventTimer);
+
+ switch (_eventTimer)
+ {
+ case 25:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE_START);
+ break;
+ case 5:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE);
+ break;
+ case 0:
+ if (instance->HavePlayers())
+ if (Creature* chromie = instance->GetCreature(_chromieGUID))
+ chromie->AI()->TalkToMap(SAY_INFINITE_FAIL);
+
+ if (Creature* infinite = instance->GetCreature(_infiniteGUID))
+ {
+ if (Creature* guardian = infinite->FindNearestCreature(NPC_GUARDIAN_OF_TIME, 100.0f))
+ infinite->Kill(guardian);
+
+ if (Creature* rift = infinite->FindNearestCreature(NPC_TIME_RIFT, 100.0f))
+ {
+ infinite->GetMotionMaster()->MovePoint(0, rift->GetPositionX(), rift->GetPositionY(), rift->GetPositionZ());
+ rift->DespawnOrUnsummon(3000);
+ }
+
+ infinite->DespawnOrUnsummon(3000);
+ infinite->AI()->Talk(SAY_FAIL_EVENT);
+ }
+ DoUpdateWorldState(WORLDSTATE_TIME_GUARDIAN_SHOW, 0);
+ return;
+ default:
+ break;
+ }
+ events.ScheduleEvent(EVENT_INFINITE_TIMER, 60000);
+ --_eventTimer;
+ break;
+ default:
+ break;
+ }
}
- else
- OUT_LOAD_INST_DATA_FAIL;
-
- OUT_LOAD_INST_DATA_COMPLETE;
}
private:
+ uint64 _chromieGUID;
uint64 _arthasGUID;
uint64 _meathookGUID;
uint64 _salrammGUID;
@@ -308,9 +343,18 @@ class instance_culling_of_stratholme : public InstanceMapScript
uint64 _exitGateGUID;
uint64 _malGanisChestGUID;
uint64 _genericBunnyGUID;
- uint32 _encounterState[MAX_ENCOUNTER];
+
uint32 _crateCount;
+ uint32 _eventTimer;
+ uint32 _infiniteCouterState;
+
+ EventMap events;
};
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_culling_of_stratholme_InstanceMapScript(map);
+ }
};
void AddSC_instance_culling_of_stratholme()
diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
index ff507f32bae..3670e225fd7 100644
--- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp
+++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp
@@ -487,6 +487,14 @@ public:
Talk(SAY_TWIGGY_FLATHEAD_OVER);
Reset();
}
+ else if (creature) // Makes BIG WILL attackable.
+ {
+ creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ creature->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ creature->setFaction(14);
+ creature->AI()->AttackStart(warrior);
+ }
}
} else WaveTimer -= diff;
}
diff --git a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
index 0783a79b381..9f8cc818958 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp
@@ -28,146 +28,92 @@ enum Spells
SPELL_ECK_SPRING_2 = 55837 //Eck leaps at a distant target.
};
-static Position EckSpawnPoint = { 1643.877930f, 936.278015f, 107.204948f, 0.668432f };
+enum Events
+{
+ EVENT_BITE = 1,
+ EVENT_SPIT,
+ EVENT_SPRING,
+ EVENT_BERSERK
+};
class boss_eck : public CreatureScript
{
public:
boss_eck() : CreatureScript("boss_eck") { }
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_eckAI>(creature);
- }
-
- struct boss_eckAI : public ScriptedAI
+ struct boss_eckAI : public BossAI
{
- boss_eckAI(Creature* creature) : ScriptedAI(creature)
+ boss_eckAI(Creature* creature) : BossAI(creature, DATA_ECK_THE_FEROCIOUS_EVENT)
{
Initialize();
- instance = creature->GetInstanceScript();
}
void Initialize()
{
- uiBerserkTimer = urand(60 * IN_MILLISECONDS, 90 * IN_MILLISECONDS); //60-90 secs according to wowwiki
- uiBiteTimer = 5 * IN_MILLISECONDS;
- uiSpitTimer = 10 * IN_MILLISECONDS;
- uiSpringTimer = 8 * IN_MILLISECONDS;
-
- bBerserk = false;
+ Berserk = false;
}
- uint32 uiBerserkTimer;
- uint32 uiBiteTimer;
- uint32 uiSpitTimer;
- uint32 uiSpringTimer;
-
- bool bBerserk;
-
- InstanceScript* instance;
-
void Reset() override
{
+ _Reset();
Initialize();
-
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) override
{
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, IN_PROGRESS);
+ _EnterCombat();
+ events.ScheduleEvent(EVENT_BITE, 5 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPIT, 10 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPRING, 8 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_BERSERK, urand(60 * IN_MILLISECONDS, 90 * IN_MILLISECONDS)); //60-90 secs according to wowwiki
}
- void UpdateAI(uint32 diff) override
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- if (uiBiteTimer <= diff)
- {
- DoCastVictim(SPELL_ECK_BITE);
- uiBiteTimer = urand(8*IN_MILLISECONDS, 12*IN_MILLISECONDS);
- } else uiBiteTimer -= diff;
-
- if (uiSpitTimer <= diff)
+ if (me->HealthBelowPctDamaged(20, damage) && !Berserk)
{
- DoCastVictim(SPELL_ECK_SPIT);
- uiSpitTimer = urand(6*IN_MILLISECONDS, 14*IN_MILLISECONDS);
- } else uiSpitTimer -= diff;
-
- if (uiSpringTimer <= diff)
- {
- Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- {
- DoCast(target, RAND(SPELL_ECK_SPRING_1, SPELL_ECK_SPRING_2));
- uiSpringTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS);
- }
- } else uiSpringTimer -= diff;
+ events.RescheduleEvent(EVENT_BERSERK, 1000);
+ Berserk = true;
+ }
+ }
- //Berserk on timer or 20% of health
- if (!bBerserk)
+ void ExecuteEvent(uint32 eventId) override
+ {
+ switch (eventId)
{
- if (uiBerserkTimer <= diff)
- {
+ case EVENT_BITE:
+ DoCastVictim(SPELL_ECK_BITE);
+ events.ScheduleEvent(EVENT_BITE, urand(8 * IN_MILLISECONDS, 12 * IN_MILLISECONDS));
+ break;
+ case EVENT_SPIT:
+ DoCastVictim(SPELL_ECK_SPIT);
+ events.ScheduleEvent(EVENT_SPIT, urand(6 * IN_MILLISECONDS, 14 * IN_MILLISECONDS));
+ break;
+ case EVENT_SPRING:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 35.0f, true))
+ DoCast(target, RAND(SPELL_ECK_SPRING_1, SPELL_ECK_SPRING_2));
+ events.ScheduleEvent(EVENT_SPRING, urand(5 * IN_MILLISECONDS, 10 * IN_MILLISECONDS));
+ break;
+ case EVENT_BERSERK:
DoCast(me, SPELL_ECK_BERSERK);
- bBerserk = true;
- }
- else
- {
- uiBerserkTimer -= diff;
- if (HealthBelowPct(20))
- {
- DoCast(me, SPELL_ECK_BERSERK);
- bBerserk = true;
- }
- }
+ Berserk = true;
+ break;
+ default:
+ break;
}
-
- DoMeleeAttackIfReady();
}
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, DONE);
- }
+ private:
+ bool Berserk;
};
-};
-
-class npc_ruins_dweller : public CreatureScript
-{
-public:
- npc_ruins_dweller() : CreatureScript("npc_ruins_dweller") { }
-
CreatureAI* GetAI(Creature* creature) const override
{
- return GetInstanceAI<npc_ruins_dwellerAI>(creature);
+ return GetInstanceAI<boss_eckAI>(creature);
}
-
- struct npc_ruins_dwellerAI : public ScriptedAI
- {
- npc_ruins_dwellerAI(Creature* creature) : ScriptedAI(creature)
- {
- instance = creature->GetInstanceScript();
- }
-
- InstanceScript* instance;
-
- void JustDied(Unit* /*killer*/) override
- {
- instance->SetData64(DATA_RUIN_DWELLER_DIED, me->GetGUID());
- if (instance->GetData(DATA_ALIVE_RUIN_DWELLERS) == 0)
- me->SummonCreature(CREATURE_ECK, EckSpawnPoint, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300*IN_MILLISECONDS);
- }
- };
-
};
void AddSC_boss_eck()
{
new boss_eck();
- new npc_ruins_dweller();
}
diff --git a/src/server/scripts/Northrend/Gundrak/gundrak.h b/src/server/scripts/Northrend/Gundrak/gundrak.h
index 8f269705a45..fffeca82f39 100644
--- a/src/server/scripts/Northrend/Gundrak/gundrak.h
+++ b/src/server/scripts/Northrend/Gundrak/gundrak.h
@@ -26,8 +26,7 @@ enum Data
DATA_MOORABI_EVENT,
DATA_DRAKKARI_COLOSSUS_EVENT,
DATA_GAL_DARAH_EVENT,
- DATA_ECK_THE_FEROCIOUS_EVENT,
- DATA_ALIVE_RUIN_DWELLERS
+ DATA_ECK_THE_FEROCIOUS_EVENT
};
enum Data64
@@ -39,8 +38,7 @@ enum Data64
DATA_MOORABI_STATUE,
DATA_DRAKKARI_COLOSSUS_STATUE,
DATA_DRAKKARI_COLOSSUS,
- DATA_RUIN_DWELLER_DIED,
- DATA_STATUE_ACTIVATE,
+ DATA_STATUE_ACTIVATE
};
enum mainCreatures
diff --git a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
index e5efdad27f3..388d43e8dca 100644
--- a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
+++ b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp
@@ -31,6 +31,8 @@
4 - Eck the Ferocious
*/
+Position const EckSpawnPoint = { 1643.877930f, 936.278015f, 107.204948f, 0.668432f };
+
class instance_gundrak : public InstanceMapScript
{
public:
@@ -134,7 +136,7 @@ public:
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
}
- bool IsEncounterInProgress() const override
+ bool IsEncounterInProgress() const override
{
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS)
@@ -274,6 +276,17 @@ public:
}
}
+ void OnUnitDeath(Unit* unit) override
+ {
+ if (unit->GetEntry() == CREATURE_RUIN_DWELLER)
+ {
+ DwellerGUIDs.erase(unit->GetGUID());
+
+ if (DwellerGUIDs.empty())
+ unit->SummonCreature(CREATURE_ECK, EckSpawnPoint, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300 * IN_MILLISECONDS);
+ }
+ }
+
void SetData(uint32 type, uint32 data) override
{
switch (type)
@@ -329,9 +342,7 @@ public:
void SetData64(uint32 type, uint64 data) override
{
- if (type == DATA_RUIN_DWELLER_DIED)
- DwellerGUIDs.erase(data);
- else if (type == DATA_STATUE_ACTIVATE)
+ if (type == DATA_STATUE_ACTIVATE)
{
toActivate = data;
timer = 3500;
@@ -353,8 +364,6 @@ public:
return m_auiEncounter[3];
case DATA_ECK_THE_FEROCIOUS_EVENT:
return m_auiEncounter[4];
- case DATA_ALIVE_RUIN_DWELLERS:
- return DwellerGUIDs.size();
}
return 0;
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 7f34e470c7e..a83f4feb70a 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -26,7 +26,6 @@ EndScriptData */
/* ContentData
npc_iruk
npc_corastrasza
-npc_jenny
npc_sinkhole_kill_credit
npc_khunok_the_behemoth
npc_nerubar_victim
@@ -407,125 +406,6 @@ public:
};
/*######
-## npc_jenny
-######*/
-
-enum Jenny
-{
- QUEST_LOADER_UP = 11881,
-
- NPC_FEZZIX_GEARTWIST = 25849,
- NPC_JENNY = 25969,
-
- SPELL_GIVE_JENNY_CREDIT = 46358,
- SPELL_CRATES_CARRIED = 46340,
- SPELL_DROP_CRATE = 46342
-};
-
-class npc_jenny : public CreatureScript
-{
-public:
- npc_jenny() : CreatureScript("npc_jenny") { }
-
- struct npc_jennyAI : public ScriptedAI
- {
- npc_jennyAI(Creature* creature) : ScriptedAI(creature)
- {
- setCrateNumber = false;
- }
-
- bool setCrateNumber;
-
- void Reset() override
- {
- if (!setCrateNumber)
- setCrateNumber = true;
-
- me->SetReactState(REACT_PASSIVE);
-
- if (!me->GetOwner())
- return;
-
- switch (me->GetOwner()->ToPlayer()->GetTeamId())
- {
- case TEAM_ALLIANCE:
- me->setFaction(FACTION_ESCORT_A_NEUTRAL_ACTIVE);
- break;
- default:
- case TEAM_HORDE:
- me->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE);
- break;
- }
- }
-
- void DamageTaken(Unit* /*pDone_by*/, uint32& /*uiDamage*/) override
- {
- DoCast(me, SPELL_DROP_CRATE, true);
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (setCrateNumber)
- {
- me->AddAura(SPELL_CRATES_CARRIED, me);
- setCrateNumber = false;
- }
-
- if (!setCrateNumber && !me->HasAura(SPELL_CRATES_CARRIED))
- me->DisappearAndDie();
-
- if (!UpdateVictim())
- return;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_jennyAI(creature);
- }
-};
-
-/*######
-## npc_fezzix_geartwist
-######*/
-
-class npc_fezzix_geartwist : public CreatureScript
-{
-public:
- npc_fezzix_geartwist() : CreatureScript("npc_fezzix_geartwist") { }
-
- struct npc_fezzix_geartwistAI : public ScriptedAI
- {
- npc_fezzix_geartwistAI(Creature* creature) : ScriptedAI(creature) { }
-
- void MoveInLineOfSight(Unit* who) override
-
- {
- ScriptedAI::MoveInLineOfSight(who);
-
- if (who->GetEntry() != NPC_JENNY || !who->HasAura(SPELL_CRATES_CARRIED))
- return;
-
- Unit* owner = who->GetOwner();
- if (!owner || !me->IsWithinDistInMap(who, 10.0f))
- return;
-
- if (Player* player = owner->ToPlayer())
- {
- owner->CastSpell(owner, SPELL_GIVE_JENNY_CREDIT, true); // Maybe is not working.
- player->CompleteQuest(QUEST_LOADER_UP);
- who->ToCreature()->DisappearAndDie();
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_fezzix_geartwistAI(creature);
- }
-};
-
-/*######
## npc_nesingwary_trapper
######*/
@@ -2112,65 +1992,6 @@ public:
};
/*######
-## Quest 11608: Bury Those Cockroaches!
-######*/
-
-enum BuryThoseCockroaches
-{
- // Quest
- QUEST_BURY_THOSE_COCKROACHES = 11608,
-
- // Spells
- SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION = 45502
-
-};
-
-class npc_seaforium_depth_charge : public CreatureScript
-{
-public:
- npc_seaforium_depth_charge() : CreatureScript("npc_seaforium_depth_charge") { }
-
- struct npc_seaforium_depth_chargeAI : public ScriptedAI
- {
- npc_seaforium_depth_chargeAI(Creature* creature) : ScriptedAI(creature) { }
-
- uint32 uiExplosionTimer;
-
- void Reset() override
- {
- uiExplosionTimer = urand(5000, 10000);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (uiExplosionTimer < diff)
- {
- DoCast(SPELL_SEAFORIUM_DEPTH_CHARGE_EXPLOSION);
- for (uint8 i = 0; i < 4; ++i)
- {
- if (Creature* cCredit = me->FindNearestCreature(25402 + i, 10.0f))//25402-25405 credit markers
- {
- if (Unit* uOwner = me->GetOwner())
- {
- Player* owner = uOwner->ToPlayer();
- if (owner && owner->GetQuestStatus(QUEST_BURY_THOSE_COCKROACHES) == QUEST_STATUS_INCOMPLETE)
- owner->KilledMonsterCredit(cCredit->GetEntry(), cCredit->GetGUID());
- }
- }
- }
- me->Kill(me);
- return;
- } else uiExplosionTimer -= diff;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_seaforium_depth_chargeAI(creature);
- }
-};
-
-/*######
## Help Those That Cannot Help Themselves, Quest 11876
######*/
@@ -2577,8 +2398,6 @@ void AddSC_borean_tundra()
new npc_corastrasza();
new npc_iruk();
new npc_nerubar_victim();
- new npc_jenny();
- new npc_fezzix_geartwist();
new npc_nesingwary_trapper();
new npc_lurgglbr();
new npc_nexus_drake_hatchling();
@@ -2593,7 +2412,6 @@ void AddSC_borean_tundra()
new npc_bonker_togglevolt();
new npc_trapped_mammoth_calf();
new npc_magmoth_crusher();
- new npc_seaforium_depth_charge();
new npc_valiance_keep_cannoneer();
new npc_warmage_coldarra();
new npc_hidden_cultist();
diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
index 8cb7630e60e..8bc0ba1722a 100644
--- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
+++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp
@@ -80,7 +80,7 @@ public:
switch (eventId)
{
case EVENT_VOID_BLAST:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
{
DoCast(target, SPELL_VOID_BLAST);
++VoidBlastCounter;
diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
index bd16fe9edd2..15c660b4ad7 100644
--- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
+++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp
@@ -114,7 +114,6 @@ class boss_broggok : public CreatureScript
break;
}
}
-
};
CreatureAI* GetAI(Creature* creature) const override
diff --git a/src/server/scripts/Outland/zone_shattrath_city.cpp b/src/server/scripts/Outland/zone_shattrath_city.cpp
index 9a62cde005c..c2e7df19ca1 100644
--- a/src/server/scripts/Outland/zone_shattrath_city.cpp
+++ b/src/server/scripts/Outland/zone_shattrath_city.cpp
@@ -30,7 +30,6 @@ npc_shattrathflaskvendors
npc_zephyr
npc_kservant
npc_ishanah
-npc_khadgar
EndContentData */
#include "ScriptMgr.h"
@@ -469,73 +468,6 @@ public:
}
};
-/*######
-# npc_khadgar
-######*/
-
-#define KHADGAR_GOSSIP_1 "I've heard your name spoken only in whispers, mage. Who are you?"
-#define KHADGAR_GOSSIP_2 "Go on, please."
-#define KHADGAR_GOSSIP_3 "I see." //6th too this
-#define KHADGAR_GOSSIP_4 "What did you do then?"
-#define KHADGAR_GOSSIP_5 "What happened next?"
-#define KHADGAR_GOSSIP_7 "There was something else I wanted to ask you."
-
-class npc_khadgar : public CreatureScript
-{
-public:
- npc_khadgar() : CreatureScript("npc_khadgar") { }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- switch (action)
- {
- case GOSSIP_ACTION_INFO_DEF+1:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
- player->SEND_GOSSIP_MENU(9876, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+2:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3);
- player->SEND_GOSSIP_MENU(9877, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+3:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4);
- player->SEND_GOSSIP_MENU(9878, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+4:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5);
- player->SEND_GOSSIP_MENU(9879, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+5:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6);
- player->SEND_GOSSIP_MENU(9880, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+6:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7);
- player->SEND_GOSSIP_MENU(9881, creature->GetGUID());
- break;
- case GOSSIP_ACTION_INFO_DEF+7:
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
- player->SEND_GOSSIP_MENU(9243, creature->GetGUID());
- break;
- }
- return true;
- }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- if (player->GetQuestStatus(10211) != QUEST_STATUS_INCOMPLETE)
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, KHADGAR_GOSSIP_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
-
- player->SEND_GOSSIP_MENU(9243, creature->GetGUID());
-
- return true;
- }
-};
-
void AddSC_shattrath_city()
{
new npc_raliq_the_drunk();
@@ -544,5 +476,4 @@ void AddSC_shattrath_city()
new npc_zephyr();
new npc_kservant();
new npc_ishanah();
- new npc_khadgar();
}
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index ea90c13f747..d04b25147c7 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -33,7 +33,6 @@ npc_guardian 100% guardianAI used to prevent players from accessin
npc_garments_of_quests 80% NPC's related to all Garments of-quests 5621, 5624, 5625, 5648, 565
npc_injured_patient 100% patients for triage-quests (6622 and 6624)
npc_doctor 100% Gustaf Vanhowzen and Gregory Victor, quest 6622 and 6624 (Triage)
-npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy
npc_sayge 100% Darkmoon event fortune teller, buff player based on answers given
npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap
npc_shadowfiend 100% restore 5% of owner's mana when shadowfiend die from damage
@@ -1170,105 +1169,6 @@ public:
};
/*######
-## npc_mount_vendor
-######*/
-
-class npc_mount_vendor : public CreatureScript
-{
-public:
- npc_mount_vendor() : CreatureScript("npc_mount_vendor") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (creature->IsQuestGiver())
- player->PrepareQuestMenu(creature->GetGUID());
-
- bool canBuy = false;
- uint32 vendor = creature->GetEntry();
- uint8 race = player->getRace();
-
- switch (vendor)
- {
- case 384: //Katie Hunter
- case 1460: //Unger Statforth
- case 2357: //Merideth Carlson
- case 4885: //Gregor MacVince
- if (player->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN)
- player->SEND_GOSSIP_MENU(5855, creature->GetGUID());
- else canBuy = true;
- break;
- case 1261: //Veron Amberstill
- if (player->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF)
- player->SEND_GOSSIP_MENU(5856, creature->GetGUID());
- else canBuy = true;
- break;
- case 3362: //Ogunaro Wolfrunner
- if (player->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC)
- player->SEND_GOSSIP_MENU(5841, creature->GetGUID());
- else canBuy = true;
- break;
- case 3685: //Harb Clawhoof
- if (player->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN)
- player->SEND_GOSSIP_MENU(5843, creature->GetGUID());
- else canBuy = true;
- break;
- case 4730: //Lelanai
- if (player->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF)
- player->SEND_GOSSIP_MENU(5844, creature->GetGUID());
- else canBuy = true;
- break;
- case 4731: //Zachariah Post
- if (player->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD_PLAYER)
- player->SEND_GOSSIP_MENU(5840, creature->GetGUID());
- else canBuy = true;
- break;
- case 7952: //Zjolnir
- if (player->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL)
- player->SEND_GOSSIP_MENU(5842, creature->GetGUID());
- else canBuy = true;
- break;
- case 7955: //Milli Featherwhistle
- if (player->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME)
- player->SEND_GOSSIP_MENU(5857, creature->GetGUID());
- else canBuy = true;
- break;
- case 16264: //Winaestra
- if (player->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF)
- player->SEND_GOSSIP_MENU(10305, creature->GetGUID());
- else canBuy = true;
- break;
- case 17584: //Torallius the Pack Handler
- if (player->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI)
- player->SEND_GOSSIP_MENU(10239, creature->GetGUID());
- else canBuy = true;
- break;
- case 48510: //Kall Worthaton
- if (player->GetReputationRank(1133) != REP_EXALTED && race != RACE_GOBLIN)
- player->SEND_GOSSIP_MENU(17494, creature->GetGUID());
- else canBuy = true;
- break;
- }
-
- if (canBuy)
- {
- if (creature->IsVendor())
- player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
- player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID());
- }
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
- {
- player->PlayerTalkClass->ClearMenus();
- if (action == GOSSIP_ACTION_TRADE)
- player->GetSession()->SendListInventory(creature->GetGUID());
-
- return true;
- }
-};
-
-/*######
## npc_sayge
######*/
@@ -2488,7 +2388,6 @@ void AddSC_npcs_special()
new npc_injured_patient();
new npc_garments_of_quests();
new npc_guardian();
- new npc_mount_vendor();
new npc_sayge();
new npc_steam_tonk();
new npc_tonk_mine();
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index 4e46ff0e3a1..abdf2a2cc3c 100644
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -57,14 +57,14 @@ m_connectionFlags(CONNECTION_ASYNC)
MySQLConnection::~MySQLConnection()
{
+ if (m_worker)
+ delete m_worker;
+
for (size_t i = 0; i < m_stmts.size(); ++i)
delete m_stmts[i];
if (m_Mysql)
mysql_close(m_Mysql);
-
- if (m_worker)
- delete m_worker;
}
void MySQLConnection::Close()
diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h
index 64665c2b198..c8f8e2dbd90 100644
--- a/src/server/shared/Networking/AsyncAcceptor.h
+++ b/src/server/shared/Networking/AsyncAcceptor.h
@@ -23,51 +23,68 @@
using boost::asio::ip::tcp;
-template <class T>
class AsyncAcceptor
{
public:
- AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port) :
- _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)),
- _socket(ioService)
- {
- AsyncAccept();
- };
+ typedef void(*ManagerAcceptHandler)(tcp::socket&& newSocket);
- AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port, bool tcpNoDelay) :
+ AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) :
_acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)),
_socket(ioService)
{
- _acceptor.set_option(boost::asio::ip::tcp::no_delay(tcpNoDelay));
+ }
- AsyncAccept();
- };
+ template <class T>
+ void AsyncAccept();
-private:
- void AsyncAccept()
+ void AsyncAcceptManaged(ManagerAcceptHandler mgrHandler)
{
- _acceptor.async_accept(_socket, [this](boost::system::error_code error)
+ _acceptor.async_accept(_socket, [this, mgrHandler](boost::system::error_code error)
{
if (!error)
{
try
{
- // this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class
- std::make_shared<T>(std::move(this->_socket))->Start();
+ _socket.non_blocking(true);
+
+ mgrHandler(std::move(_socket));
}
catch (boost::system::system_error const& err)
{
- TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ TC_LOG_INFO("network", "Failed to initialize client's socket %s", err.what());
}
}
- // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face
- this->AsyncAccept();
+ AsyncAcceptManaged(mgrHandler);
});
}
+private:
tcp::acceptor _acceptor;
tcp::socket _socket;
};
+template<class T>
+void AsyncAcceptor::AsyncAccept()
+{
+ _acceptor.async_accept(_socket, [this](boost::system::error_code error)
+ {
+ if (!error)
+ {
+ try
+ {
+ // this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class
+ std::make_shared<T>(std::move(this->_socket))->Start();
+ }
+ catch (boost::system::system_error const& err)
+ {
+ TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ }
+ }
+
+ // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face
+ this->AsyncAccept<T>();
+ });
+}
+
#endif /* __ASYNCACCEPT_H_ */
diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h
index c7f8ba31a71..2115bea3f47 100644
--- a/src/server/shared/Networking/MessageBuffer.h
+++ b/src/server/shared/Networking/MessageBuffer.h
@@ -26,42 +26,74 @@ class MessageBuffer
typedef std::vector<uint8>::size_type size_type;
public:
- MessageBuffer() : _wpos(0), _storage() { }
+ MessageBuffer() : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(4096);
+ }
- MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _storage(right._storage) { }
+ explicit MessageBuffer(std::size_t initialSize) : _wpos(0), _rpos(0), _storage()
+ {
+ _storage.resize(initialSize);
+ }
+
+ MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right._storage)
+ {
+ }
- MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _storage(right.Move()) { }
+ MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right.Move()) { }
void Reset()
{
- _storage.clear();
_wpos = 0;
+ _rpos = 0;
}
- bool IsMessageReady() const { return _wpos == _storage.size(); }
+ void Resize(size_type bytes)
+ {
+ _storage.resize(bytes);
+ }
- size_type GetSize() const { return _storage.size(); }
+ uint8* GetBasePointer() { return _storage.data(); }
- size_type GetReadyDataSize() const { return _wpos; }
+ uint8* GetReadPointer() { return &_storage[_rpos]; }
- size_type GetMissingSize() const { return _storage.size() - _wpos; }
+ uint8* GetWritePointer() { return &_storage[_wpos]; }
- uint8* Data() { return _storage.data(); }
+ void ReadCompleted(size_type bytes) { _rpos += bytes; }
- void Grow(size_type bytes)
- {
- _storage.resize(_storage.size() + bytes);
- }
+ void WriteCompleted(size_type bytes) { _wpos += bytes; }
- uint8* GetWritePointer() { return &_storage[_wpos]; }
+ size_type GetActiveSize() const { return _wpos - _rpos; }
- void WriteCompleted(size_type bytes) { _wpos += bytes; }
+ size_type GetRemainingSpace() const { return _storage.size() - _wpos; }
+
+ size_type GetBufferSize() const { return _storage.size(); }
+
+ // Discards inactive data
+ void Normalize()
+ {
+ if (_rpos)
+ {
+ if (_rpos != _wpos)
+ memmove(GetBasePointer(), GetReadPointer(), GetActiveSize());
+ _wpos -= _rpos;
+ _rpos = 0;
+ }
+ }
- void ResetWritePointer() { _wpos = 0; }
+ void Write(void* data, std::size_t size)
+ {
+ if (size)
+ {
+ memcpy(GetWritePointer(), data, size);
+ WriteCompleted(size);
+ }
+ }
std::vector<uint8>&& Move()
{
_wpos = 0;
+ _rpos = 0;
return std::move(_storage);
}
@@ -70,6 +102,7 @@ public:
if (this != &right)
{
_wpos = right._wpos;
+ _rpos = right._rpos;
_storage = right._storage;
}
@@ -81,6 +114,7 @@ public:
if (this != &right)
{
_wpos = right._wpos;
+ _rpos = right._rpos;
_storage = right.Move();
}
@@ -89,6 +123,7 @@ public:
private:
size_type _wpos;
+ size_type _rpos;
std::vector<uint8> _storage;
};
diff --git a/src/server/shared/Networking/NetworkThread.h b/src/server/shared/Networking/NetworkThread.h
new file mode 100644
index 00000000000..043aee56504
--- /dev/null
+++ b/src/server/shared/Networking/NetworkThread.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NetworkThread_h__
+#define NetworkThread_h__
+
+#include "Define.h"
+#include "Errors.h"
+#include "Log.h"
+#include "Timer.h"
+#include <atomic>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <thread>
+
+template<class SocketType>
+class NetworkThread
+{
+public:
+ NetworkThread() : _connections(0), _stopped(false), _thread(nullptr)
+ {
+ }
+
+ virtual ~NetworkThread()
+ {
+ Stop();
+ if (_thread)
+ {
+ Wait();
+ delete _thread;
+ }
+ }
+
+ void Stop()
+ {
+ _stopped = true;
+ }
+
+ bool Start()
+ {
+ if (_thread)
+ return false;
+
+ _thread = new std::thread(&NetworkThread::Run, this);
+ return true;
+ }
+
+ void Wait()
+ {
+ ASSERT(_thread);
+
+ _thread->join();
+ delete _thread;
+ _thread = nullptr;
+ }
+
+ int32 GetConnectionCount() const
+ {
+ return _connections;
+ }
+
+ virtual void AddSocket(std::shared_ptr<SocketType> sock)
+ {
+ std::lock_guard<std::mutex> lock(_newSocketsLock);
+
+ ++_connections;
+ _newSockets.insert(sock);
+ SocketAdded(sock);
+ }
+
+protected:
+ virtual void SocketAdded(std::shared_ptr<SocketType> /*sock*/) { }
+ virtual void SocketRemoved(std::shared_ptr<SocketType> /*sock*/) { }
+
+ void AddNewSockets()
+ {
+ std::lock_guard<std::mutex> lock(_newSocketsLock);
+
+ if (_newSockets.empty())
+ return;
+
+ for (typename SocketSet::const_iterator i = _newSockets.begin(); i != _newSockets.end(); ++i)
+ {
+ if (!(*i)->IsOpen())
+ {
+ SocketRemoved(*i);
+
+ --_connections;
+ }
+ else
+ _Sockets.insert(*i);
+ }
+
+ _newSockets.clear();
+ }
+
+ void Run()
+ {
+ TC_LOG_DEBUG("misc", "Network Thread Starting");
+
+ typename SocketSet::iterator i, t;
+
+ uint32 sleepTime = 10;
+ uint32 tickStart = 0, diff = 0;
+ while (!_stopped)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+
+ tickStart = getMSTime();
+
+ AddNewSockets();
+
+ for (i = _Sockets.begin(); i != _Sockets.end();)
+ {
+ if (!(*i)->Update())
+ {
+ if ((*i)->IsOpen())
+ (*i)->CloseSocket();
+
+ SocketRemoved(*i);
+
+ --_connections;
+ _Sockets.erase(i++);
+ }
+ else
+ ++i;
+ }
+
+ diff = GetMSTimeDiffToNow(tickStart);
+ sleepTime = diff > 10 ? 0 : 10 - diff;
+ }
+
+ TC_LOG_DEBUG("misc", "Network Thread exits");
+ }
+
+private:
+ typedef std::set<std::shared_ptr<SocketType> > SocketSet;
+
+ std::atomic<int32> _connections;
+ std::atomic<bool> _stopped;
+
+ std::thread* _thread;
+
+ SocketSet _Sockets;
+
+ std::mutex _newSocketsLock;
+ SocketSet _newSockets;
+};
+
+#endif // NetworkThread_h__
diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h
index 3bd30bd731b..17f48343485 100644
--- a/src/server/shared/Networking/Socket.h
+++ b/src/server/shared/Networking/Socket.h
@@ -35,32 +35,40 @@ using boost::asio::ip::tcp;
#define READ_BLOCK_SIZE 4096
-template<class T, class PacketType>
+template<class T>
class Socket : public std::enable_shared_from_this<T>
{
- typedef typename std::conditional<std::is_pointer<PacketType>::value, PacketType, PacketType const&>::type WritePacketType;
-
public:
- Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
- _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false), _closing(false)
+ explicit Socket(tcp::socket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
+ _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false)
{
- _readHeaderBuffer.Grow(headerSize);
+ _readBuffer.Resize(READ_BLOCK_SIZE);
}
virtual ~Socket()
{
boost::system::error_code error;
_socket.close(error);
-
- while (!_writeQueue.empty())
- {
- DeletePacket(_writeQueue.front());
- _writeQueue.pop();
- }
}
virtual void Start() = 0;
+ virtual bool Update()
+ {
+ if (!IsOpen())
+ return false;
+
+#ifndef BOOST_ASIO_HAS_IOCP
+ if (_isWritingAsync || (!_writeBuffer.GetActiveSize() && _writeQueue.empty()))
+ return true;
+
+ for (; WriteHandler(boost::system::error_code(), 0);)
+ ;
+#endif
+
+ return true;
+ }
+
boost::asio::ip::address GetRemoteIpAddress() const
{
return _remoteAddress;
@@ -71,31 +79,14 @@ public:
return _remotePort;
}
- void AsyncReadHeader()
+ void AsyncRead()
{
if (!IsOpen())
return;
- _readHeaderBuffer.ResetWritePointer();
- _readDataBuffer.Reset();
-
- AsyncReadMissingHeaderData();
- }
-
- void AsyncReadData(std::size_t size)
- {
- if (!IsOpen())
- return;
-
- if (!size)
- {
- // if this is a packet with 0 length body just invoke handler directly
- ReadDataHandler();
- return;
- }
-
- _readDataBuffer.Grow(size);
- AsyncReadMissingData();
+ _readBuffer.Normalize();
+ _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), READ_BLOCK_SIZE),
+ std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
void ReadData(std::size_t size)
@@ -105,13 +96,11 @@ public:
boost::system::error_code error;
- _readDataBuffer.Grow(size);
-
- std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readDataBuffer.GetWritePointer(), size), error);
+ std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readBuffer.GetWritePointer(), size), error);
- _readDataBuffer.WriteCompleted(bytesRead);
+ _readBuffer.WriteCompleted(bytesRead);
- if (error || !_readDataBuffer.IsMessageReady())
+ if (error || bytesRead != size)
{
TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(),
error.message().c_str());
@@ -120,15 +109,19 @@ public:
}
}
- void AsyncWrite(WritePacketType data)
+ void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard)
{
- boost::asio::async_write(_socket, boost::asio::buffer(data), std::bind(&Socket<T, PacketType>::WriteHandler, this->shared_from_this(),
- std::placeholders::_1, std::placeholders::_2));
+
+ _writeQueue.push(std::move(buffer));
+
+#ifdef BOOST_ASIO_HAS_IOCP
+ AsyncProcessQueue(guard);
+#endif
}
bool IsOpen() const { return !_closed && !_closing; }
- virtual void CloseSocket()
+ void CloseSocket()
{
if (_closed.exchange(true))
return;
@@ -143,39 +136,37 @@ public:
/// Marks the socket for closing after write buffer becomes empty
void DelayedCloseSocket() { _closing = true; }
- virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); }
- virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); }
-
- uint8* GetHeaderBuffer() { return _readHeaderBuffer.Data(); }
- uint8* GetDataBuffer() { return _readDataBuffer.Data(); }
-
- size_t GetHeaderSize() const { return _readHeaderBuffer.GetReadyDataSize(); }
- size_t GetDataSize() const { return _readDataBuffer.GetReadyDataSize(); }
-
- MessageBuffer&& MoveHeader() { return std::move(_readHeaderBuffer); }
- MessageBuffer&& MoveData() { return std::move(_readDataBuffer); }
+ MessageBuffer& GetReadBuffer() { return _readBuffer; }
protected:
- virtual void ReadHeaderHandler() = 0;
- virtual void ReadDataHandler() = 0;
-
- std::mutex _writeLock;
- std::queue<PacketType> _writeQueue;
+ virtual void ReadHandler() = 0;
-private:
- void AsyncReadMissingHeaderData()
+ bool AsyncProcessQueue(std::unique_lock<std::mutex>&)
{
- _socket.async_read_some(boost::asio::buffer(_readHeaderBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readHeaderBuffer.GetMissingSize())),
- std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+ if (_isWritingAsync)
+ return true;
+
+ _isWritingAsync = true;
+
+#ifdef BOOST_ASIO_HAS_IOCP
+ MessageBuffer& buffer = _writeQueue.front();
+ _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
+ this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+#else
+ _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandler, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+#endif
+
+ return true;
}
- void AsyncReadMissingData()
- {
- _socket.async_read_some(boost::asio::buffer(_readDataBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readDataBuffer.GetMissingSize())),
- std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
- }
+ std::mutex _writeLock;
+ std::queue<MessageBuffer> _writeQueue;
+#ifndef BOOST_ASIO_HAS_IOCP
+ MessageBuffer _writeBuffer;
+#endif
- void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferredBytes)
+private:
+ void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes)
{
if (error)
{
@@ -183,70 +174,130 @@ private:
return;
}
- _readHeaderBuffer.WriteCompleted(transferredBytes);
- if (!IsHeaderReady())
+ _readBuffer.WriteCompleted(transferredBytes);
+ ReadHandler();
+ }
+
+#ifdef BOOST_ASIO_HAS_IOCP
+
+ void WriteHandler(boost::system::error_code error, std::size_t transferedBytes)
+ {
+ if (!error)
{
- // incomplete, read more
- AsyncReadMissingHeaderData();
- return;
- }
+ std::unique_lock<std::mutex> deleteGuard(_writeLock);
+
+ _isWritingAsync = false;
+ _writeQueue.front().ReadCompleted(transferedBytes);
+ if (!_writeQueue.front().GetActiveSize())
+ _writeQueue.pop();
- ReadHeaderHandler();
+ if (!_writeQueue.empty())
+ AsyncProcessQueue(deleteGuard);
+ else if (_closing)
+ CloseSocket();
+ }
+ else
+ CloseSocket();
}
- void ReadDataHandlerInternal(boost::system::error_code error, size_t transferredBytes)
+#else
+
+ bool WriteHandler(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/)
{
+ std::unique_lock<std::mutex> guard(_writeLock, std::try_to_lock);
+ if (!guard)
+ return false;
+
+ if (!IsOpen())
+ return false;
+
+ std::size_t bytesToSend = _writeBuffer.GetActiveSize();
+
+ if (bytesToSend == 0)
+ return HandleQueue(guard);
+
+ boost::system::error_code error;
+ std::size_t bytesWritten = _socket.write_some(boost::asio::buffer(_writeBuffer.GetReadPointer(), bytesToSend), error);
+
if (error)
{
- CloseSocket();
- return;
- }
+ if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
+ return AsyncProcessQueue(guard);
- _readDataBuffer.WriteCompleted(transferredBytes);
- if (!IsDataReady())
+ return false;
+ }
+ else if (bytesWritten == 0)
+ return false;
+ else if (bytesWritten < bytesToSend) //now n > 0
{
- // incomplete, read more
- AsyncReadMissingData();
- return;
+ _writeBuffer.ReadCompleted(bytesWritten);
+ _writeBuffer.Normalize();
+ return AsyncProcessQueue(guard);
}
- ReadDataHandler();
+ // now bytesWritten == bytesToSend
+ _writeBuffer.Reset();
+
+ return HandleQueue(guard);
}
- void WriteHandler(boost::system::error_code error, size_t /*transferedBytes*/)
+ bool HandleQueue(std::unique_lock<std::mutex>& guard)
{
- if (!error)
+ if (_writeQueue.empty())
+ {
+ _isWritingAsync = false;
+ return false;
+ }
+
+ MessageBuffer& queuedMessage = _writeQueue.front();
+
+ std::size_t bytesToSend = queuedMessage.GetActiveSize();
+
+ boost::system::error_code error;
+ std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);
+
+ if (error)
{
- std::lock_guard<std::mutex> deleteGuard(_writeLock);
+ if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
+ return AsyncProcessQueue(guard);
- DeletePacket(_writeQueue.front());
_writeQueue.pop();
+ return false;
+ }
+ else if (bytesSent == 0)
+ {
+ _writeQueue.pop();
+ return false;
+ }
+ else if (bytesSent < bytesToSend) // now n > 0
+ {
+ queuedMessage.ReadCompleted(bytesSent);
+ return AsyncProcessQueue(guard);
+ }
- if (!_writeQueue.empty())
- AsyncWrite(_writeQueue.front());
- else if (_closing)
- CloseSocket();
+ _writeQueue.pop();
+ if (_writeQueue.empty())
+ {
+ _isWritingAsync = false;
+ return false;
}
- else
- CloseSocket();
- }
- template<typename Q = PacketType>
- typename std::enable_if<std::is_pointer<Q>::value>::type DeletePacket(PacketType& packet) { delete packet; }
+ return true;
+ }
- template<typename Q = PacketType>
- typename std::enable_if<!std::is_pointer<Q>::value>::type DeletePacket(PacketType const& /*packet*/) { }
+#endif
tcp::socket _socket;
boost::asio::ip::address _remoteAddress;
uint16 _remotePort;
- MessageBuffer _readHeaderBuffer;
- MessageBuffer _readDataBuffer;
+ MessageBuffer _readBuffer;
std::atomic<bool> _closed;
std::atomic<bool> _closing;
+
+ bool _isWritingAsync;
};
#endif // __SOCKET_H__
diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h
new file mode 100644
index 00000000000..47bd7794a4c
--- /dev/null
+++ b/src/server/shared/Networking/SocketMgr.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SocketMgr_h__
+#define SocketMgr_h__
+
+#include "AsyncAcceptor.h"
+#include "Config.h"
+#include "Errors.h"
+#include "NetworkThread.h"
+#include <boost/asio/ip/tcp.hpp>
+#include <memory>
+
+using boost::asio::ip::tcp;
+
+template<class SocketType>
+class SocketMgr
+{
+public:
+ virtual ~SocketMgr()
+ {
+ delete[] _threads;
+ }
+
+ virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port)
+ {
+ _threadCount = sConfigMgr->GetIntDefault("Network.Threads", 1);
+
+ if (_threadCount <= 0)
+ {
+ TC_LOG_ERROR("misc", "Network.Threads is wrong in your config file");
+ return false;
+ }
+
+ _acceptor = new AsyncAcceptor(service, bindIp, port);
+ _threads = CreateThreads();
+
+ ASSERT(_threads);
+
+ for (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Start();
+
+ return true;
+ }
+
+ virtual void StopNetwork()
+ {
+ if (_threadCount != 0)
+ for (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Stop();
+
+ Wait();
+ }
+
+ void Wait()
+ {
+ if (_threadCount != 0)
+ for (int32 i = 0; i < _threadCount; ++i)
+ _threads[i].Wait();
+ }
+
+ virtual void OnSocketOpen(tcp::socket&& sock)
+ {
+ size_t min = 0;
+
+ for (int32 i = 1; i < _threadCount; ++i)
+ if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount())
+ min = i;
+
+ try
+ {
+ std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock));
+ newSocket->Start();
+
+ _threads[min].AddSocket(newSocket);
+ }
+ catch (boost::system::system_error const& err)
+ {
+ TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
+ }
+ }
+
+ int32 GetNetworkThreadCount() const { return _threadCount; }
+
+protected:
+ SocketMgr() : _threads(nullptr), _threadCount(1)
+ {
+ }
+
+ virtual NetworkThread<SocketType>* CreateThreads() const = 0;
+
+ AsyncAcceptor* _acceptor;
+ NetworkThread<SocketType>* _threads;
+ int32 _threadCount;
+};
+
+#endif // SocketMgr_h__
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index e149902af02..191e44b3e93 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -46,6 +46,7 @@
#include "CliRunnable.h"
#include "SystemConfig.h"
#include "WorldSocket.h"
+#include "WorldSocketMgr.h"
using namespace boost::program_options;
@@ -82,7 +83,7 @@ uint32 realmID; ///< Id of the realm
void SignalHandler(const boost::system::error_code& error, int signalNumber);
void FreezeDetectorHandler(const boost::system::error_code& error);
-AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService);
+AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService);
bool StartDB();
void StopDB();
void WorldUpdateLoop();
@@ -203,7 +204,7 @@ extern int main(int argc, char** argv)
}
// Start the Remote Access port (acceptor) if enabled
- AsyncAcceptor<RASession>* raAcceptor = nullptr;
+ AsyncAcceptor* raAcceptor = nullptr;
if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
raAcceptor = StartRaSocketAcceptor(_ioService);
@@ -217,11 +218,8 @@ extern int main(int argc, char** argv)
// Launch the worldserver listener socket
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
- bool tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true);
- AsyncAcceptor<WorldSocket> worldAcceptor(_ioService, worldListener, worldPort, tcpNoDelay);
-
- sScriptMgr->OnNetworkStart();
+ sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort);
// Set server online (allow connecting now)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID);
@@ -252,6 +250,8 @@ extern int main(int argc, char** argv)
// unload battleground templates before different singletons destroyed
sBattlegroundMgr->DeleteAllBattlegrounds();
+ sWorldSocketMgr.StopNetwork();
+
sInstanceSaveMgr->Unload();
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
@@ -379,12 +379,14 @@ void FreezeDetectorHandler(const boost::system::error_code& error)
}
}
-AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService)
+AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService)
{
uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
- return new AsyncAcceptor<RASession>(ioService, raListener, raPort);
+ AsyncAcceptor* acceptor = new AsyncAcceptor(ioService, raListener, raPort);
+ acceptor->AsyncAccept<RASession>();
+ return acceptor;
}
/// Initialize connection to the databases