aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent_Michael <Vincent_Michael@gmx.de>2013-02-18 18:51:52 +0100
committerVincent_Michael <Vincent_Michael@gmx.de>2013-02-18 18:51:52 +0100
commit71eaceae5de6cc1c517bec78d0ef52e149a59b6e (patch)
treea89711c8f03305f36b6042efa8eb5c5b104c2fad
parent2277f6db44a4dabf98611189d8d75df3a0008a66 (diff)
parent1c745dfe16787f9b51310c07b5b3c6801e9592e5 (diff)
Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts: src/server/game/Entities/Vehicle/Vehicle.cpp src/server/game/Globals/ObjectMgr.cpp src/server/game/Spells/SpellMgr.cpp src/server/game/Weather/Weather.h src/server/shared/Database/Implementation/WorldDatabase.cpp src/tools/CMakeLists.txt
-rw-r--r--sql/old/3.3.5a/09521_characters_character_achievement.sql (renamed from sql/old/3.3.5a/09521_character_achievement.sql)0
-rw-r--r--sql/old/3.3.5a/2011_04_14_00_characters_misc.sql (renamed from sql/old/3.3.5a/2011_04_14_00_characters.sql)0
-rw-r--r--sql/old/3.3.5a/2011_04_19_00_characters_misc.sql (renamed from sql/old/3.3.5a/2011_04_19_00_characters.sql)0
-rw-r--r--sql/old/3.3.5a/2012_04_20_05_world_gameobject_template.sql (renamed from sql/old/3.3.5a/2012_04_20_05_gameobject_template.sql)0
-rw-r--r--sql/old/3.3.5a/2012_07_01_01_world_achievement_criteria_data.sql (renamed from sql/old/3.3.5a/2012_07_01_01_achievement_criteria_data.sql)0
-rw-r--r--sql/old/3.3.5a/2012_10_09_00_characters_glyphs.sql (renamed from sql/old/3.3.5a/2012_10_09_00_character_glyphs.sql)0
-rw-r--r--sql/old/3.3.5a/2012_10_17_00_characters_gm_tickets.sql (renamed from sql/old/3.3.5a/2012_10_17_00_character_gm_tickets.sql)0
-rw-r--r--sql/old/3.3.5a/2012_11_02_00_characters_misc.sql (renamed from sql/old/3.3.5a/2012_11_02_00_character_misc.sql)0
-rw-r--r--sql/old/3.3.5a/2012_11_18_00_characters_calendar.sql (renamed from sql/old/3.3.5a/2012_11_18_00_character_calendar.sql)0
-rw-r--r--sql/old/3.3.5a/2012_12_03_00_characters_character_queststatus_monthly.sql (renamed from sql/old/3.3.5a/2012_12_03_00_character_character_queststatus_monthly.sql)0
-rw-r--r--sql/old/3.3.5a/2012_12_13_00_world_misc.sql (renamed from sql/old/3.3.5a/2012_12_13_00_world.sql)0
-rw-r--r--sql/old/3.3.5a/2012_12_18_00_characters_worldstates.sql (renamed from sql/old/3.3.5a/2012_12_18_00_character_worldstates.sql)0
-rw-r--r--sql/old/3.3.5a/2013_01_01_00_world_item_template_restore.sql (renamed from sql/old/3.3.5a/2013_01_01_00_item_template_restore.sql)0
-rw-r--r--sql/old/3.3.5a/2013_01_02_05_world_eye_of_eternity.sql (renamed from sql/old/3.3.5a/2013_01_02_05_eye_of_eternity.sql)0
-rw-r--r--sql/updates/world/2013_02_15_00_world_waypoint_data.sql2
-rw-r--r--sql/updates/world/2013_02_16_00_world_creature_template.sql1
-rw-r--r--sql/updates/world/2013_02_16_01_world_spell_target_position.sql11
-rw-r--r--sql/updates/world/2013_02_16_02_world_creature_text.sql8
-rw-r--r--sql/updates/world/2013_02_16_03_world_sai.sql14
-rw-r--r--sql/updates/world/2013_02_16_04_world_creature_loot_template.sql6
-rw-r--r--sql/updates/world/2013_02_16_05_world_quest_template.sql17
-rw-r--r--sql/updates/world/2013_02_17_00_world_spell_script_names.sql14
-rw-r--r--sql/updates/world/2013_02_18_00_world_misc_equip.sql73
-rw-r--r--sql/updates/world/2013_02_18_01_world_trinity_string.sql3
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp54
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp3
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h12
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp20
-rw-r--r--src/server/game/Accounts/AccountMgr.h4
-rw-r--r--src/server/game/Accounts/RBAC.cpp5
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp26
-rw-r--r--src/server/game/Entities/Creature/Creature.h17
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.h7
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp95
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--[-rwxr-xr-x]src/server/game/Entities/Vehicle/Vehicle.cpp547
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h37
-rw-r--r--src/server/game/Events/GameEventMgr.cpp34
-rw-r--r--src/server/game/Events/GameEventMgr.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp82
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp3
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp5
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp162
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp13
-rw-r--r--src/server/game/Weather/Weather.cpp3
-rw-r--r--src/server/game/Weather/Weather.h2
-rw-r--r--src/server/game/World/World.cpp8
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp1
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp7
-rw-r--r--src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp90
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp2
-rw-r--r--src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_desolace.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp53
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp92
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp4
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp8
-rw-r--r--src/server/scripts/Spells/spell_item.cpp61
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.cpp2
-rw-r--r--src/server/worldserver/worldserver.conf.dist10
-rw-r--r--src/tools/CMakeLists.txt4
74 files changed, 1102 insertions, 565 deletions
diff --git a/sql/old/3.3.5a/09521_character_achievement.sql b/sql/old/3.3.5a/09521_characters_character_achievement.sql
index e8262aed4ad..e8262aed4ad 100644
--- a/sql/old/3.3.5a/09521_character_achievement.sql
+++ b/sql/old/3.3.5a/09521_characters_character_achievement.sql
diff --git a/sql/old/3.3.5a/2011_04_14_00_characters.sql b/sql/old/3.3.5a/2011_04_14_00_characters_misc.sql
index ab9bd93419d..ab9bd93419d 100644
--- a/sql/old/3.3.5a/2011_04_14_00_characters.sql
+++ b/sql/old/3.3.5a/2011_04_14_00_characters_misc.sql
diff --git a/sql/old/3.3.5a/2011_04_19_00_characters.sql b/sql/old/3.3.5a/2011_04_19_00_characters_misc.sql
index 96536d67a03..96536d67a03 100644
--- a/sql/old/3.3.5a/2011_04_19_00_characters.sql
+++ b/sql/old/3.3.5a/2011_04_19_00_characters_misc.sql
diff --git a/sql/old/3.3.5a/2012_04_20_05_gameobject_template.sql b/sql/old/3.3.5a/2012_04_20_05_world_gameobject_template.sql
index 24400b16a5c..24400b16a5c 100644
--- a/sql/old/3.3.5a/2012_04_20_05_gameobject_template.sql
+++ b/sql/old/3.3.5a/2012_04_20_05_world_gameobject_template.sql
diff --git a/sql/old/3.3.5a/2012_07_01_01_achievement_criteria_data.sql b/sql/old/3.3.5a/2012_07_01_01_world_achievement_criteria_data.sql
index e1c0529fffe..e1c0529fffe 100644
--- a/sql/old/3.3.5a/2012_07_01_01_achievement_criteria_data.sql
+++ b/sql/old/3.3.5a/2012_07_01_01_world_achievement_criteria_data.sql
diff --git a/sql/old/3.3.5a/2012_10_09_00_character_glyphs.sql b/sql/old/3.3.5a/2012_10_09_00_characters_glyphs.sql
index b90fa7d7682..b90fa7d7682 100644
--- a/sql/old/3.3.5a/2012_10_09_00_character_glyphs.sql
+++ b/sql/old/3.3.5a/2012_10_09_00_characters_glyphs.sql
diff --git a/sql/old/3.3.5a/2012_10_17_00_character_gm_tickets.sql b/sql/old/3.3.5a/2012_10_17_00_characters_gm_tickets.sql
index affb23f836c..affb23f836c 100644
--- a/sql/old/3.3.5a/2012_10_17_00_character_gm_tickets.sql
+++ b/sql/old/3.3.5a/2012_10_17_00_characters_gm_tickets.sql
diff --git a/sql/old/3.3.5a/2012_11_02_00_character_misc.sql b/sql/old/3.3.5a/2012_11_02_00_characters_misc.sql
index 9cbbd423bb8..9cbbd423bb8 100644
--- a/sql/old/3.3.5a/2012_11_02_00_character_misc.sql
+++ b/sql/old/3.3.5a/2012_11_02_00_characters_misc.sql
diff --git a/sql/old/3.3.5a/2012_11_18_00_character_calendar.sql b/sql/old/3.3.5a/2012_11_18_00_characters_calendar.sql
index a3e7c352788..a3e7c352788 100644
--- a/sql/old/3.3.5a/2012_11_18_00_character_calendar.sql
+++ b/sql/old/3.3.5a/2012_11_18_00_characters_calendar.sql
diff --git a/sql/old/3.3.5a/2012_12_03_00_character_character_queststatus_monthly.sql b/sql/old/3.3.5a/2012_12_03_00_characters_character_queststatus_monthly.sql
index 256bb1f7ad6..256bb1f7ad6 100644
--- a/sql/old/3.3.5a/2012_12_03_00_character_character_queststatus_monthly.sql
+++ b/sql/old/3.3.5a/2012_12_03_00_characters_character_queststatus_monthly.sql
diff --git a/sql/old/3.3.5a/2012_12_13_00_world.sql b/sql/old/3.3.5a/2012_12_13_00_world_misc.sql
index ab27796f933..ab27796f933 100644
--- a/sql/old/3.3.5a/2012_12_13_00_world.sql
+++ b/sql/old/3.3.5a/2012_12_13_00_world_misc.sql
diff --git a/sql/old/3.3.5a/2012_12_18_00_character_worldstates.sql b/sql/old/3.3.5a/2012_12_18_00_characters_worldstates.sql
index c6fc15e60b7..c6fc15e60b7 100644
--- a/sql/old/3.3.5a/2012_12_18_00_character_worldstates.sql
+++ b/sql/old/3.3.5a/2012_12_18_00_characters_worldstates.sql
diff --git a/sql/old/3.3.5a/2013_01_01_00_item_template_restore.sql b/sql/old/3.3.5a/2013_01_01_00_world_item_template_restore.sql
index dc18ff71fe8..dc18ff71fe8 100644
--- a/sql/old/3.3.5a/2013_01_01_00_item_template_restore.sql
+++ b/sql/old/3.3.5a/2013_01_01_00_world_item_template_restore.sql
diff --git a/sql/old/3.3.5a/2013_01_02_05_eye_of_eternity.sql b/sql/old/3.3.5a/2013_01_02_05_world_eye_of_eternity.sql
index 89cc8f08cce..89cc8f08cce 100644
--- a/sql/old/3.3.5a/2013_01_02_05_eye_of_eternity.sql
+++ b/sql/old/3.3.5a/2013_01_02_05_world_eye_of_eternity.sql
diff --git a/sql/updates/world/2013_02_15_00_world_waypoint_data.sql b/sql/updates/world/2013_02_15_00_world_waypoint_data.sql
index 555cbd506e8..8af0531b2f3 100644
--- a/sql/updates/world/2013_02_15_00_world_waypoint_data.sql
+++ b/sql/updates/world/2013_02_15_00_world_waypoint_data.sql
@@ -1,4 +1,4 @@
-SET @NPC_DRAKE := 29709;
+SET @NPC_DRAKE := 29709;
DELETE FROM `waypoint_data` WHERE `id`=@NPC_DRAKE;
INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES
diff --git a/sql/updates/world/2013_02_16_00_world_creature_template.sql b/sql/updates/world/2013_02_16_00_world_creature_template.sql
new file mode 100644
index 00000000000..d8efe46b573
--- /dev/null
+++ b/sql/updates/world/2013_02_16_00_world_creature_template.sql
@@ -0,0 +1 @@
+UPDATE `creature_template` SET `Armor_mod`=0 WHERE `entry`=29747;
diff --git a/sql/updates/world/2013_02_16_01_world_spell_target_position.sql b/sql/updates/world/2013_02_16_01_world_spell_target_position.sql
new file mode 100644
index 00000000000..c262ecf450f
--- /dev/null
+++ b/sql/updates/world/2013_02_16_01_world_spell_target_position.sql
@@ -0,0 +1,11 @@
+DELETE FROM `spell_target_position` WHERE `id` IN (64014,64024,64025,64028,64029,64030,64031,64032,65042);
+INSERT INTO `spell_target_position` (`id`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES
+(64014, 603, -705.9705, -92.55729, 430.8192, 0),
+(64024, 603, 2086.224, -24.05382, 422.2889, 0),
+(64025, 603, 2518.131, 2569.342, 412.6822, 0),
+(64028, 603, 553.243, -12.30903, 410.5428, 0),
+(64029, 603, 1859.563, -24.83773, 449.1945, 6.230825),
+(64030, 603, 1497.989, -24.16162, 421.6254, 0.03490658),
+(64031, 603, 926.2917, -11.44444, 418.9779, 0.01745329),
+(64032, 603, 131.1389, -35.36806, 410.187, 0),
+(65042, 603, 1855.073, -11.48785, 334.559, 5.532694);
diff --git a/sql/updates/world/2013_02_16_02_world_creature_text.sql b/sql/updates/world/2013_02_16_02_world_creature_text.sql
new file mode 100644
index 00000000000..d7250b0b49c
--- /dev/null
+++ b/sql/updates/world/2013_02_16_02_world_creature_text.sql
@@ -0,0 +1,8 @@
+-- Lurgglbr
+DELETE FROM `creature_text` WHERE `entry`=25208;
+INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES
+(25208,0,0, 'You can''t hold me against my will! You''ve all been brainwashed!', 12,0,100,0,0,0, 'Lurgglbr'),
+(25208,1,0, 'Together we will fight our way out of here. Are you ready?', 12,0,100,0,0,0, 'Lurgglbr'),
+(25208,2,0, 'This is far enough. I can make it on my own from here.', 12,0,100,0,0,0, 'Lurgglbr'),
+(25208,3,0, 'Thank you for rescuing me, $r. Please tell the king that I am back.', 12,0,100,0,0,0, 'Lurgglbr');
+
diff --git a/sql/updates/world/2013_02_16_03_world_sai.sql b/sql/updates/world/2013_02_16_03_world_sai.sql
new file mode 100644
index 00000000000..fb89bf4ced0
--- /dev/null
+++ b/sql/updates/world/2013_02_16_03_world_sai.sql
@@ -0,0 +1,14 @@
+-- quest fix cuergo's gold (q2882)
+SET @ENTRY :=7898;
+UPDATE `creature_template` SET `AIName`= 'SmartAI', `ScriptName`='' WHERE `entry`=@ENTRY;
+DELETE FROM `creature_ai_scripts` WHERE `creature_id`=@ENTRY;
+DELETE FROM `smart_scripts` WHERE `source_type`=0 AND`entryorguid`=@ENTRY;
+DELETE FROM `smart_scripts` WHERE `source_type`=9 AND`entryorguid`=@ENTRY*100;
+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
+(@ENTRY,0,0,0,63,0,100,0,0,0,0,0,80,@ENTRY*100,0,0,0,0,0,1,0,0,0,0,0,0,0, 'Trigger - on respawn - run script'),
+(@ENTRY*100,9,0,0,0,0,100,0,0,0,300000,300000,11,11463,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - spawn pirate1'),
+(@ENTRY*100,9,1,0,0,0,100,0,0,0,300000,300000,11,11463,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - spawn pirate2'),
+(@ENTRY*100,9,2,0,0,0,100,0,0,0,300000,300000,11,11485,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - spawn buccaneer1'),
+(@ENTRY*100,9,3,0,0,0,100,0,0,0,300000,300000,11,11485,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - spawn buccaneer2'),
+(@ENTRY*100,9,4,0,0,0,100,0,0,0,300000,300000,11,11487,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - spawn swashbuckler'),
+(@ENTRY*100,9,5,0,0,0,100,0,0,0,0,0,41,0,0,0,0,0,0,1,0,0,0,0,0,0,0,'Timed Actionscript - despawn trigger');
diff --git a/sql/updates/world/2013_02_16_04_world_creature_loot_template.sql b/sql/updates/world/2013_02_16_04_world_creature_loot_template.sql
new file mode 100644
index 00000000000..6819b7aeb45
--- /dev/null
+++ b/sql/updates/world/2013_02_16_04_world_creature_loot_template.sql
@@ -0,0 +1,6 @@
+-- Remove Zulian Mudskunk from Zulian Crocolisk's loot template
+DELETE FROM `creature_loot_template` WHERE `entry`=15043 and `item`=19975;
+-- Add Vicious Oil (Item) into loot template of Vicious Oil (NPC)
+DELETE FROM `creature_loot_template` WHERE `entry`=30325 and `item`=42640;
+INSERT INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `lootmode`, `groupid`, `mincountOrRef`, `maxcount`) values
+(30325,42640,-100,1,0,1,1);
diff --git a/sql/updates/world/2013_02_16_05_world_quest_template.sql b/sql/updates/world/2013_02_16_05_world_quest_template.sql
new file mode 100644
index 00000000000..81a8e38f25d
--- /dev/null
+++ b/sql/updates/world/2013_02_16_05_world_quest_template.sql
@@ -0,0 +1,17 @@
+-- Previous quest should be The Defense of Warsong Hold not To Conquest Hold, But Be Careful!
+UPDATE `quest_template` SET `PrevQuestId`=11596 WHERE `Id`=12486;
+-- Change grouping so Alliance and Horde quests are no longer in 1 group
+UPDATE `quest_template` SET `ExclusiveGroup`=-12222 WHERE `Id` IN(12222,12223);
+-- Hellscreams Champion requires some conditions to start the quest
+UPDATE `quest_template` SET `ExclusiveGroup`=0,`NextQuestId`=0 WHERE `Id` IN(11652,11705,11722);
+UPDATE `quest_template` SET `NextQuestId`=11709 WHERE `Id`=11705;
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN (19,20) AND `SourceEntry`=11916;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(20,0,11916,0,0,8,0,11652,0,0,0,0, '', 'Player must have completed The Plains of Nasam before been able to accept Hellscream''s Champion'),
+(19,0,11916,0,0,8,0,11652,0,0,0,0, '', 'Player must have completed The Plains of Nasam before been able to accept Hellscream''s Champion'),
+(20,0,11916,0,0,8,0,11705,0,0,0,0, '', 'Player must have completed The Foolish Endeavors before been able to accept Hellscream''s Champion'),
+(19,0,11916,0,0,8,0,11705,0,0,0,0, '', 'Player must have completed The Foolish Endeavors before been able to accept Hellscream''s Champion'),
+(20,0,11916,0,0,8,0,11722,0,0,0,0, '', 'Player must have completed The Trophies of Gammoth before been able to accept Hellscream''s Champion'),
+(19,0,11916,0,0,8,0,11722,0,0,0,0, '', 'Player must have completed The Trophies of Gammoth before been able to accept Hellscream''s Champion');
+-- Fix SAI issue for Hugh Glass (wrong npcflag was set)
+UPDATE `smart_scripts` SET `action_param1`=643 WHERE `entryorguid`=2648400 AND `source_type`=9 AND `id`=6;
diff --git a/sql/updates/world/2013_02_17_00_world_spell_script_names.sql b/sql/updates/world/2013_02_17_00_world_spell_script_names.sql
new file mode 100644
index 00000000000..e47b22b1c6b
--- /dev/null
+++ b/sql/updates/world/2013_02_17_00_world_spell_script_names.sql
@@ -0,0 +1,14 @@
+DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_sindragosa_frost_breath';
+DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_item_unsated_craving';
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(69649,'spell_sindragosa_frost_breath'),
+(71056,'spell_sindragosa_frost_breath'),
+(71057,'spell_sindragosa_frost_breath'),
+(71058,'spell_sindragosa_frost_breath'),
+(73061,'spell_sindragosa_frost_breath'),
+(73062,'spell_sindragosa_frost_breath'),
+(73063,'spell_sindragosa_frost_breath'),
+(73064,'spell_sindragosa_frost_breath'),
+(71168,'spell_item_unsated_craving');
+
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=71952;
diff --git a/sql/updates/world/2013_02_18_00_world_misc_equip.sql b/sql/updates/world/2013_02_18_00_world_misc_equip.sql
new file mode 100644
index 00000000000..a5964cd883b
--- /dev/null
+++ b/sql/updates/world/2013_02_18_00_world_misc_equip.sql
@@ -0,0 +1,73 @@
+-- creature_template.equipment_id deleted
+-- creature_equip_template.entry == creature_template.entry
+-- id field added to creature_equip_template -> PK(entry, id)
+-- id field in creature_equip_template starts at 1
+-- creature.equipment_id references id of creature_equip_template
+-- creature.equipment_id = 0 means no equipment at all (default 1)
+-- creature.equipment_id = -1 means pick a random equipment from creature_equip_template
+
+-- Diff_entries should use the same template of the normal entry
+UPDATE `creature_template` SET `equipment_id` = 0 WHERE `name` LIKE '%(1)' OR `name` LIKE '%(2)' OR `name` LIKE '%(3)' OR `name` LIKE '%(4)';
+
+-- Delete unused templates
+DROP TABLE IF EXISTS `temp_c_e`;
+CREATE TABLE IF NOT EXISTS `temp_c_e` (`entry` mediumint(8));
+ALTER TABLE `temp_c_e` ADD INDEX `ind` (`entry`);
+INSERT INTO `temp_c_e` SELECT `equipment_id` FROM `creature_template` WHERE `equipment_id` != 0 UNION
+ SELECT `equipment_id` FROM `creature` WHERE `equipment_id` != 0 UNION
+ SELECT `equipment_id` FROM `game_event_model_equip` WHERE `equipment_id` != 0;
+DELETE FROM `creature_equip_template` WHERE `entry` NOT IN (SELECT `entry` FROM `temp_c_e`);
+DROP TABLE `temp_c_e`;
+
+-- Create temporary table to hold the values of creature_equip_template with converted entry
+DROP TABLE IF EXISTS `creature_equip_template2`;
+CREATE TABLE IF NOT EXISTS `creature_equip_template2` (
+ `entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `id` tinyint(3) unsigned NOT NULL DEFAULT '1',
+ `itemEntry1` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `itemEntry2` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `itemEntry3` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`entry`, `id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+INSERT INTO `creature_equip_template2` (`entry`, `id`, `itemEntry1`, `itemEntry2`, `itemEntry3`)
+ SELECT `creature_template`.`entry`, 1, `itemEntry1`, `itemEntry2`, `itemEntry3`
+ FROM `creature_template`
+ JOIN `creature_equip_template` ON `creature_equip_template`.`entry` = `equipment_id`
+ WHERE `equipment_id` != 0;
+
+INSERT IGNORE INTO `creature_equip_template2` (`entry`, `id`, `itemEntry1`, `itemEntry2`, `itemEntry3`)
+ SELECT `id`, 2, `itemEntry1`, `itemEntry2`, `itemEntry3`
+ FROM `creature`
+ JOIN `creature_equip_template` ON `creature_equip_template`.`entry` = `equipment_id`
+ WHERE `equipment_id` != 0;
+
+DROP TABLE `creature_equip_template`;
+RENAME TABLE `creature_equip_template2` TO `creature_equip_template`;
+
+UPDATE `creature` SET `equipment_id` = 2 WHERE `equipment_id` != 0;
+UPDATE `creature` SET `equipment_id` = 1 WHERE `equipment_id` = 0;
+
+-- From game_event_model_equip
+UPDATE `creature` SET `equipment_id` = 1 WHERE `guid` IN (12088, 12093, 12095, 79670, 79675, 79676, 79690, 79792, 79807, 79814);
+UPDATE `game_event_model_equip` SET `equipment_id` = 2 WHERE `guid` IN (12088, 12093, 12095, 79670, 79675, 79676, 79690, 79792, 79807, 79814);
+DELETE FROM `creature_equip_template` WHERE `entry` IN (1976, 23585, 424) AND `id`=2;
+INSERT INTO `creature_equip_template` (`entry`, `id`, `itemEntry1`, `itemEntry2`, `itemEntry3`) VALUES
+(1976, 2, 2715, 143, 0),
+(23585, 2, 2715, 143, 0),
+(424, 2, 2715, 143, 0);
+
+-- ALTER TABLE `creature_equip_template` CHANGE `entry` `entry` mediumint(8) unsigned NOT NULL;
+-- ALTER TABLE `creature_equip_template` ADD `id` tinyint(3) unsigned NOT NULL DEFAULT '1' AFTER `entry`;
+-- ALTER TABLE `creature_equip_template` DROP INDEX `PRIMARY`, ADD PRIMARY KEY (`entry`, `id`);
+ALTER TABLE `creature_template` DROP `equipment_id`;
+ALTER TABLE `creature` CHANGE `equipment_id` `equipment_id` tinyint(3) unsigned NOT NULL DEFAULT '1';
+ALTER TABLE `game_event_model_equip` CHANGE `equipment_id` `equipment_id` tinyint(3) unsigned NOT NULL DEFAULT '1';
+
+-- Conversion from SAI
+UPDATE `smart_scripts` SET `action_param1` = 1 WHERE `entryorguid` = 2523901 AND `source_type` = 9 AND `id` = 3;
+UPDATE `smart_scripts` SET `action_param1` = 0 WHERE `entryorguid` = 2523900 AND `source_type` = 9 AND `id` = 2;
+UPDATE `smart_scripts` SET `action_param1` = 2 WHERE `entryorguid` = 32720 AND `source_type` = 0 AND `id` = 0;
+DELETE FROM `creature_equip_template` WHERE `entry` = 25239 AND `id`=1;
+INSERT INTO `creature_equip_template` (`entry`, `id`, `itemEntry1`, `itemEntry2`, `itemEntry3`) VALUES
+(25239, 1, 6829, 0, 0);
diff --git a/sql/updates/world/2013_02_18_01_world_trinity_string.sql b/sql/updates/world/2013_02_18_01_world_trinity_string.sql
new file mode 100644
index 00000000000..84d28222fe7
--- /dev/null
+++ b/sql/updates/world/2013_02_18_01_world_trinity_string.sql
@@ -0,0 +1,3 @@
+DELETE FROM `trinity_string` WHERE `entry` = 5036;
+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
+(5036, 'EquipmentId: %u (Original: %u).');
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 23620bf1174..7cee0e20dd5 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -370,9 +370,7 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
{
if (loadDefault)
{
- if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(me->GetEntry()))
- me->LoadEquipment(creatureInfo->equipmentId, true);
-
+ me->LoadEquipment(me->GetOriginalEquipmentId(), true);
return;
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e37b9e777d8..bc94169687c 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1459,15 +1459,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (Creature* npc = (*itr)->ToCreature())
{
uint32 slot[3];
- if (e.action.equip.entry)
+ int8 equipId = (int8)e.action.equip.entry;
+ if (equipId)
{
- EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.action.equip.entry);
+ EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId);
if (!einfo)
{
- sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info entry %u", e.action.equip.entry);
+ sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u", equipId, npc->GetEntry());
return;
}
- npc->SetCurrentEquipmentId(e.action.equip.entry);
+ npc->SetCurrentEquipmentId(equipId);
slot[0] = einfo->ItemEntry[0];
slot[1] = einfo->ItemEntry[1];
slot[2] = einfo->ItemEntry[2];
@@ -1478,11 +1479,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
slot[1] = e.action.equip.slot2;
slot[2] = e.action.equip.slot3;
}
- if (!e.action.equip.mask || e.action.equip.mask & 1)
+ if (!e.action.equip.mask || (e.action.equip.mask & 1))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, slot[0]);
- if (!e.action.equip.mask || e.action.equip.mask & 2)
+ if (!e.action.equip.mask || (e.action.equip.mask & 2))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, slot[1]);
- if (!e.action.equip.mask || e.action.equip.mask & 4)
+ if (!e.action.equip.mask || (e.action.equip.mask & 4))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, slot[2]);
}
}
@@ -2028,6 +2029,45 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
delete targets;
break;
}
+ case SMART_ACTION_SET_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetUInt32Value(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_ADD_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_REMOVE_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->RemoveFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
default:
sLog->outError(LOG_FILTER_SQL, "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 69902954fde..679d2d87ffc 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -907,6 +907,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SET_HOME_POS:
case SMART_ACTION_SET_HEALTH_REGEN:
case SMART_ACTION_SET_ROOT:
+ case SMART_ACTION_SET_GO_FLAG:
+ case SMART_ACTION_ADD_GO_FLAG:
+ case SMART_ACTION_REMOVE_GO_FLAG:
break;
default:
sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index a3420071f5e..f117ab52e01 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -427,7 +427,6 @@ enum SMART_ACTION
SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat)
SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount)
SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask
-
SMART_ACTION_SET_DATA = 45, // Field, Data (only creature TODO)
SMART_ACTION_MOVE_FORWARD = 46, // distance
SMART_ACTION_SET_VISIBILITY = 47, // on/off
@@ -450,7 +449,6 @@ enum SMART_ACTION
SMART_ACTION_STORE_TARGET_LIST = 64, // varID,
SMART_ACTION_WP_RESUME = 65, // none
SMART_ACTION_SET_ORIENTATION = 66, //
-
SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
SMART_ACTION_PLAYMOVIE = 68, // entry
SMART_ACTION_MOVE_TO_POS = 69, // PointId, xyz
@@ -488,8 +486,11 @@ enum SMART_ACTION
SMART_ACTION_SET_HOME_POS = 101, // none
SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1
SMART_ACTION_SET_ROOT = 103, // off/on
+ SMART_ACTION_SET_GO_FLAG = 104, // Flags
+ SMART_ACTION_ADD_GO_FLAG = 105, // Flags
+ SMART_ACTION_REMOVE_GO_FLAG = 106, // Flags
- SMART_ACTION_END = 104
+ SMART_ACTION_END = 107
};
struct SmartAction
@@ -926,6 +927,11 @@ struct SmartAction
uint32 root;
} setRoot;
+ struct
+ {
+ uint32 flag;
+ } goFlag;
+
//! Note for any new future actions
//! All parameters must have type uint32
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index b1d0087c32c..bd560c8266e 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
@@ -56,7 +56,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
RBACData* rbac = new RBACData(GetId(username), username, -1);
// No need to Load From DB, as it's new data
- RBACGroupContainer const& groupsToAdd = _defaultGroups[0]; // 0: Default sec level
+ RBACGroupContainer const& groupsToAdd = _defaultSecGroups[0]; // 0: Default sec level
for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
rbac->AddGroup(*it, -1);
@@ -426,13 +426,23 @@ void AccountMgr::LoadRBAC()
uint8 secId = field[0].GetUInt8();
if (lastSecId != secId)
- groups = &_defaultGroups[secId];
+ groups = &_defaultSecGroups[secId];
groups->insert(field[1].GetUInt32());
}
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u permission definitions, %u role definitions and %u group definitions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime));
+
+ // Load default groups to be added to any RBAC Object.
+ std::string defaultGroups = ConfigMgr::GetStringDefault("RBAC.DefaultGroups", "");
+ Tokenizer tokens(defaultGroups, ',');
+ for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
+ if (uint32 groupId = atoi(*itr))
+ {
+ sLog->outError(LOG_FILTER_LFG, "Adding default group %u", groupId);
+ _defaultGroups.insert(groupId);
+ }
}
void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId)
@@ -459,7 +469,7 @@ void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 sec
uint8 secLevel = field[0].GetUInt8();
int32 realmId = field[1].GetUInt32();
- RBACGroupContainer const& groupsToRemove = _defaultGroups[secLevel];
+ RBACGroupContainer const& groupsToRemove = _defaultSecGroups[secLevel];
for (RBACGroupContainer::const_iterator it = groupsToRemove.begin(); it != groupsToRemove.end(); ++it)
rbac->RemoveGroup(*it, realmId);
}
@@ -467,7 +477,7 @@ void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 sec
}
// Add new groups depending on the new security Level
- RBACGroupContainer const& groupsToAdd = _defaultGroups[securityLevel];
+ RBACGroupContainer const& groupsToAdd = _defaultSecGroups[securityLevel];
for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
rbac->AddGroup(*it, realmId);
diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h
index 90c533ca5fa..440e012f1fc 100644
--- a/src/server/game/Accounts/AccountMgr.h
+++ b/src/server/game/Accounts/AccountMgr.h
@@ -77,12 +77,14 @@ class AccountMgr
RBACGroupsContainer const& GetRBACGroupList() const { return _groups; }
RBACRolesContainer const& GetRBACRoleList() const { return _roles; }
RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; }
+ RBACGroupContainer const& GetRBACDefaultGroups() const { return _defaultGroups; }
private:
RBACPermissionsContainer _permissions;
RBACRolesContainer _roles;
RBACGroupsContainer _groups;
- RBACDefaultSecurityGroupContainer _defaultGroups;
+ RBACDefaultSecurityGroupContainer _defaultSecGroups;
+ RBACGroupContainer _defaultGroups;
};
#define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp
index 4a069df05cd..121c9faae76 100644
--- a/src/server/game/Accounts/RBAC.cpp
+++ b/src/server/game/Accounts/RBAC.cpp
@@ -296,6 +296,11 @@ void RBACData::LoadFromDB()
while (result->NextRow());
}
+ // Add default groups
+ RBACGroupContainer const& groups = sAccountMgr->GetRBACDefaultGroups();
+ for (RBACGroupContainer::const_iterator itr = groups.begin(); itr != groups.end(); ++itr)
+ AddGroup(*itr);
+
// Force calculation of permissions, it wasn't performed at load time
// while adding groups, roles and permissions
CalculateNewPermissions();
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index d2c76b71801..f6e494e7b70 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -135,7 +135,7 @@ class RBACGroup: public RBACObject
RBACRoleContainer _roles; ///> Set of Roles
};
-/*
+/**
* @name RBACData
* @brief Contains all needed information about the acccount
*
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 97d414b9915..9cec59db168 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -145,7 +145,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
-m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
+m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(1), m_originalEquipmentId(1), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL)
{
@@ -323,8 +323,8 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data
// Load creature equipment
if (!data || data->equipmentId == 0) // use default from the template
- LoadEquipment(cinfo->equipmentId);
- else if (data && data->equipmentId != -1) // override, -1 means no equipment
+ LoadEquipment(GetOriginalEquipmentId());
+ else if (data && data->equipmentId != 0) // override, 0 means no equipment
LoadEquipment(data->equipmentId);
SetName(normalInfo->Name); // at normal entry always
@@ -1080,7 +1080,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
data.mapid = mapid;
data.phaseMask = phaseMask;
data.displayid = displayId;
- data.equipmentId = GetEquipmentId();
+ data.equipmentId = GetCurrentEquipmentId();
data.posX = GetPositionX();
data.posY = GetPositionY();
data.posZ = GetPositionZMinusOffset();
@@ -1115,7 +1115,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
stmt->setUInt8(index++, spawnMask);
stmt->setUInt16(index++, uint16(GetPhaseMask()));
stmt->setUInt32(index++, displayId);
- stmt->setInt32(index++, int32(GetEquipmentId()));
+ stmt->setInt32(index++, int32(GetCurrentEquipmentId()));
stmt->setFloat(index++, GetPositionX());
stmt->setFloat(index++, GetPositionY());
stmt->setFloat(index++, GetPositionZ());
@@ -1270,14 +1270,14 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint3
if (!vehId)
vehId = cinfo->VehicleId;
- if (vehId && !CreateVehicleKit(vehId, Entry))
- vehId = 0;
-
Object::_Create(guidlow, Entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT);
if (!UpdateEntry(Entry, team, data))
return false;
+ if (vehId && !CreateVehicleKit(vehId, Entry))
+ vehId = 0;
+
return true;
}
@@ -1355,24 +1355,24 @@ bool Creature::LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap)
return true;
}
-void Creature::LoadEquipment(uint32 equip_entry, bool force)
+void Creature::LoadEquipment(int8 id, bool force /*= true*/)
{
- if (equip_entry == 0)
+ if (id == 0)
{
if (force)
{
- for (uint8 i = 0; i < 3; ++i)
+ for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
m_equipmentId = 0;
}
return;
}
- EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(equip_entry);
+ EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(GetEntry(), id);
if (!einfo)
return;
- m_equipmentId = equip_entry;
+ m_equipmentId = id;
for (uint8 i = 0; i < 3; ++i)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->ItemEntry[i]);
}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 255014a7bbf..6e737709f99 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -138,7 +138,6 @@ struct CreatureTemplate
uint32 questItems[MAX_CREATURE_QUEST_ITEMS];
uint32 movementId;
bool RegenHealth;
- uint32 equipmentId;
uint32 MechanicImmuneMask;
uint32 flags_extra;
uint32 ScriptID;
@@ -234,7 +233,8 @@ struct EquipmentInfo
};
// Benchmarked: Faster than std::map (insert/find)
-typedef UNORDERED_MAP<uint16, EquipmentInfo> EquipmentInfoContainer;
+typedef UNORDERED_MAP<uint8, EquipmentInfo> EquipmentInfoContainerInternal;
+typedef UNORDERED_MAP<uint32, EquipmentInfoContainerInternal> EquipmentInfoContainer;
// from `creature` table
struct CreatureData
@@ -244,7 +244,7 @@ struct CreatureData
uint16 mapid;
uint16 phaseMask;
uint32 displayid;
- int32 equipmentId;
+ int8 equipmentId;
float posX;
float posY;
float posZ;
@@ -453,13 +453,12 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
bool Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData* data = NULL);
bool LoadCreaturesAddon(bool reload = false);
void SelectLevel(const CreatureTemplate* cinfo);
- void LoadEquipment(uint32 equip_entry, bool force=false);
+ void LoadEquipment(int8 id = 1, bool force = false);
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
void Update(uint32 time); // overwrited Unit::Update
void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
- uint32 GetEquipmentId() const { return GetCreatureTemplate()->equipmentId; }
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; }
@@ -552,8 +551,11 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void UpdateMaxPower(Powers power);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
+
+ uint8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
uint32 GetCurrentEquipmentId() { return m_equipmentId; }
- void SetCurrentEquipmentId(uint32 entry) { m_equipmentId = entry; }
+ void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; }
+
float GetSpellDamageMod(int32 Rank);
VendorItemData const* GetVendorItems() const;
@@ -748,7 +750,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void Regenerate(Powers power);
MovementGeneratorType m_defaultMovementType;
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
- uint32 m_equipmentId;
+ uint8 m_equipmentId;
+ uint8 m_originalEquipmentId;
bool m_AlreadyCallAssistance;
bool m_AlreadySearchedAssistance;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 19de01ffd41..d72b906e6a5 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -26027,7 +26027,7 @@ bool Player::AddItem(uint32 itemId, uint32 count)
ItemPosCountVec dest;
InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount);
if (msg != EQUIP_ERR_OK)
- count = noSpaceForCount;
+ count -= noSpaceForCount;
if (count == 0 || dest.empty())
{
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 9034c26d4f1..920e0357bc5 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -29,6 +29,8 @@
#include "QuestDef.h"
#include "SpellMgr.h"
#include "Unit.h"
+#include "Opcodes.h"
+#include "WorldSession.h"
#include <string>
#include <vector>
@@ -1813,6 +1815,11 @@ class Player : public Unit, public GridObject<Player>
return mMitems.erase(id) ? true : false;
}
+ void SendOnCancelExpectedVehicleRideAura()
+ {
+ WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
+ GetSession()->SendPacket(&data);
+ }
void PetSpellInitialize();
void CharmSpellInitialize();
void PossessSpellInitialize();
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index f7bc6a99fb1..d1f42de5749 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -2936,7 +2936,9 @@ void Unit::DeMorph()
Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
{
ASSERT(casterGUID || caster);
- if (!casterGUID)
+
+ // Check if these can stack anyway
+ if (!casterGUID && !newAura->IsStackableOnOneSlotWithDifferentCasters())
casterGUID = caster->GetGUID();
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
@@ -7585,48 +7587,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
break;
}
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- // Victim needs more checks so bugs, rats or summons can not be affected by the proc.
- if (GetTypeId() != TYPEID_PLAYER || !victim || victim->GetTypeId() != TYPEID_UNIT || victim->GetCreatureType() == CREATURE_TYPE_CRITTER)
- return false;
-
- Player* player = ToPlayer();
- if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE)
- {
- break;
- }
- else if (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)
- {
- uint32 spellId = 0;
- uint32 questId = 0;
- switch (victim->GetEntry())
- {
- case 36678: // NPC: Professor Putricide
- questId = 24749; // Quest: Unholy Infusion
- spellId = 71516; // Spell: Shadow Infusion
- break;
- case 37955: // NPC: Blood-Queen Lana'thel
- questId = 24756; // Quest: Blood Infusion
- spellId = 72154; // Spell: Thirst Quenched
- break;
- case 36853: // NPC: Sindragosa
- questId = 24757; // Quest: Frost Infusion
- spellId = 72290; // Spell: Frost-Imbued Blade
- break;
- default:
- return false;
- }
-
- if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE || !player->HasAura(spellId))
- return false;
-
- break;
- }
- else
- return false;
- }
}
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
@@ -10248,8 +10208,6 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
{
if (CreateVehicleKit(VehicleId, creatureEntry))
{
- GetVehicleKit()->Reset();
-
// Send others that we now have a vehicle
WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, GetPackGUID().size()+4);
data.appendPackGUID(GetGUID());
@@ -14823,7 +14781,10 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
// dismount players when charmed
if (GetTypeId() == TYPEID_PLAYER)
- Dismount();
+ RemoveAurasByType(SPELL_AURA_MOUNTED);
+
+ if (charmer->GetTypeId() == TYPEID_PLAYER)
+ charmer->RemoveAurasByType(SPELL_AURA_MOUNTED);
ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle());
@@ -16082,31 +16043,10 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
{
if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->isInCombat())
return;
-
- InterruptNonMeleeSpells(false);
- player->StopCastingCharm();
- player->StopCastingBindSight();
- Dismount();
- RemoveAurasByType(SPELL_AURA_MOUNTED);
-
- // drop flag at invisible in bg
- if (Battleground* bg = player->GetBattleground())
- bg->EventPlayerDroppedFlag(player);
-
- WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- player->GetSession()->SendPacket(&data);
-
- player->UnsummonPetTemporaryIfAny();
}
ASSERT(!m_vehicle);
- m_vehicle = vehicle;
-
- if (!m_vehicle->AddPassenger(this, seatId))
- {
- m_vehicle = NULL;
- return;
- }
+ (void)vehicle->AddPassenger(this, seatId);
}
void Unit::ChangeSeat(int8 seatId, bool next)
@@ -16114,15 +16054,17 @@ void Unit::ChangeSeat(int8 seatId, bool next)
if (!m_vehicle)
return;
- if (seatId < 0)
- {
- seatId = m_vehicle->GetNextEmptySeat(GetTransSeat(), next);
- if (seatId < 0)
- return;
- }
- else if (seatId == GetTransSeat() || !m_vehicle->HasEmptySeat(seatId))
+ // Don't change if current and new seat are identical
+ if (seatId == GetTransSeat())
+ return;
+
+ SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
+ // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
+ if (seat == m_vehicle->Seats.end() || seat->second.Passenger)
return;
+ // Todo: the functions below could be consolidated and refactored to take
+ // SeatMap::const_iterator as parameter, to save redundant map lookups.
m_vehicle->RemovePassenger(this);
if (!m_vehicle->AddPassenger(this, seatId))
ASSERT(false);
@@ -16149,6 +16091,9 @@ void Unit::ExitVehicle(Position const* /*exitPosition*/)
void Unit::_ExitVehicle(Position const* exitPosition)
{
+ /// It's possible m_vehicle is NULL, when this function is called indirectly from @VehicleJoinEvent::Abort.
+ /// In that case it was not possible to add the passenger to the vehicle. The vehicle aura has already been removed
+ /// from the target in the aforementioned function and we don't need to do anything else at this point.
if (!m_vehicle)
return;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index a8e088b2dd3..f9a0ca80f90 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -332,6 +332,7 @@ class UnitAI;
class Totem;
class Transport;
class Vehicle;
+class VehicleJoinEvent;
class TransportBase;
class SpellCastTargets;
@@ -2170,6 +2171,7 @@ class Unit : public WorldObject
uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
+ friend class VehicleJoinEvent;
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
void RemoveVehicleKit();
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 16a90018293..02c5e4a2e1a 100755..100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -30,9 +30,12 @@
#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
+#include "EventProcessor.h"
+#include "Player.h"
+#include "Battleground.h"
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
-_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
+UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry), _status(STATUS_NONE)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@@ -41,10 +44,16 @@ _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntr
{
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
if (veSeat->CanEnterOrExit())
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
}
+ // Set or remove correct flags based on available seats. Will overwrite db data (if wrong).
+ if (UsableSeatNum)
+ _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
+ else
+ _me->RemoveFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
+
InitMovementInfoForBase();
}
@@ -56,6 +65,15 @@ Vehicle::~Vehicle()
ASSERT(!itr->second.Passenger);
}
+/**
+ * @fn void Vehicle::Install()
+ *
+ * @brief Initializes power type for vehicle. Nothing more.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Install()
{
if (Creature* creature = _me->ToCreature())
@@ -114,15 +132,26 @@ void Vehicle::InstallAllAccessories(bool evading)
InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime);
}
+/**
+ * @fn void Vehicle::Uninstall()
+ *
+ * @brief Removes all passengers and sets status to STATUS_UNINSTALLING.
+ * No new passengers can be added to the vehicle after this call.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Uninstall()
{
/// @Prevent recursive uninstall call. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
- if (_status == STATUS_UNINSTALLING)
+ if (_status == STATUS_UNINSTALLING && !GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
{
sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to uninstall, but already has STATUS_UNINSTALLING! "
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry());
return;
}
+
_status = STATUS_UNINSTALLING;
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
RemoveAllPassengers();
@@ -131,26 +160,39 @@ void Vehicle::Uninstall()
sScriptMgr->OnUninstall(this);
}
+/**
+ * @fn void Vehicle::Reset(bool evading )
+ *
+ * @brief Reapplies immunities and reinstalls accessories. Only has effect for creatures.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param evading true if called from CreatureAI::EnterEvadeMode
+ */
+
void Vehicle::Reset(bool evading /*= false*/)
{
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
- if (_me->GetTypeId() == TYPEID_PLAYER)
- {
- if (_usableSeatNum)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- }
- else
- {
- ApplyAllImmunities();
- InstallAllAccessories(evading);
- if (_usableSeatNum)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
+ if (GetBase()->GetTypeId() != TYPEID_UNIT)
+ return;
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnReset(this);
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset (Entry: %u, GuidLow: %u, DBGuid: %u)", GetCreatureEntry(), _me->GetGUIDLow(), _me->ToCreature()->GetDBTableGUIDLow());
+
+ ApplyAllImmunities();
+ InstallAllAccessories(evading);
+
+ sScriptMgr->OnReset(this);
}
+/**
+ * @fn void Vehicle::ApplyAllImmunities()
+ *
+ * @brief Applies specific immunities that cannot be set in DB.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::ApplyAllImmunities()
{
// This couldn't be done in DB, because some spells have MECHANIC_NONE
@@ -199,10 +241,28 @@ void Vehicle::ApplyAllImmunities()
}
}
+/**
+ * @fn void Vehicle::RemoveAllPassengers()
+ *
+ * @brief Removes all current and pending passengers from the vehicle.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::RemoveAllPassengers()
{
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemoveAllPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
+ /// Setting to_Abort to true will cause @VehicleJoinEvent::Abort to be executed on next @Unit::UpdateEvents call
+ /// This will properly "reset" the pending join process for the passenger.
+ while (_pendingJoinEvents.size())
+ {
+ VehicleJoinEvent* e = _pendingJoinEvents.front();
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_front();
+ }
+
// Passengers always cast an aura with SPELL_AURA_CONTROL_VEHICLE on the vehicle
// We just remove the aura and the unapply handler will make the target leave the vehicle.
// We don't need to iterate over Seats
@@ -215,6 +275,19 @@ void Vehicle::RemoveAllPassengers()
// ASSERT(!itr->second.passenger);
}
+/**
+ * @fn bool Vehicle::HasEmptySeat(int8 seatId) const
+ *
+ * @brief Checks if vehicle's seat specified by 'seatId' is empty.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Identifier for the seat.
+ *
+ * @return true if empty seat, false if not.
+ */
+
bool Vehicle::HasEmptySeat(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -223,6 +296,19 @@ bool Vehicle::HasEmptySeat(int8 seatId) const
return !seat->second.Passenger;
}
+/**
+ * @fn Unit* Vehicle::GetPassenger(int8 seatId) const
+ *
+ * @brief Gets a passenger on specified seat.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Seat to look on.
+ *
+ * @return null if it not found, else pointer to passenger if in world
+ */
+
Unit* Vehicle::GetPassenger(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -232,78 +318,105 @@ Unit* Vehicle::GetPassenger(int8 seatId) const
return ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger);
}
-int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
+/**
+ * @fn SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
+ *
+ * @brief Gets the next empty seat based on current seat.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Identifier for the current seat.
+ * @param next true if iterating forward, false means iterating backwards.
+ *
+ * @return The next empty seat.
+ */
+
+SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
if (seat == Seats.end())
- return -1;
+ return seat;
while (seat->second.Passenger || (!seat->second.SeatInfo->CanEnterOrExit() && !seat->second.SeatInfo->IsUsableByOverride()))
{
if (next)
{
- ++seat;
- if (seat == Seats.end())
+ if (++seat == Seats.end())
seat = Seats.begin();
}
else
{
- if (seat == Seats.begin())
+ if (seat-- == Seats.begin())
seat = Seats.end();
- --seat;
}
+ // Make sure we don't loop indefinetly
if (seat->first == seatId)
- return -1; // no available seat
+ return Seats.end();
}
- return seat->first;
+ return seat;
}
+/**
+ * @fn void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type,
+ * uint32 summonTime)
+ *
+ * @brief Installs an accessory.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param entry The NPC entry of accessory.
+ * @param seatId Identifier for the seat to add the accessory to.
+ * @param minion true if accessory considered a 'minion'. Implies that the accessory will despawn when the vehicle despawns.
+ * Essentially that it has no life without the vehicle. Their fates are bound.
+ * @param type See enum @SummonType.
+ * @param summonTime Time after which the minion is despawned in case of a timed despawn @type specified.
+ */
+
void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime)
{
/// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
{
- sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to install accessory Entry: %u on seat %d with STATUS_UNINSTALLING! "
- "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry(), entry, (int32)seatId);
+ sLog->outError(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB GUID: %u, Entry: %u) attempts to install accessory (Entry: %u) on seat %i with STATUS_UNINSTALLING! "
+ "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(),
+ (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(), entry, (int32)seatId);
return;
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle: Installing accessory entry %u on vehicle entry %u (seat:%i)", entry, GetCreatureEntry(), seatId);
- if (Unit* passenger = GetPassenger(seatId))
- {
- // already installed
- if (passenger->GetEntry() == entry)
- {
- ASSERT(passenger->GetTypeId() == TYPEID_UNIT);
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsInEvadeMode() && passenger->ToCreature()->IsAIEnabled)
- passenger->ToCreature()->AI()->EnterEvadeMode();
- return;
- }
- }
- else
- passenger->ExitVehicle(); // this should not happen
- }
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB Guid: %u, Entry %u): installing accessory (Entry: %u) on seat: %i",
+ _me->GetGUIDLow(), (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(),
+ entry, (int32)seatId);
- if (TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime))
- {
- if (minion)
- accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
+ TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime);
+ ASSERT(accessory);
- if (!_me->HandleSpellClick(accessory, seatId))
- {
- accessory->UnSummon();
- return;
- }
+ if (minion)
+ accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnInstallAccessory(this, accessory);
- }
+ (void)_me->HandleSpellClick(accessory, seatId);
+
+ /// If for some reason adding accessory to vehicle fails it will unsummon in
+ /// @VehicleJoinEvent::Abort
}
+/**
+ * @fn bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
+ *
+ * @brief Attempts to add a passenger to the vehicle on 'seatId'.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] The prospective passenger.
+ * @param seatId Identifier for the seat. Value of -1 indicates the next available seat.
+ *
+ * @return true if it succeeds, false if it fails.
+ */
+
bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
{
/// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
@@ -314,10 +427,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
return false;
}
- if (unit->GetVehicle() != this)
- return false;
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s scheduling enter vehicle (entry: %u, vehicleId: %u, guid: %u (dbguid: %s) on seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(),
+ (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : 0), (int32)seatId);
+ // The seat selection code may kick other passengers off the vehicle.
+ // While the validity of the following may be arguable, it is possible that when such a passenger
+ // exits the vehicle will dismiss. That's why the actual adding the passenger to the vehicle is scheduled
+ // asynchronously, so it can be cancelled easily in case the vehicle is uninstalled meanwhile.
SeatMap::iterator seat;
+ VehicleJoinEvent* e = new VehicleJoinEvent(this, unit);
+ unit->m_Events.AddEvent(e, unit->m_Events.CalculateTime(0));
+ _pendingJoinEvents.push_back(e);
+
if (seatId < 0) // no specific seat requirement
{
for (seat = Seats.begin(); seat != Seats.end(); ++seat)
@@ -325,86 +447,47 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
break;
if (seat == Seats.end()) // no available seat
+ {
+ CancelJoinEvent(e);
return false;
+ }
+
+ e->Seat = seat;
}
else
{
seat = Seats.find(seatId);
if (seat == Seats.end())
+ {
+ CancelJoinEvent(e);
return false;
+ }
+ e->Seat = seat;
if (seat->second.Passenger)
{
- if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger))
- passenger->ExitVehicle();
- else
- seat->second.Passenger = 0;
+ Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger);
+ ASSERT(passenger);
+ passenger->ExitVehicle();
}
ASSERT(!seat->second.Passenger);
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
-
- seat->second.Passenger = unit->GetGUID();
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- ASSERT(_usableSeatNum);
- --_usableSeatNum;
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- }
-
- if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
- unit->AddUnitState(UNIT_STATE_ONVEHICLE);
-
- VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
- unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
- unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
- unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
- unit->m_movementInfo.t_pos.SetOrientation(0);
- unit->m_movementInfo.t_time = 0; // 1 for player
- unit->m_movementInfo.t_seat = seat->first;
- unit->m_movementInfo.t_guid = _me->GetGUID();
-
- if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER &&
- seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
- ASSERT(_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
-
- if (_me->IsInWorld())
- {
- unit->SendClearTarget(); // SMSG_BREAK_TARGET
- unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
- // also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(unit);
- init.DisableTransportPathTransformations();
- init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
- init.SetFacing(0.0f);
- init.SetTransportEnter();
- init.Launch();
-
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsAIEnabled)
- _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
-
- // update all passenger's positions
- //Passenger's spline OR vehicle movement will update positions
- //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
- }
- }
-
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnAddPassenger(this, unit, seatId);
-
return true;
}
+/**
+ * @fn void Vehicle::RemovePassenger(Unit* unit)
+ *
+ * @brief Removes the passenger from the vehicle.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] unit The passenger to remove..
+ */
+
void Vehicle::RemovePassenger(Unit* unit)
{
if (unit->GetVehicle() != this)
@@ -413,20 +496,12 @@ void Vehicle::RemovePassenger(Unit* unit)
SeatMap::iterator seat = GetSeatIteratorForPassenger(unit);
ASSERT(seat != Seats.end());
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
seat->second.Passenger = 0;
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- ++_usableSeatNum;
- }
+ if (seat->second.SeatInfo->CanEnterOrExit() && ++UsableSeatNum)
+ _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
unit->ClearUnitState(UNIT_STATE_ONVEHICLE);
@@ -435,7 +510,7 @@ void Vehicle::RemovePassenger(Unit* unit)
if (_me->IsInWorld())
{
- unit->m_movementInfo.t_pos.Relocate(0, 0, 0, 0);
+ unit->m_movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
unit->m_movementInfo.t_time = 0;
unit->m_movementInfo.t_seat = 0;
}
@@ -451,7 +526,15 @@ void Vehicle::RemovePassenger(Unit* unit)
sScriptMgr->OnRemovePassenger(this, unit);
}
-//! Must be called after m_base::Relocate
+/**
+ * @fn void Vehicle::RelocatePassengers()
+ *
+ * @brief Relocate passengers. Must be called after m_base::Relocate
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::RelocatePassengers()
{
ASSERT(_me->GetMap());
@@ -466,21 +549,40 @@ void Vehicle::RelocatePassengers()
float px, py, pz, po;
passenger->m_movementInfo.t_pos.GetPosition(px, py, pz, po);
CalculatePassengerPosition(px, py, pz, po);
+
passenger->UpdatePosition(px, py, pz, po);
}
}
}
+/**
+ * @fn void Vehicle::Dismiss()
+ *
+ * @brief Dismiss the vehicle. Removes passengers and despawns self. Only valid for creatures.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Dismiss()
{
if (GetBase()->GetTypeId() != TYPEID_UNIT)
return;
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u", _creatureEntry, _me->GetGUIDLow());
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u, DBGuid: %u", GetCreatureEntry(), _me->GetGUIDLow(), _me->ToCreature()->GetDBTableGUIDLow());
Uninstall();
GetBase()->ToCreature()->DespawnOrUnsummon();
}
+/**
+ * @fn void Vehicle::InitMovementInfoForBase()
+ *
+ * @brief Sets correct MovementFlags2 based on VehicleFlags from DBC.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::InitMovementInfoForBase()
{
uint32 vehicleFlags = GetVehicleInfo()->m_flags;
@@ -497,6 +599,19 @@ void Vehicle::InitMovementInfoForBase()
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING);
}
+/**
+ * @fn VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
+ *
+ * @brief Returns information on the seat of specified passenger, represented by the format in VehicleSeat.dbc
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] The passenger for which we check the seat info.
+ *
+ * @return null if passenger not found on vehicle, else the DBC record for the seat.
+ */
+
VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
{
SeatMap::iterator itr;
@@ -507,6 +622,19 @@ VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
return NULL;
}
+/**
+ * @fn SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
+ *
+ * @brief Gets seat iterator for specified passenger.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] passenger Passenger to look up.
+ *
+ * @return The seat iterator for specified passenger if it's found on the vehicle. Otherwise Seats.end() (invalid iterator).
+ */
+
SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
{
SeatMap::iterator itr;
@@ -517,6 +645,17 @@ SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
return Seats.end();
}
+/**
+ * @fn uint8 Vehicle::GetAvailableSeatCount() const
+ *
+ * @brief Gets the available seat count.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @return The available seat count.
+ */
+
uint8 Vehicle::GetAvailableSeatCount() const
{
uint8 ret = 0;
@@ -547,3 +686,139 @@ void Vehicle::CalculatePassengerOffset(float& x, float& y, float& z, float& o)
y = (iny - inx * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
x = (inx + iny * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
}
+
+/**
+ * @fn void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+ *
+ * @brief Aborts delayed @VehicleJoinEvent objects.
+ * Implies that the related unit will not be boarding the vehicle after all.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] e The VehicleJoinEvent* to process.
+ */
+
+void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+{
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_back();
+}
+
+/**
+ * @fn bool VehicleJoinEvent::Execute(uint64, uint32)
+ *
+ * @brief Actually adds the passenger @Passenger to vehicle @Target.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param parameter1 Unused
+ * @param parameter2 Unused.
+ *
+ * @return true, cannot fail.
+ *
+ */
+
+bool VehicleJoinEvent::Execute(uint64, uint32)
+{
+ ASSERT(Passenger->IsInWorld());
+ ASSERT(Target->GetBase()->IsInWorld());
+
+ Passenger->m_vehicle = Target;
+ Seat->second.Passenger = Passenger->GetGUID();
+ if (Seat->second.SeatInfo->CanEnterOrExit())
+ {
+ ASSERT(Target->UsableSeatNum);
+ --(Target->UsableSeatNum);
+ if (!Target->UsableSeatNum)
+ {
+ if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER)
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
+ else
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ }
+
+ Passenger->InterruptNonMeleeSpells(false);
+
+ Player* player = Passenger->ToPlayer();
+ if (player)
+ {
+ // drop flag
+ if (Battleground* bg = player->GetBattleground())
+ bg->EventPlayerDroppedFlag(player);
+
+ player->StopCastingCharm();
+ player->StopCastingBindSight();
+ player->SendOnCancelExpectedVehicleRideAura();
+ player->UnsummonPetTemporaryIfAny();
+ }
+
+ if (Seat->second.SeatInfo->m_flags && !(Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
+ Passenger->AddUnitState(UNIT_STATE_ONVEHICLE);
+
+ VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
+ Passenger->m_movementInfo.t_pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
+ Passenger->m_movementInfo.t_time = 0; // 1 for player
+ Passenger->m_movementInfo.t_seat = Seat->first;
+ Passenger->m_movementInfo.t_guid = Target->GetBase()->GetGUID();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT && Passenger->GetTypeId() == TYPEID_PLAYER &&
+ Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
+ ASSERT(Target->GetBase()->SetCharmedBy(Passenger, CHARM_TYPE_VEHICLE)) // SMSG_CLIENT_CONTROL
+
+ Passenger->SendClearTarget(); // SMSG_BREAK_TARGET
+ Passenger->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
+ // also adds MOVEMENTFLAG_ROOT
+
+ Movement::MoveSplineInit init(Passenger);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ, false, true);
+ init.SetFacing(0.0f);
+ init.SetTransportEnter();
+ init.Launch();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ {
+ if (Target->GetBase()->ToCreature()->IsAIEnabled)
+ Target->GetBase()->ToCreature()->AI()->PassengerBoarded(Passenger, Seat->first, true);
+
+ sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first);
+
+ // Actually quite a redundant hook. Could just use OnAddPassenger and check for unit typemask inside script.
+ if (Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
+ sScriptMgr->OnInstallAccessory(Target, Passenger->ToCreature());
+
+ // update all passenger's positions
+ //Passenger's spline OR vehicle movement will update positions
+ //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
+ }
+
+ return true;
+}
+
+/**
+ * @fn void VehicleJoinEvent::Abort(uint64)
+ *
+ * @brief Aborts the event. Implies that unit @Passenger will not be boarding vehicle @Target after all.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param parameter1 Unused
+ */
+
+void VehicleJoinEvent::Abort(uint64)
+{
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, board on vehicle GuidLow: %u, Entry: %u SeatId: %i cancelled",
+ Passenger->GetGUIDLow(), Passenger->GetEntry(), Target->GetBase()->GetGUIDLow(), Target->GetBase()->GetEntry(), (int32)Seat->first);
+
+ /// @SPELL_AURA_CONTROL_VEHICLE auras can be applied even when the passenger is not (yet) on the vehicle.
+ /// When this code is triggered it means that something went wrong in @Vehicle::AddPassenger, and we should remove
+ /// the aura manually.
+ Target->GetBase()->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, Passenger->GetGUID());
+
+ if (Passenger->IsInWorld() && Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
+ Passenger->ToCreature()->DespawnOrUnsummon();
+}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index 823fb72b8a8..7ec0df8e533 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -23,12 +23,12 @@
#include "Object.h"
#include "VehicleDefines.h"
#include "Unit.h"
+#include <deque>
struct VehicleEntry;
-
class Unit;
-
typedef std::set<uint64> GuidSet;
+class VehicleJoinEvent;
class Vehicle : public TransportBase
{
@@ -46,7 +46,7 @@ class Vehicle : public TransportBase
bool HasEmptySeat(int8 seatId) const;
Unit* GetPassenger(int8 seatId) const;
- int8 GetNextEmptySeat(int8 seatId, bool next) const;
+ SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const;
uint8 GetAvailableSeatCount() const;
bool AddPassenger(Unit* passenger, int8 seatId = -1);
@@ -61,11 +61,15 @@ class Vehicle : public TransportBase
void SetLastShootPos(Position const& pos) { m_lastShootPos.Relocate(pos); }
Position GetLastShootPos() { return m_lastShootPos; }
- SeatMap Seats;
+ SeatMap Seats; ///< The collection of all seats on the vehicle. Including vacant ones.
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
protected:
+ friend class VehicleJoinEvent;
+ uint32 UsableSeatNum; ///< Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
+
+ protected:
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
friend void Unit::RemoveVehicleKit();
@@ -88,12 +92,27 @@ class Vehicle : public TransportBase
/// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(float& x, float& y, float& z, float& o);
- Unit* _me;
- VehicleEntry const* _vehicleInfo;
+ Unit* _me; ///< The underlying unit with the vehicle kit. Can be player or creature.
+ VehicleEntry const* _vehicleInfo; ///< DBC data for vehicle
GuidSet vehiclePlayers;
- uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
- uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players
- Status _status;
+
+ uint32 _creatureEntry; ///< Can be different than the entry of _me in case of players
+ Status _status; ///< Internal variable for sanity checks
Position m_lastShootPos;
+ std::deque<VehicleJoinEvent*> _pendingJoinEvents; ///< Collection of delayed join events for prospective passengers
+ void CancelJoinEvent(VehicleJoinEvent* e);
+};
+
+class VehicleJoinEvent : public BasicEvent
+{
+ friend class Vehicle;
+ protected:
+ VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) {}
+ bool Execute(uint64, uint32);
+ void Abort(uint64);
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator Seat;
};
#endif
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index 051d76f46ed..d06ff1fa533 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -450,8 +450,8 @@ void GameEventMgr::LoadFromDB()
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3
- QueryResult result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id "
+ // 0 1 2 3 4
+ QueryResult result = WorldDatabase.Query("SELECT creature.guid, creature.id, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id "
"FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
if (!result)
@@ -466,7 +466,8 @@ void GameEventMgr::LoadFromDB()
Field* fields = result->Fetch();
uint32 guid = fields[0].GetUInt32();
- uint16 event_id = fields[1].GetUInt8();
+ uint32 entry = fields[1].GetUInt32();
+ uint16 event_id = fields[2].GetUInt8();
if (event_id >= mGameEventModelEquip.size())
{
@@ -476,17 +477,18 @@ void GameEventMgr::LoadFromDB()
ModelEquipList& equiplist = mGameEventModelEquip[event_id];
ModelEquip newModelEquipSet;
- newModelEquipSet.modelid = fields[2].GetUInt32();
- newModelEquipSet.equipment_id = fields[3].GetUInt32();
+ newModelEquipSet.modelid = fields[3].GetUInt32();
+ newModelEquipSet.equipment_id = fields[4].GetUInt8();
newModelEquipSet.equipement_id_prev = 0;
newModelEquipSet.modelid_prev = 0;
if (newModelEquipSet.equipment_id > 0)
{
- if (!sObjectMgr->GetEquipmentInfo(newModelEquipSet.equipment_id))
+ int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id);
+ if (!sObjectMgr->GetEquipmentInfo(entry, equipId))
{
- sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.",
- guid, newModelEquipSet.equipment_id);
+ sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u, entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.",
+ guid, entry, newModelEquipSet.equipment_id);
continue;
}
}
@@ -1103,14 +1105,8 @@ void GameEventMgr::UnApplyEvent(uint16 event_id)
void GameEventMgr::ApplyNewEvent(uint16 event_id)
{
- switch (sWorld->getIntConfig(CONFIG_EVENT_ANNOUNCE))
- {
- case 0: // disable
- break;
- case 1: // announce events
- sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
- break;
- }
+ if (sWorld->getBoolConfig(CONFIG_EVENT_ANNOUNCE))
+ sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
sLog->outInfo(LOG_FILTER_GAMEEVENTS, "GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str());
@@ -1332,7 +1328,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
itr->second.equipement_id_prev = creature->GetCurrentEquipmentId();
itr->second.modelid_prev = creature->GetDisplayId();
creature->LoadEquipment(itr->second.equipment_id, true);
- if (itr->second.modelid >0 && itr->second.modelid_prev != itr->second.modelid)
+ if (itr->second.modelid > 0 && itr->second.modelid_prev != itr->second.modelid)
{
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid);
if (minfo)
@@ -1347,7 +1343,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
else
{
creature->LoadEquipment(itr->second.equipement_id_prev, true);
- if (itr->second.modelid_prev >0 && itr->second.modelid_prev != itr->second.modelid)
+ if (itr->second.modelid_prev > 0 && itr->second.modelid_prev != itr->second.modelid)
{
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid_prev);
if (minfo)
@@ -1370,7 +1366,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
sObjectMgr->GetCreatureModelRandomGender(&displayID);
if (data2->equipmentId == 0)
- itr->second.equipement_id_prev = cinfo->equipmentId;
+ itr->second.equipement_id_prev = 1;
else if (data2->equipmentId != -1)
itr->second.equipement_id_prev = data->equipmentId;
itr->second.modelid_prev = displayID;
diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
index 25aa99f858a..192c441f50f 100644
--- a/src/server/game/Events/GameEventMgr.h
+++ b/src/server/game/Events/GameEventMgr.h
@@ -73,9 +73,9 @@ struct GameEventData
struct ModelEquip
{
uint32 modelid;
- uint32 equipment_id;
uint32 modelid_prev;
- uint32 equipement_id_prev;
+ uint8 equipment_id;
+ uint8 equipement_id_prev;
};
struct NPCVendorEntry
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 8597b6098a9..85022c9164c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -427,8 +427,8 @@ void ObjectMgr::LoadCreatureTemplates()
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
// 71 72 73 74 75 76 77 78 79 80 81 82
"InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, "
- // 83 84 85 86 87 88 89
- " questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName "
+ // 83 84 85 86 87 88
+ " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName "
"FROM creature_template;");
if (!result)
@@ -525,10 +525,9 @@ void ObjectMgr::LoadCreatureTemplates()
creatureTemplate.movementId = fields[82].GetUInt32();
creatureTemplate.RegenHealth = fields[83].GetBool();
- creatureTemplate.equipmentId = fields[84].GetUInt32();
- creatureTemplate.MechanicImmuneMask = fields[85].GetUInt32();
- creatureTemplate.flags_extra = fields[86].GetUInt32();
- creatureTemplate.ScriptID = GetScriptId(fields[87].GetCString());
+ creatureTemplate.MechanicImmuneMask = fields[84].GetUInt32();
+ creatureTemplate.flags_extra = fields[85].GetUInt32();
+ creatureTemplate.ScriptID = GetScriptId(fields[86].GetCString());
++count;
}
@@ -877,15 +876,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
}
- if (cInfo->equipmentId > 0) // 0 no equipment
- {
- if (!GetEquipmentInfo(cInfo->equipmentId))
- {
- sLog->outError(LOG_FILTER_SQL, "Table `creature_template` lists creature (Entry: %u) with `equipment_id` %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
- const_cast<CreatureTemplate*>(cInfo)->equipmentId = 0;
- }
- }
-
/// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
if (cInfo->scale <= 0.0f)
{
@@ -1011,11 +1001,28 @@ CreatureAddon const* ObjectMgr::GetCreatureTemplateAddon(uint32 entry)
return NULL;
}
-EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
+EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry, int8& id)
{
EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry);
- if (itr != _equipmentInfoStore.end())
- return &(itr->second);
+ if (itr == _equipmentInfoStore.end())
+ return NULL;
+
+ if (itr->second.empty())
+ return NULL;
+
+ if (id == -1) // select a random element
+ {
+ EquipmentInfoContainerInternal::const_iterator ritr = itr->second.begin();
+ std::advance(ritr, urand(0u, itr->second.size()));
+ id = std::distance(itr->second.begin(), ritr) + 1;
+ return &ritr->second;
+ }
+ else
+ {
+ EquipmentInfoContainerInternal::const_iterator itr2 = itr->second.find(id);
+ if (itr2 != itr->second.end())
+ return &itr2->second;
+ }
return NULL;
}
@@ -1024,7 +1031,8 @@ void ObjectMgr::LoadEquipmentTemplates()
{
uint32 oldMSTime = getMSTime();
- QueryResult result = WorldDatabase.Query("SELECT entry, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
+ // 0 1 2 3 4
+ QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
if (!result)
{
@@ -1037,13 +1045,21 @@ void ObjectMgr::LoadEquipmentTemplates()
{
Field* fields = result->Fetch();
- uint16 entry = fields[0].GetUInt16();
+ uint32 entry = fields[0].GetUInt32();
+
+ if (!sObjectMgr->GetCreatureTemplate(entry))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry);
+ continue;
+ }
+
+ uint8 id = fields[1].GetUInt8();
- EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry];
+ EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry][id];
- equipmentInfo.ItemEntry[0] = fields[1].GetUInt32();
- equipmentInfo.ItemEntry[1] = fields[2].GetUInt32();
- equipmentInfo.ItemEntry[2] = fields[3].GetUInt32();
+ equipmentInfo.ItemEntry[0] = fields[2].GetUInt32();
+ equipmentInfo.ItemEntry[1] = fields[3].GetUInt32();
+ equipmentInfo.ItemEntry[2] = fields[4].GetUInt32();
for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
{
@@ -1054,8 +1070,8 @@ void ObjectMgr::LoadEquipmentTemplates()
if (!dbcItem)
{
- sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u, forced to 0.",
- equipmentInfo.ItemEntry[i], i+1, entry);
+ sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id=%u, forced to 0.",
+ equipmentInfo.ItemEntry[i], i+1, entry, id);
equipmentInfo.ItemEntry[i] = 0;
continue;
}
@@ -1070,8 +1086,8 @@ void ObjectMgr::LoadEquipmentTemplates()
dbcItem->InventoryType != INVTYPE_THROWN &&
dbcItem->InventoryType != INVTYPE_RANGEDRIGHT)
{
- sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u is not equipable in a hand, forced to 0.",
- equipmentInfo.ItemEntry[i], i+1, entry);
+ sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id = %u is not equipable in a hand, forced to 0.",
+ equipmentInfo.ItemEntry[i], i+1, entry, id);
equipmentInfo.ItemEntry[i] = 0;
}
}
@@ -1518,13 +1534,13 @@ void ObjectMgr::LoadCreatures()
if (!ok)
continue;
- // -1 no equipment, 0 use default
- if (data.equipmentId > 0)
+ // -1 random, 0 no equipment, 1 is default (may or may not have equipment)
+ if (data.equipmentId != 0)
{
- if (!GetEquipmentInfo(data.equipmentId))
+ if (!GetEquipmentInfo(data.id, data.equipmentId) && data.equipmentId != 1)
{
sLog->outError(LOG_FILTER_SQL, "Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
- data.equipmentId = -1;
+ data.equipmentId = 1;
}
}
@@ -1698,7 +1714,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float
data.id = entry;
data.mapid = mapId;
data.displayid = 0;
- data.equipmentId = cInfo->equipmentId;
+ data.equipmentId = 1;
data.posX = x;
data.posY = y;
data.posZ = z;
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 8c14f902c1f..d0963a224b7 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -672,7 +672,7 @@ class ObjectMgr
CreatureModelInfo const* GetCreatureModelRandomGender(uint32* displayID);
static uint32 ChooseDisplayId(uint32 team, const CreatureTemplate* cinfo, const CreatureData* data = NULL);
static void ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data = NULL);
- EquipmentInfo const* GetEquipmentInfo(uint32 entry);
+ EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id);
CreatureAddon const* GetCreatureAddon(uint32 lowguid);
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
ItemTemplate const* GetItemTemplate(uint32 entry);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 031a8ee96e7..90c97562185 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -665,7 +665,7 @@ void Group::ChangeLeader(uint64 guid)
if (!player)
return;
- sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid);
+ sScriptMgr->OnGroupChangeLeader(this, guid, m_leaderGuid);
if (!isBGGroup() && !isBFGroup())
{
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e08a7a30699..4d72e79f4df 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1650,8 +1650,7 @@ void WorldSession::HandleCancelMountAuraOpcode(WorldPacket& /*recvData*/)
return;
}
- _player->Dismount();
- _player->RemoveAurasByType(SPELL_AURA_MOUNTED);
+ _player->RemoveAurasByType(SPELL_AURA_MOUNTED); // Calls Dismount()
}
void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 03884ae003e..99d36135977 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1041,7 +1041,8 @@ enum TrinityStrings
LANG_COMMAND_NO_ACHIEVEMENT_CRITERIA_FOUND = 5033,
LANG_COMMAND_NO_OUTDOOR_PVP_FORUND = 5034,
LANG_CALL_FOR_HELP = 5035,
- // Room for more Trinity strings 5036-9999
+ LANG_NPCINFO_EQUIPMENT = 5036,
+ // Room for more Trinity strings 5037-9999
// Level requirement notifications
LANG_SAY_REQ = 6604,
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 5f93551a099..0ef69a38ea4 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -5320,10 +5320,7 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode,
target->SendMessageToSet(&data, true);
if (apply)
- {
- data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- target->ToPlayer()->GetSession()->SendPacket(&data);
- }
+ target->ToPlayer()->SendOnCancelExpectedVehicleRideAura();
}
void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 4abca023dd3..36e58287599 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -933,6 +933,10 @@ bool Aura::CanBeSaved() const
if (HasEffectType(SPELL_AURA_OPEN_STABLE))
return false;
+ // Can't save vehicle auras, it requires both caster & target to be in world
+ if (HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
+ return false;
+
// Incanter's Absorbtion - considering the minimal duration and problems with aura stacking
// we skip saving this aura
// Also for some reason other auras put as MultiSlot crash core on keeping them after restart,
@@ -1814,16 +1818,17 @@ void Aura::LoadScripts()
bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET);
std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, target))
- return false;
+ result &= hookItr->Call(*scritr, target);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+ return result;
}
void Aura::CallScriptDispel(DispelInfo* dispelInfo)
@@ -1833,7 +1838,8 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1845,7 +1851,8 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1858,14 +1865,15 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -1877,12 +1885,12 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -1895,10 +1903,9 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1910,10 +1917,9 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1926,14 +1932,15 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp);
std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -1944,10 +1951,9 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC);
std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1959,10 +1965,9 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT);
std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, amount, canBeRecalculated);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, amount, canBeRecalculated);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1974,10 +1979,9 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC);
std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, isPeriodic, amplitude);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, isPeriodic, amplitude);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1989,10 +1993,9 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD);
std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, spellMod);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, spellMod);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2004,11 +2007,13 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
- defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
+ if (!defaultPrevented)
+ defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2020,10 +2025,9 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2035,10 +2039,9 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2050,10 +2053,9 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2065,26 +2067,27 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp);
std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, splitAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, splitAmount);
+
(*scritr)->_FinishScriptCall();
}
}
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, eventInfo))
- return false;
+ result &= hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+
+ return result;
}
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
@@ -2095,12 +2098,14 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin();
for (; effItr != effEndItr; ++effItr)
- (*effItr).Call(*scritr, eventInfo);
+ effItr->Call(*scritr, eventInfo);
+
+ if (prepare)
+ prepare = !(*scritr)->_IsDefaultActionPrevented();
- if (prepare && (*scritr)->_IsDefaultActionPrevented())
- prepare = false;
(*scritr)->_FinishScriptCall();
}
+
return prepare;
}
@@ -2111,7 +2116,8 @@ void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo&
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2123,7 +2129,8 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2136,12 +2143,12 @@ bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -2154,10 +2161,9 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 61e28a886ab..86d8f55c0ae 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3610,7 +3610,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
Creature* npc = unitTarget->ToCreature();
- npc->LoadEquipment(npc->GetEquipmentId());
+ npc->LoadEquipment();
return;
}
// Emblazon Runeblade
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index aadc30e3921..990b35d0862 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1188,6 +1188,12 @@ bool SpellInfo::IsMultiSlotAura() const
return IsPassive() || Id == 55849 || Id == 40075 || Id == 44413; // Power Spark, Fel Flak Fire, Incanter's Absorption
}
+bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
+{
+ /// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
+ return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
+}
+
bool SpellInfo::IsDeathPersistent() const
{
return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 7852c5c7270..ad344f0463d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -443,6 +443,7 @@ public:
bool IsStackableWithRanks() const;
bool IsPassiveStackableWithRanks() const;
bool IsMultiSlotAura() const;
+ bool IsStackableOnOneSlotWithDifferentCasters() const;
bool IsDeathPersistent() const;
bool IsRequiringDeadTarget() const;
bool IsAllowingDeadTarget() const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index b648a14fce5..8ec3d7d3731 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3354,6 +3354,17 @@ void SpellMgr::LoadSpellInfoCorrections()
case 64596: // Cosmic Smash (Algalon the Observer)
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
break;
+ case 64014: // Expedition Base Camp Teleport
+ case 64024: // Conservatory Teleport
+ case 64025: // Halls of Invention Teleport
+ case 64028: // Colossal Forge Teleport
+ case 64029: // Shattered Walkway Teleport
+ case 64030: // Antechamber Teleport
+ case 64031: // Scrapyard Teleport
+ case 64032: // Formation Grounds Teleport
+ case 65042: // Prison of Yogg-Saron Teleport
+ spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
+ break;
// ENDOF ULDUAR SPELLS
//
// TRIAL OF THE CRUSADER SPELLS
@@ -3447,7 +3458,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
- spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // another missing radius
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index ef1ee3ff08f..34a6ab35040 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -222,6 +222,9 @@ bool Weather::UpdateWeather()
char const* wthstr;
switch (state)
{
+ case WEATHER_STATE_FOG:
+ wthstr = "fog";
+ break;
case WEATHER_STATE_LIGHT_RAIN:
wthstr = "light rain";
break;
diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h
index 3286d550157..bde4280cb25 100644
--- a/src/server/game/Weather/Weather.h
+++ b/src/server/game/Weather/Weather.h
@@ -46,7 +46,7 @@ struct WeatherData
enum WeatherState
{
WEATHER_STATE_FINE = 0,
- WEATHER_STATE_UNK = 1, // Used in some instance encounters.
+ WEATHER_STATE_FOG = 1, // Used in some instance encounters.
WEATHER_STATE_LIGHT_RAIN = 3,
WEATHER_STATE_MEDIUM_RAIN = 4,
WEATHER_STATE_HEAVY_RAIN = 5,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4a1d1566af1..1a7f4b8c2a9 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -979,7 +979,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = ConfigMgr::GetIntDefault("ChatFlood.MessageDelay", 1);
m_int_configs[CONFIG_CHATFLOOD_MUTE_TIME] = ConfigMgr::GetIntDefault("ChatFlood.MuteTime", 10);
- m_int_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", 0);
+ m_bool_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", false);
m_float_configs[CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyFleeAssistanceRadius", 30.0f);
m_float_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyAssistanceRadius", 10.0f);
@@ -1445,12 +1445,12 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature Model Based Info Data...");
sObjectMgr->LoadCreatureModelInfo();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates...");
- sObjectMgr->LoadEquipmentTemplates();
-
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature templates...");
sObjectMgr->LoadCreatureTemplates();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates..."); // must be after LoadCreatureTemplates
+ sObjectMgr->LoadEquipmentTemplates();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature template addons...");
sObjectMgr->LoadCreatureTemplateAddons();
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 872a6c7afb3..e65eaf73983 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -174,6 +174,7 @@ enum WorldBoolConfigs
CONFIG_WINTERGRASP_ENABLE,
CONFIG_GUILD_LEVELING_ENABLED,
CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs?
+ CONFIG_EVENT_ANNOUNCE,
BOOL_CONFIG_VALUE_COUNT
};
@@ -265,7 +266,6 @@ enum WorldIntConfigs
CONFIG_CHATFLOOD_MESSAGE_COUNT,
CONFIG_CHATFLOOD_MESSAGE_DELAY,
CONFIG_CHATFLOOD_MUTE_TIME,
- CONFIG_EVENT_ANNOUNCE,
CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY,
CONFIG_CREATURE_FAMILY_FLEE_DELAY,
CONFIG_WORLD_BOSS_LEVEL_DIFF,
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 6653439b703..6987e958831 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -649,6 +649,7 @@ public:
handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), target->GetGUIDLow(), faction, npcflags, Entry, displayid, nativeid);
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
+ handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId());
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction());
handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str());
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 52721f9866d..4dcbf204388 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -495,10 +495,9 @@ public:
cInfo->questItems[5] = fields[78].GetUInt32();
cInfo->movementId = fields[79].GetUInt32();
cInfo->RegenHealth = fields[80].GetBool();
- cInfo->equipmentId = fields[81].GetUInt32();
- cInfo->MechanicImmuneMask = fields[82].GetUInt32();
- cInfo->flags_extra = fields[83].GetUInt32();
- cInfo->ScriptID = sObjectMgr->GetScriptId(fields[84].GetCString());
+ cInfo->MechanicImmuneMask = fields[81].GetUInt32();
+ cInfo->flags_extra = fields[82].GetUInt32();
+ cInfo->ScriptID = sObjectMgr->GetScriptId(fields[83].GetCString());
sObjectMgr->CheckCreatureTemplate(cInfo);
}
diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
index fa1ab5528ca..1303f5c4f58 100644
--- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
@@ -32,12 +32,20 @@ enum Say
SAY_LEASH = 1,
};
+enum Events
+{
+ EVENT_CLEAVE = 1,
+ EVENT_MORTAL_STRIKE = 2,
+ EVENT_BLAST_WAVE = 3,
+ EVENT_KNOCK_BACK = 4,
+};
+
enum Spells
{
SPELL_CLEAVE = 26350,
- SPELL_BLASTWAVE = 23331,
- SPELL_MORTALSTRIKE = 24573,
- SPELL_KNOCKBACK = 25778
+ SPELL_BLAST_WAVE = 23331,
+ SPELL_MORTAL_STRIKE = 24573,
+ SPELL_KNOCK_BACK = 25778
};
class boss_broodlord : public CreatureScript
@@ -54,17 +62,13 @@ public:
{
boss_broodlordAI(Creature* creature) : ScriptedAI(creature) {}
- uint32 Cleave_Timer;
- uint32 BlastWave_Timer;
- uint32 MortalStrike_Timer;
- uint32 KnockBack_Timer;
-
void Reset()
{
- Cleave_Timer = 8000; // These times are probably wrong
- BlastWave_Timer = 12000;
- MortalStrike_Timer = 20000;
- KnockBack_Timer = 30000;
+ // These timers are probably wrong
+ events.ScheduleEvent(EVENT_CLEAVE, 8000);
+ events.ScheduleEvent(EVENT_BLAST_WAVE, 12000);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000);
+ events.ScheduleEvent(EVENT_KNOCK_BACK, 30000);
}
void EnterCombat(Unit* /*who*/)
@@ -78,45 +82,51 @@ public:
if (!UpdateVictim())
return;
- //Cleave_Timer
- if (Cleave_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_CLEAVE);
- Cleave_Timer = 7000;
- } else Cleave_Timer -= diff;
-
- // BlastWave
- if (BlastWave_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_BLASTWAVE);
- BlastWave_Timer = urand(8000, 16000);
- } else BlastWave_Timer -= diff;
+ if (EnterEvadeIfOutOfCombatArea(diff))
+ Talk(SAY_LEASH);
- //MortalStrike_Timer
- if (MortalStrike_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_MORTALSTRIKE);
- MortalStrike_Timer = urand(25000, 35000);
- } else MortalStrike_Timer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (KnockBack_Timer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (Unit* target = me->getVictim())
+ switch (eventId)
{
- DoCast(target, SPELL_KNOCKBACK);
- // Drop 50% aggro
- if (DoGetThreat(target))
- DoModifyThreatPercent(target, -50);
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, 8000);
+ break;
+ case EVENT_MORTAL_STRIKE:
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000);
+ break;
+ case EVENT_BLAST_WAVE:
+ DoCastVictim(SPELL_BLAST_WAVE);
+ events.ScheduleEvent(EVENT_BLAST_WAVE, 12000);
+ break;
+ case EVENT_KNOCK_BACK:
+ if (Unit* target = me->getVictim())
+ {
+ DoCast(target, SPELL_BLAST_WAVE);
+ // Drop 50% of threat
+ if (DoGetThreat(target))
+ DoModifyThreatPercent(target, -50);
+ }
+ events.ScheduleEvent(EVENT_KNOCK_BACK, 30000);
+ break;
+ default:
+ break;
}
-
- KnockBack_Timer = urand(15000, 30000);
- } else KnockBack_Timer -= diff;
+ }
if (EnterEvadeIfOutOfCombatArea(diff))
Talk(SAY_LEASH);
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events; /// @todo: change BWL to instance script and bosses to BossAI
};
};
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
index 96293c635d6..14321873b0d 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp
@@ -102,10 +102,8 @@ public:
npc_unworthy_initiateAI(Creature* creature) : ScriptedAI(creature)
{
me->SetReactState(REACT_PASSIVE);
- if (!me->GetEquipmentId())
- if (const CreatureTemplate* info = sObjectMgr->GetCreatureTemplate(28406))
- if (info->equipmentId)
- const_cast<CreatureTemplate*>(me->GetCreatureTemplate())->equipmentId = info->equipmentId;
+ if (!me->GetCurrentEquipmentId())
+ me->SetCurrentEquipmentId(me->GetOriginalEquipmentId());
}
uint64 playerGUID;
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
index f508266434b..7e2515c42a7 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp
@@ -237,7 +237,7 @@ public:
case 2:
me->SetStandState(UNIT_STAND_STATE_STAND);
DoCast(me, SPELL_KOLTIRA_TRANSFORM);
- me->LoadEquipment(me->GetEquipmentId());
+ me->LoadEquipment();
break;
case 3:
SetEscortPaused(true);
diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
index 2169320621b..f27a5612a05 100644
--- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
+++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp
@@ -185,7 +185,7 @@ public:
++_summonDeaths;
if (_summonDeaths == 11) // All summons died
{
- SendWeather(WEATHER_STATE_UNK, 0.0f);
+ SendWeather(WEATHER_STATE_FOG, 0.0f);
me->RemoveAurasDueToSpell(SPELL_PTAH_EXPLOSION);
events.SetPhase(PHASE_NORMAL);
events.ScheduleEvent(EVENT_RAGING_SMASH, urand(7000, 12000), 0, PHASE_NORMAL);
diff --git a/src/server/scripts/Kalimdor/zone_desolace.cpp b/src/server/scripts/Kalimdor/zone_desolace.cpp
index f4c0eed481e..ab37f94ce40 100644
--- a/src/server/scripts/Kalimdor/zone_desolace.cpp
+++ b/src/server/scripts/Kalimdor/zone_desolace.cpp
@@ -107,7 +107,7 @@ public:
}
}
};
-
+
CreatureAI* GetAI(Creature* creature) const
{
return new npc_aged_dying_ancient_kodoAI(creature);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
index ab0c44aa6d0..4b1ccabe682 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
@@ -45,11 +45,13 @@ enum Spells
SPELL_SHROUD_OF_SORROW = 70986,
SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949,
SPELL_VAMPIRIC_BITE = 71726,
+ SPELL_VAMPIRIC_BITE_DUMMY = 71837,
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879,
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL = 70872,
SPELL_FRENZIED_BLOODTHIRST = 70877,
SPELL_UNCONTROLLABLE_FRENZY = 70923,
- SPELL_PRESENCE_OF_THE_DARKFALLEN = 71952,
+ SPELL_PRESENCE_OF_THE_DARKFALLEN = 70994,
+ SPELL_PRESENCE_OF_THE_DARKFALLEN_2 = 71952,
SPELL_BLOOD_MIRROR_DAMAGE = 70821,
SPELL_BLOOD_MIRROR_VISUAL = 71510,
SPELL_BLOOD_MIRROR_DUMMY = 70838,
@@ -88,6 +90,7 @@ uint32 const vampireAuras[3][MAX_DIFFICULTY] =
#define ESSENCE_OF_BLOOD_QUEEN_PLR RAID_MODE<uint32>(70879, 71525, 71530, 71531)
#define FRENZIED_BLOODTHIRST RAID_MODE<uint32>(70877, 71474, 70877, 71474)
#define DELIRIOUS_SLASH RAID_MODE<uint32>(71623, 71624, 71625, 71626)
+#define PRESENCE_OF_THE_DARKFALLEN RAID_MODE<uint32>(70994, 71962, 71963, 71964)
enum Events
{
@@ -220,6 +223,7 @@ class boss_blood_queen_lana_thel : public CreatureScript
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_DUMMY);
instance->DoRemoveAurasDueToSpellOnPlayers(DELIRIOUS_SLASH);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PACT_OF_THE_DARKFALLEN);
+ instance->DoRemoveAurasDueToSpellOnPlayers(PRESENCE_OF_THE_DARKFALLEN);
}
void DoAction(int32 const action)
@@ -357,8 +361,11 @@ class boss_blood_queen_lana_thel : public CreatureScript
{
Unit* target = targets.front();
DoCast(target, SPELL_VAMPIRIC_BITE);
+ DoCastAOE(SPELL_VAMPIRIC_BITE_DUMMY, true);
Talk(SAY_VAMPIRIC_BITE);
_vampires.insert(target->GetGUID());
+ target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK);
+ target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK);
}
break;
}
@@ -377,9 +384,10 @@ class boss_blood_queen_lana_thel : public CreatureScript
_offtank->CastSpell(me->getVictim(), SPELL_BLOOD_MIRROR_DAMAGE, true);
me->getVictim()->CastSpell(_offtank, SPELL_BLOOD_MIRROR_DUMMY, true);
DoCastVictim(SPELL_BLOOD_MIRROR_VISUAL);
- if (Item* shadowsEdge = _offtank->GetWeaponForAttack(BASE_ATTACK, true))
- if (!_offtank->HasAura(SPELL_THIRST_QUENCHED) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE && !_offtank->HasAura(SPELL_GUSHING_WOUND))
- _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, true);
+ if (Is25ManRaid() && _offtank->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE &&
+ _offtank->HasAura(SPELL_UNSATED_CRAVING) && !_offtank->HasAura(SPELL_THIRST_QUENCHED) &&
+ !_offtank->HasAura(SPELL_GUSHING_WOUND))
+ _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK);
}
}
@@ -396,13 +404,7 @@ class boss_blood_queen_lana_thel : public CreatureScript
{
std::list<Player*> targets;
SelectRandomTarget(false, &targets);
- uint32 targetCount = 2;
- // do not combine these checks! we want it incremented TWICE when both conditions are met
- if (IsHeroic())
- ++targetCount;
- if (Is25ManRaid())
- ++targetCount;
- Trinity::Containers::RandomResizeList<Player*>(targets, targetCount);
+ Trinity::Containers::RandomResizeList(targets, Is25ManRaid() ? 3 : 2);
if (targets.size() > 1)
{
Talk(SAY_PACT_OF_THE_DARKFALLEN);
@@ -554,33 +556,36 @@ class spell_blood_queen_vampiric_bite : public SpellScriptLoader
uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_FRENZIED_BLOODTHIRST, GetCaster());
GetCaster()->RemoveAura(spellId, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL);
- GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, true);
- // Presence of the Darkfallen buff on Blood-Queen
- if (GetCaster()->GetMap()->IsHeroic())
- GetCaster()->CastSpell(GetCaster(), SPELL_PRESENCE_OF_THE_DARKFALLEN, true);
+ GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, TRIGGERED_FULL_MASK);
+
// Shadowmourne questline
- if (GetCaster()->ToPlayer()->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE)
+ if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND))
{
- if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND))
+ if (aura->GetStackAmount() == 3)
{
- if (aura->GetStackAmount() == 3)
- {
- GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, true);
- GetCaster()->RemoveAura(aura);
- }
- else
- GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, true);
+ GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, TRIGGERED_FULL_MASK);
+ GetCaster()->RemoveAura(aura);
}
+ else
+ GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK);
}
+
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* bloodQueen = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL)))
bloodQueen->AI()->SetGUID(GetHitUnit()->GetGUID(), GUID_VAMPIRE);
}
+ void HandlePresence(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK);
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK);
+ }
+
void Register()
{
OnCheckCast += SpellCheckCastFn(spell_blood_queen_vampiric_bite_SpellScript::CheckTarget);
BeforeHit += SpellHitFn(spell_blood_queen_vampiric_bite_SpellScript::OnCast);
+ OnEffectHitTarget += SpellEffectFn(spell_blood_queen_vampiric_bite_SpellScript::HandlePresence, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
}
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index 1c6ed848158..5c7f575413a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -84,7 +84,9 @@ enum Spells
SPELL_CONCUSSIVE_SHOCK = 71337,
// Frost Infusion
- SPELL_FROST_INFUSION_CREDIT = 72289
+ SPELL_FROST_INFUSION_CREDIT = 72289,
+ SPELL_FROST_IMBUED_BLADE = 72290,
+ SPELL_FROST_INFUSION = 72292,
};
enum Events
@@ -147,11 +149,7 @@ enum MovementPoints
enum Shadowmourne
{
- QUEST_FROST_INFUSION = 24757,
- ITEM_SHADOW_S_EDGE = 49888,
-
- SPELL_FROST_INFUSION = 72292,
- SPELL_FROST_IMBUED_BLADE = 72290,
+ QUEST_FROST_INFUSION = 24757
};
Position const RimefangFlyPos = {4413.309f, 2456.421f, 233.3795f, 2.890186f};
@@ -390,47 +388,10 @@ class boss_sindragosa : public CreatureScript
void SpellHitTarget(Unit* target, SpellInfo const* spell)
{
if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(70127, me))
- {
if (spellId == spell->Id)
- {
if (Aura const* mysticBuffet = target->GetAura(spell->Id))
_mysticBuffetStack = std::max<uint8>(_mysticBuffetStack, mysticBuffet->GetStackAmount());
- return;
- }
- }
-
- // Frost Infusion
- if (Player* player = target->ToPlayer())
- {
- if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(_isThirdPhase ? SPELL_FROST_BREATH_P2 : SPELL_FROST_BREATH_P1, me))
- {
- if (spellId == spell->Id)
- {
- Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true);
- if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && shadowsEdge)
- {
- if (!player->HasAura(SPELL_FROST_IMBUED_BLADE) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE)
- {
- if (Aura* infusion = player->GetAura(SPELL_FROST_INFUSION))
- {
- if (infusion->GetStackAmount() == 3)
- {
- player->CastSpell(player, SPELL_FROST_IMBUED_BLADE, true);
- player->RemoveAura(infusion);
- }
- else
- player->CastSpell(player, SPELL_FROST_INFUSION, true);
- }
- else
- player->CastSpell(player, SPELL_FROST_INFUSION, true);
- }
- }
-
- return;
- }
- }
- }
}
void UpdateAI(uint32 const diff)
@@ -1155,6 +1116,50 @@ class spell_sindragosa_unchained_magic : public SpellScriptLoader
}
};
+class spell_sindragosa_frost_breath : public SpellScriptLoader
+{
+ public:
+ spell_sindragosa_frost_breath() : SpellScriptLoader("spell_sindragosa_frost_breath") { }
+
+ class spell_sindragosa_frost_breath_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sindragosa_frost_breath_SpellScript);
+
+ void HandleInfusion()
+ {
+ Player* target = GetHitPlayer();
+ if (!target)
+ return;
+
+ if (target->GetQuestStatus(QUEST_FROST_INFUSION) != QUEST_STATUS_INCOMPLETE)
+ return;
+
+ // Check if player has Shadow's Edge equipped and not ready for infusion
+ if (!target->HasAura(SPELL_UNSATED_CRAVING) || target->HasAura(SPELL_FROST_IMBUED_BLADE))
+ return;
+
+ Aura* infusion = target->GetAura(SPELL_FROST_INFUSION, target->GetGUID());
+ if (infusion && infusion->GetStackAmount() >= 3)
+ {
+ target->RemoveAura(infusion);
+ target->CastSpell(target, SPELL_FROST_IMBUED_BLADE, TRIGGERED_FULL_MASK);
+ }
+ else
+ target->CastSpell(target, SPELL_FROST_INFUSION, TRIGGERED_FULL_MASK);
+ }
+
+ void Register()
+ {
+ AfterHit += SpellHitFn(spell_sindragosa_frost_breath_SpellScript::HandleInfusion);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_sindragosa_frost_breath_SpellScript();
+ }
+};
+
class spell_sindragosa_instability : public SpellScriptLoader
{
public:
@@ -1577,6 +1582,7 @@ void AddSC_boss_sindragosa()
new npc_sindragosa_trash();
new spell_sindragosa_s_fury();
new spell_sindragosa_unchained_magic();
+ new spell_sindragosa_frost_breath();
new spell_sindragosa_instability();
new spell_sindragosa_frost_beacon();
new spell_sindragosa_ice_tomb();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index 1407568686f..887a31baf9a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -56,6 +56,7 @@ enum SharedSpells
SPELL_FROSTMOURNE_TELEPORT_VISUAL = 73078,
// Shadowmourne questline
+ SPELL_UNSATED_CRAVING = 71168,
SPELL_SHADOWS_FATE = 71169
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 462708360e3..593d9586156 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -435,7 +435,7 @@ class instance_icecrown_citadel : public InstanceMapScript
// these 2 gates are functional only on 25man modes
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01:
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04:
- if (instance->GetSpawnMode() & 1)
+ if (instance->Is25ManRaid())
AddDoor(go, true);
break;
case GO_LADY_DEATHWHISPER_ELEVATOR:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
index d3c174841ee..125f66497bf 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
@@ -565,10 +565,6 @@ class instance_ulduar : public InstanceMapScript
}
HandleGameObject(KologarnBridgeGUID, false);
}
- if (state == IN_PROGRESS)
- HandleGameObject(KologarnDoorGUID, false);
- else
- HandleGameObject(KologarnDoorGUID, true);
break;
case BOSS_HODIR:
if (state == DONE)
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
index 2c8d067a865..37bad9c4e4f 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
@@ -316,7 +316,7 @@ public:
me->SetDisplayId(MODEL_NIGHTELF);
// and reseting equipment
- me->LoadEquipment(me->GetEquipmentId());
+ me->LoadEquipment();
if (instance && instance->GetData64(DATA_LEOTHERAS_EVENT_STARTER))
{
@@ -410,7 +410,7 @@ public:
if (me->HasAura(AURA_BANISH))
return;
- me->LoadEquipment(me->GetEquipmentId());
+ me->LoadEquipment();
}
void UpdateAI(const uint32 diff)
@@ -558,7 +558,7 @@ public:
{
//switch to nightelf form
me->SetDisplayId(MODEL_NIGHTELF);
- me->LoadEquipment(me->GetEquipmentId());
+ me->LoadEquipment();
CastConsumingMadness();
DespawnDemon();
@@ -589,7 +589,7 @@ public:
Talk(SAY_FINAL_FORM);
me->SetDisplayId(MODEL_NIGHTELF);
- me->LoadEquipment(me->GetEquipmentId());
+ me->LoadEquipment();
}
}
};
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index d57ed6e126b..c9c75cdb134 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -813,53 +813,65 @@ class spell_item_scroll_of_recall : public SpellScriptLoader
enum ShadowsFate
{
SPELL_SOUL_FEAST = 71203,
- QUEST_A_FEAST_OF_SOULS = 24547
};
-class spell_item_shadows_fate : public SpellScriptLoader
+class spell_item_unsated_craving : public SpellScriptLoader
{
public:
- spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { }
+ spell_item_unsated_craving() : SpellScriptLoader("spell_item_unsated_craving") { }
- class spell_item_shadows_fate_AuraScript : public AuraScript
+ class spell_item_unsated_craving_AuraScript : public AuraScript
{
- PrepareAuraScript(spell_item_shadows_fate_AuraScript);
+ PrepareAuraScript(spell_item_unsated_craving_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/)
+ bool CheckProc(ProcEventInfo& procInfo)
{
- if (!sSpellMgr->GetSpellInfo(SPELL_SOUL_FEAST))
+ Unit* caster = procInfo.GetActor();
+ if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
return false;
- if (!sObjectMgr->GetQuestTemplate(QUEST_A_FEAST_OF_SOULS))
+
+ Unit* target = procInfo.GetActionTarget();
+ if (!target || target->GetTypeId() != TYPEID_UNIT || target->GetCreatureType() == CREATURE_TYPE_CRITTER || target->isSummon())
return false;
- return true;
- }
- bool Load()
- {
- _procTarget = NULL;
return true;
}
- bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ void Register()
{
- _procTarget = GetCaster();
- return _procTarget && _procTarget->GetTypeId() == TYPEID_PLAYER && _procTarget->ToPlayer()->GetQuestStatus(QUEST_A_FEAST_OF_SOULS) == QUEST_STATUS_INCOMPLETE;
+ DoCheckProc += AuraCheckProcFn(spell_item_unsated_craving_AuraScript::CheckProc);
}
+ };
- void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_unsated_craving_AuraScript();
+ }
+};
+
+class spell_item_shadows_fate : public SpellScriptLoader
+{
+ public:
+ spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { }
+
+ class spell_item_shadows_fate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shadows_fate_AuraScript);
+
+ void HandleProc(ProcEventInfo& procInfo)
{
- PreventDefaultAction();
- GetTarget()->CastSpell(_procTarget, SPELL_SOUL_FEAST, true);
+ Unit* caster = procInfo.GetActor();
+ Unit* target = GetCaster();
+ if (!caster || !target)
+ return;
+
+ caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK);
}
void Register()
{
- DoCheckProc += AuraCheckProcFn(spell_item_shadows_fate_AuraScript::CheckProc);
- OnEffectProc += AuraEffectProcFn(spell_item_shadows_fate_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ OnProc += AuraProcFn(spell_item_shadows_fate_AuraScript::HandleProc);
}
-
- private:
- Unit* _procTarget;
};
AuraScript* GetAuraScript() const
@@ -2481,6 +2493,7 @@ void AddSC_item_spell_scripts()
new spell_item_piccolo_of_the_flaming_fire();
new spell_item_savory_deviate_delight();
new spell_item_scroll_of_recall();
+ new spell_item_unsated_craving();
new spell_item_shadows_fate();
new spell_item_shadowmourne();
new spell_item_shadowmourne_soul_fragment();
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp
index 185ac647e33..8466e75bad2 100644
--- a/src/server/shared/Database/Implementation/WorldDatabase.cpp
+++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp
@@ -78,7 +78,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_INS_CREATURE_TRANSPORT, "INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_UPD_CREATURE_TRANSPORT_EMOTE, "UPDATE creature_transport SET emote = ? WHERE transport_entry = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, security, help FROM command", CONNECTION_SYNCH);
- PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH);
+ PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH);
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 35d37d97f79..96ad754a007 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1028,7 +1028,7 @@ Event.Announce = 0
#
# BeepAtStart
-# Description: Beep when the world server finished starting (Unix/Linux systems).
+# Description: Beep when the world server finished starting.
# Default: 1 - (Enabled)
# 0 - (Disabled)
@@ -1094,6 +1094,14 @@ DBC.EnforceItemAttributes = 1
AccountInstancesPerHour = 5
#
+# RBAC.DefaultGroups
+# Description: Comma separated list of groups to be added to any account
+# Check auth.rbac_groups for correct ids
+# Default: "" (No group)
+
+RBAC.DefaultGroups = ""
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 671de25dfd3..09f23b844cf 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -12,4 +12,6 @@ add_subdirectory(map_extractor)
add_subdirectory(vmap4_assembler)
add_subdirectory(vmap4_extractor)
add_subdirectory(mmaps_generator)
-# add_subdirectory(mesh_extractor)
+#if (WITH_MESHEXTRACTOR)
+# add_subdirectory(mesh_extractor)
+#endif()