diff options
77 files changed, 2184 insertions, 1482 deletions
diff --git a/sql/updates/world/3.3.5/2016_08_21_00_world.sql b/sql/updates/world/3.3.5/2016_08_21_00_world.sql new file mode 100644 index 00000000000..6a6e7a9a22c --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_00_world.sql @@ -0,0 +1,20 @@ +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|4 WHERE `entry`=34045; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|1536 WHERE `entry`=21574; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|16384 WHERE `entry` IN (32104,37425,31990,37309); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|65536 WHERE `entry`=20175; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|13108096 WHERE `entry`=19886; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|71970058 WHERE `entry`=30600; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|80358666 WHERE `entry` IN (37243,37244); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|268435456 WHERE `entry` IN (38973,38974,38975,38970,38971,38972,38233,38459,38460); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|277165934 WHERE `entry`=32796; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|344276858 WHERE `entry` IN (35427,35410); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|541800015 WHERE `entry` IN (39299,39300,39301); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|617299835 WHERE `entry` IN (38483,37341,37363,33911,33910); + +UPDATE `creature_template` SET `unit_flags2`=`unit_flags2`|32 WHERE `entry`=30794; + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|2 WHERE `entry` IN (37628,30808,25546,25543,30769,30758,30768,30776,30813,30812,30811,30800,30792,30796,30801,30797,30799,31997,37316,31995,37314,21620,20665,19901,31979,37298,32092,37413,32003,37322,32032,37352,32137,37465,37484,37483,37480,32044,37365,32056,37377,37320,32112,37433,37315,37482,37481,37479,37323,37236,37305,37420,37301,37416,37399,37485,37809,37348,37427,37344,37349,37242,37373,34140,37318,34256,34257,34254,33191,37486); + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|64 WHERE `entry` IN (31585,31183,31635); +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128 WHERE `entry` IN (25558,25557); diff --git a/sql/updates/world/3.3.5/2016_08_21_01_world.sql b/sql/updates/world/3.3.5/2016_08_21_01_world.sql new file mode 100644 index 00000000000..37ce1e9809f --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_01_world.sql @@ -0,0 +1,3 @@ +-- +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|2 WHERE `entry`=30808; +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|4 WHERE `entry` IN (33911,33910); diff --git a/sql/updates/world/3.3.5/2016_08_21_02_world.sql b/sql/updates/world/3.3.5/2016_08_21_02_world.sql new file mode 100644 index 00000000000..9ae243c4db1 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_02_world.sql @@ -0,0 +1,3 @@ +-- +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|2 WHERE `entry`=27339; +UPDATE `gameobject_addon` SET `parent_rotation0`=0, `parent_rotation1`=0, `parent_rotation2`=0.333807, `parent_rotation3`=0.9426414 WHERE `guid`=57849; diff --git a/sql/updates/world/3.3.5/2016_08_21_03_world.sql b/sql/updates/world/3.3.5/2016_08_21_03_world.sql new file mode 100644 index 00000000000..c8b1f0f1c2e --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_03_world.sql @@ -0,0 +1,6 @@ +-- +DELETE FROM `spell_ranks` WHERE `first_spell_id` = 34453 AND `rank` IN (1,2); +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|2 WHERE `entry` IN (32117,37440,32113,37436,32116,37439,32115,37438,32114,37437,32118,37441); +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128 WHERE `entry` IN (22582); +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|130 WHERE `entry` IN (30780,30782,30784,30786); +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|80358666 WHERE `entry` IN (37283,37444); diff --git a/sql/updates/world/3.3.5/2016_08_21_04_world.sql b/sql/updates/world/3.3.5/2016_08_21_04_world.sql new file mode 100644 index 00000000000..7d7fbd23005 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_04_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `gameobject` SET `spawntimesecs` = 2 WHERE `id` = 188489; diff --git a/sql/updates/world/3.3.5/2016_08_21_05_world.sql b/sql/updates/world/3.3.5/2016_08_21_05_world.sql new file mode 100644 index 00000000000..e7327102a1f --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_05_world.sql @@ -0,0 +1,11 @@ +-- +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry` IN (25686,25684,25699,25701); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (25686,25701,25684,25699) AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +-- DB/Creature: Add missing SAI Gorloc Gibberer and Gorloc Dredger +(25686, 0, 0, 0, 0, 0, 100, 0, 0, 4000, 4000, 6000, 11, 50520, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gorloc Gibberer - In Combat - Cast \'Deep Dredge\''), +(25701, 0, 0, 0, 0, 0, 100, 0, 0, 4000, 4000, 6000, 11, 50520, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Gorloc Dredger - In Combat - Cast \'Deep Dredge\''), +-- DB/Creature: Add missing SAI Talramas Abomination +(25684, 0, 0, 0, 0, 0, 100, 0, 0, 2000, 20000, 20000, 11, 50366, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Talramas Abomination - In Combat - Cast \'Plague Cloud\''), +-- DB/Creature: Add missing SAI Gorloc Mud Splasher +(25699, 0, 0, 0, 0, 0, 100, 0, 0, 2000, 12000, 20000, 11, 50522, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Gorloc Mud Splasher - In Combat - Cast \'Gorloc Stomp\''); diff --git a/sql/updates/world/3.3.5/2016_08_21_06_world.sql b/sql/updates/world/3.3.5/2016_08_21_06_world.sql new file mode 100644 index 00000000000..22fce10b220 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_06_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `gossip_menu_option` SET `option_text`='I require training', `OptionBroadcastTextID` =6503 WHERE `menu_id`=4762 AND `id`=0; diff --git a/sql/updates/world/3.3.5/2016_08_21_07_world.sql b/sql/updates/world/3.3.5/2016_08_21_07_world.sql new file mode 100644 index 00000000000..62d1963db90 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_21_07_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=8388672 WHERE `entry`=23777; diff --git a/sql/updates/world/3.3.5/2016_08_22_00_world.sql b/sql/updates/world/3.3.5/2016_08_22_00_world.sql new file mode 100644 index 00000000000..3b741e03565 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_22_00_world.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `conditions` WHERE `SourceEntry`=42793 AND `SourceTypeOrReferenceId`=13; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 42793, 0, 0, 31, 0, 3, 24009, 0, 0, 0, 0, "", "Spell Burn Body targets Alliance Corpse"), +(13, 1, 42793, 0, 1, 31, 0, 3, 24010, 0, 0, 0, 0, "", "Spell Burn Body targets Forsaken Corpse"); diff --git a/sql/updates/world/3.3.5/2016_08_23_00_world.sql b/sql/updates/world/3.3.5/2016_08_23_00_world.sql new file mode 100644 index 00000000000..22a4ef95f4e --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_00_world.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN(17) AND `SourceEntry`=13982; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17,0,13982,0,0,29,0,9016,10,1,0,0,0,'',"Spell 'Bael'Gar's Fiery Essence' requires Bael'Gar's corpse"); diff --git a/sql/updates/world/3.3.5/2016_08_23_01_world.sql b/sql/updates/world/3.3.5/2016_08_23_01_world.sql new file mode 100644 index 00000000000..0c266a2e88f --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_01_world.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=39246 AND `ConditionTypeOrReference`=36; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=17 AND `SourceEntry`=39246; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17,0,39246,0,0,29,0,22105,10,1,0,11,0,'',"Spell 'Fumping' requires dead Decrepit Clefthoof"); diff --git a/sql/updates/world/3.3.5/2016_08_23_02_world.sql b/sql/updates/world/3.3.5/2016_08_23_02_world.sql new file mode 100644 index 00000000000..144a4aa4377 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_02_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `conditions` SET `ConditionValue2`=33844 WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=62709 AND `ElseGroup`=0; diff --git a/sql/updates/world/3.3.5/2016_08_23_03_world.sql b/sql/updates/world/3.3.5/2016_08_23_03_world.sql new file mode 100644 index 00000000000..727544cd88c --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_03_world.sql @@ -0,0 +1,5 @@ +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=66512; +DELETE FROM `spell_script_names` WHERE `ScriptName` IN('spell_q14076_14092_pound_drum','spell_q12279_cast_net'); +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(66512,'spell_q14076_14092_pound_drum'), +(48794,'spell_q12279_cast_net'); diff --git a/sql/updates/world/3.3.5/2016_08_23_04_world.sql b/sql/updates/world/3.3.5/2016_08_23_04_world.sql new file mode 100644 index 00000000000..d7697d28ad7 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_04_world.sql @@ -0,0 +1,10 @@ +-- NPC ID / entry 35646 Wormhole (summoned by item 48933 Wormhole Generator: Northrend) + +DELETE FROM `gossip_menu_option` WHERE `menu_id`= 10668; +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`OptionBroadcastTextID`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`,`BoxBroadcastTextID`,`VerifiedBuild`) VALUES +(10668, 0, 0, 'Borean Tundra', 35939, 1, 1, 0, 0, 0, 0, '', 0, 0), +(10668, 1, 0, 'Howling Fjord', 35943, 1, 1, 0, 0, 0, 0, '', 0, 0), +(10668, 2, 0, 'Sholazar Basin', 35940, 1, 1, 0, 0, 0, 0, '', 0, 0), +(10668, 3, 0, 'Icecrown', 35941, 1, 1, 0, 0, 0, 0, '', 0, 0), +(10668, 4, 0, 'Storm Peaks', 35942, 1, 1, 0, 0, 0, 0, '', 0, 0), +(10668, 5, 0, 'Underground...', 36022, 1, 1, 0, 0, 0, 0, '', 0, 0); diff --git a/sql/updates/world/3.3.5/2016_08_23_05_world.sql b/sql/updates/world/3.3.5/2016_08_23_05_world.sql new file mode 100644 index 00000000000..cab7e8f3a20 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_23_05_world.sql @@ -0,0 +1,63 @@ +-- +DELETE FROM `spell_script_names` WHERE `ScriptName`="spell_brewfest_relay_race_turn_in"; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(43755, "spell_brewfest_relay_race_turn_in"); + +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=-43880; +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +(-43880, -43332, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Exhausted'"), +(-43880, -43310, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Ram Level - Neutral'"), +(-43880, -43052, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Ram Fatigue'"), +(-43880, -42994, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Ram - Gallop'"), +(-43880, -42993, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Ram - Canter'"), +(-43880, -42992, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Ram - Trot'"), +(-43880, -42146, 0, "On removal of aura 'Ramsteins Swift Work Ram' also remove aura 'Brewfest Racing Ram Aura [DND]'"); + +DELETE FROM `gossip_menu_option` WHERE `id`=4 AND `menu_id` IN (8934, 8976); +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES +(8934, 4, 0, "I want to race for tokens!", 0, 1, 1, 0, 0, 0, 0, "", 0, -1), +(8976, 4, 0, "I want to race for tokens!", 0, 1, 1, 0, 0, 0, 0, "", 0, -1); + +UPDATE `smart_scripts` SET `link`=2 WHERE `id`=1 AND `entryorguid` IN (24468, 24510); +DELETE FROM `smart_scripts` WHERE `id`=2 AND `entryorguid` IN (24468, 24510); +DELETE FROM `smart_scripts` WHERE `entryorguid`=23558 AND `id` IN (6, 7, 8, 9); +DELETE FROM `smart_scripts` WHERE `entryorguid`=24497 AND `id` IN (8, 9, 10, 11); +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 +(24468, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 43755, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Pol Amberstill <Ram Racing Apprentice> - Within 0-25 Range - Cast 'Brewfest - Daily - Relay Race - Player - Increase Mount Duration - DND'"), +(24510, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 43755, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Driz Tumblequick <Ram Racing Apprentice> - Within 0-25 Range - Cast 'Brewfest - Daily - Relay Race - Player - Increase Mount Duration - DND'"), +(23558, 0, 6, 7, 62, 0, 100, 0, 8934, 4, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Neill Ramstein <Ram Racing Master> - On Gossip Option 4 Selected - Close Gossip"), +(23558, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 85, 43880, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Neill Ramstein <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Ramstein's Swift Work Ram'"), +(23558, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 85, 44689, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Neill Ramstein <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Relay Race Accept Hidden Debuff - DND'"), +(23558, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 44262, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Neill Ramstein <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Brewfest - Create Ram Racing Crop'"), +(24497, 0, 8, 9, 62, 0, 100, 0, 8976, 4, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Ram Master Ray <Ram Racing Master> - On Gossip Option 4 Selected - Close Gossip"), +(24497, 0, 9, 10, 61, 0, 100, 0, 0, 0, 0, 0, 85, 43880, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Ram Master Ray <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Ramstein's Swift Work Ram'"), +(24497, 0, 10, 11, 61, 0, 100, 0, 0, 0, 0, 0, 85, 44689, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Ram Master Ray <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Relay Race Accept Hidden Debuff - DND'"), +(24497, 0, 11, 0, 61, 0, 100, 0, 0, 0, 0, 0, 85, 44262, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, "Ram Master Ray <Ram Racing Master> - On Gossip Option 4 Selected - Cast Spell 'Brewfest - Create Ram Racing Crop'"); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup` IN (8934, 8976) AND `SourceEntry`=4; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 8934, 4, 0, 0, 8, 0, 11122, 0, 0, 0, 0, 0, "", "Brewfest Relay Race - Show gossip if player has turned in the quest 'There and Back Again'"), +(15, 8934, 4, 0, 0, 1, 0, 44689, 0, 0, 1, 0, 0, "", "Brewfest Relay Race - Show gossip if player does not have aura 'Relay Race Accept Hidden Debuff - DND'"), +(15, 8934, 4, 0, 0, 1, 0, 43883, 0, 0, 1, 0, 0, "", "Brewfest Relay Race - Show gossip if player does not have aura 'Rental Racing Ram'"), +(15, 8976, 4, 0, 0, 8, 0, 11412, 0, 0, 0, 0, 0, "", "Brewfest Relay Race - Show gossip if player has turned in the quest 'There and Back Again'"), +(15, 8976, 4, 0, 0, 1, 0, 44689, 0, 0, 1, 0, 0, "", "Brewfest Relay Race - Show gossip if player does not have aura 'Relay Race Accept Hidden Debuff - DND'"), +(15, 8976, 4, 0, 0, 1, 0, 43883, 0, 0, 1, 0, 0, "", "Brewfest Relay Race - Show gossip if player does not have aura 'Rental Racing Ram'"); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry` IN (24468, 24510, 24364, 24527) AND `ElseGroup`=1; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry` IN (24468, 24510) AND `SourceGroup`=3; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(22, 1, 24468, 0, 1, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramsteins Swift Work Ram'"), +(22, 1, 24468, 0, 1, 2, 0, 33797, 1, 0, 0, 0, 0, "", "SAI triggers only if player has item 'Portable Brewfest Keg'"), +(22, 1, 24510, 0, 1, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramsteins Swift Work Ram'"), +(22, 1, 24510, 0, 1, 2, 0, 33797, 1, 0, 0, 0, 0, "", "SAI triggers only if player has item 'Portable Brewfest Keg'"), +(22, 1, 24364, 0, 1, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramsteins Swift Work Ram'"), +(22, 1, 24364, 0, 1, 2, 0, 33797, 1, 0, 1, 0, 0, "", "SAI triggers only if player does not have item 'Portable Brewfest Keg'"), +(22, 1, 24527, 0, 1, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramsteins Swift Work Ram'"), +(22, 1, 24527, 0, 1, 2, 0, 33797, 1, 0, 1, 0, 0, "", "SAI triggers only if player does not have item 'Portable Brewfest Keg'"), +(22, 3, 24468, 0, 0, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramsteins Swift Work Ram'"), +(22, 3, 24510, 0, 0, 1, 0, 43880, 0, 0, 0, 0, 0, "", "SAI triggers only if player has aura 'Ramstein's Swift Work Ram'"); + +-- Update wrong comments +UPDATE `conditions` SET `Comment`="SAI triggers only if player has aura 'Rental Racing Ram'" WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=24510 AND `ConditionTypeOrReference`=1 AND `ConditionValue1`=43883; +UPDATE `conditions` SET `Comment`="SAI triggers only if player has item 'Portable Brewfest Keg'" WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=24510 AND `ConditionTypeOrReference`=2; +UPDATE `smart_scripts` SET `Comment`="Driz Tumblequick <Ram Racing Apprentice> - Within 0-25 Range - Cast 'Brewfest - Throw Keg - DND'" WHERE `entryorguid`=24510 AND `id`=0; diff --git a/sql/updates/world/3.3.5/2016_08_24_00_world.sql b/sql/updates/world/3.3.5/2016_08_24_00_world.sql new file mode 100644 index 00000000000..db20add8d90 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_00_world.sql @@ -0,0 +1,33 @@ +-- +DELETE FROM `conditions` WHERE `SourceEntry`=43189 AND `SourceTypeOrReferenceId`=17; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 43189, 0, 0, 29, 0, 24173, 100, 0, 1, 0, 0, "", "Spell 'Test Horn' cannot be cast if NPC 'Frostgore' is nearby"), +(17, 0, 43189, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, "", "Spell 'Test Horn' cannot be cast if nearby NPC 'Frostgore' is alive"); + +UPDATE `event_scripts` SET `x`=2932.631, `y`=-4488.105, `z`=285.6876, `o`=3.298672 WHERE `id`=15726; + +DELETE FROM `waypoints` WHERE `entry`=24173; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(24173, 1, 2918.373, -4505.415, 280.0419, ""), +(24173, 2, 2920.935, -4521.924, 276.0025, ""), +(24173, 3, 2923.956, -4535.499, 274.4535, ""), +(24173, 4, 2944.427, -4555.303, 273.6897, ""); + +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=24173; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (24173, 2417300); +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 +(24173, 0, 0, 0, 0, 0, 100, 0, 5000, 10000, 10000, 20000, 11, 52058, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, "Frostgore - In Combat - Cast 'Ground Slam'"), +(24173, 0, 1, 2, 11, 0, 100, 0, 0, 0, 0, 0, 18, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Spawn - Add UNIT_FLAG_IMMUNE_TO_PC"), +(24173, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 53, 1, 24173, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Spawn - Start Waypoint"), +(24173, 0, 3, 0, 40, 0, 100, 0, 4, 0, 0, 0, 80, 2417300, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On WP 4 Reached - Start Script"), +(2417300, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Set home position to summoner's position"), +(2417300, 9, 1, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 66, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Turn to summoner"), +(2417300, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Say Text 0"), +(2417300, 9, 3, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Say Text 1"), +(2417300, 9, 4, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 19, 256, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Remove UNIT_FLAG_IMMUNE_TO_PC"), +(2417300, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, "Frostgore - On Script - Attack summoner"); + +DELETE FROM `creature_text` WHERE `entry`=24173; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(24173, 0, 0, (SELECT MaleText FROM broadcast_text WHERE ID = 22876), 12, 0, 100, 1, 0, 0, 22876, 0, "Frostgore"), +(24173, 1, 0, (SELECT MaleText FROM broadcast_text WHERE ID = 22877), 12, 0, 100, 25, 0, 0, 22877, 0, "Frostgore"); diff --git a/sql/updates/world/3.3.5/2016_08_24_01_world.sql b/sql/updates/world/3.3.5/2016_08_24_01_world.sql new file mode 100644 index 00000000000..65efdb08659 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_01_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `smart_scripts` SET `target_type`=27 WHERE `entryorguid`=30423 AND `id`=1; diff --git a/sql/updates/world/3.3.5/2016_08_24_02_world.sql b/sql/updates/world/3.3.5/2016_08_24_02_world.sql new file mode 100644 index 00000000000..e1407e23780 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_02_world.sql @@ -0,0 +1,2 @@ +-- fix random incorrect unit flag on dragonkin type +UPDATE `creature_template` SET `unit_flags`=(`unit_flags`&~(0x100|0x200|0x2000000)) WHERE `entry`=31403; diff --git a/sql/updates/world/3.3.5/2016_08_24_03_world.sql b/sql/updates/world/3.3.5/2016_08_24_03_world.sql new file mode 100644 index 00000000000..68b4d9274ec --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_03_world.sql @@ -0,0 +1,2 @@ +-- Scarlet Mine Car must have UNIT_FIELD_FLAGS UNIT_FLAG_IMMUNE_TO_PC +UPDATE `creature_template` SET `unit_flags`= `unit_flags`| 520 WHERE `entry`= 28817; diff --git a/sql/updates/world/3.3.5/2016_08_24_04_world.sql b/sql/updates/world/3.3.5/2016_08_24_04_world.sql new file mode 100644 index 00000000000..5076e7f521d --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_04_world.sql @@ -0,0 +1,7 @@ +-- fix sons of hodir reputation amounts to correspond to 3.3.5 retail +UPDATE `quest_template` SET `RewardFactionOverride1`=65000 WHERE `id` IN (13559,13108,13003); -- Hodir's Tribute awards 650 rep per turn-in; Whatever it Takes! and Thrusing Hodir's Spear also award 650 rep +UPDATE `quest_template` SET `RewardFactionOverride1`=2860000 WHERE `id` IN (12915,12924); -- Mending Fences and A Spark of Hope award 28600 rep +UPDATE `quest_template` SET `RewardFactionOverride1`=32500 WHERE `id` IN (12924,13011,12975,12985,13001); -- Forging an Alliance, Jormuttar is Soo Fat..., In Memoriam, Forging a Head, Raising Hodir's Spear reward 325 rep each +UPDATE `quest_template` SET `RewardFactionOverride1`=45500 WHERE `id` IN (12981,12977,13010,13420,13421,13006,12994,13046); -- Hot and Cold, Blowing Hodir's Horn, 'Krolmir, Hammer of Storms', Everfrost, Remember Everfrost!, Polishing the Helm, Spy Hunter, Feeding Arngrim each award 455 reputation +UPDATE `quest_template` SET `RewardFactionOverride1`=32500 WHERE `id` = 12987; -- Mounting Hodir's Helm awards 325 rep +UPDATE `quest_template` SET `RewardFactionOverride1`=97 WHERE `id` = 12976; -- A Monument to the Fallen awards 97 rep diff --git a/sql/updates/world/3.3.5/2016_08_24_05_world.sql b/sql/updates/world/3.3.5/2016_08_24_05_world.sql new file mode 100644 index 00000000000..34b2dc925a3 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_05_world.sql @@ -0,0 +1,2 @@ +-- fix typo in previous update. nobody saw that! +UPDATE `quest_template` SET `RewardFactionOverride1`=9700 WHERE `id` = 12976; -- A Monument to the Fallen awards 97 rep diff --git a/sql/updates/world/3.3.5/2016_08_24_06_world.sql b/sql/updates/world/3.3.5/2016_08_24_06_world.sql new file mode 100644 index 00000000000..7df954dec3b --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_06_world.sql @@ -0,0 +1,5 @@ +-- +UPDATE `quest_template` SET `RewardFactionID1`=67 WHERE `ID`=5237; +UPDATE `quest_template` SET `RewardFactionID1`=469 WHERE `ID`=5238; + +UPDATE `quest_offer_reward` SET `RewardText`="$N, your successful re-engineering of the cauldrons is a tremendous victory for us!$B$B<The high executor clears his throat and begins to bellow loudly.>$B$BLet all within my presence hear: for service to the Forsaken and to the Horde as a whole above and beyond what was expected - in the face of overwhelming odds and incredible danger, might I add - I give $N this, and I extend upon $Ghim:her; our undying gratitude as a true hero of the Horde. Huzzah!" WHERE `ID`=5237; diff --git a/sql/updates/world/3.3.5/2016_08_24_07_world.sql b/sql/updates/world/3.3.5/2016_08_24_07_world.sql new file mode 100644 index 00000000000..2c1c2941dc2 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_07_world.sql @@ -0,0 +1,6 @@ +-- move sons of hodir reputation changes to reputation_reward_rate table +-- also add multipliers to Argent Crusade, Alliance Vanguard, Horde Expedition, Kirin Tor, Knights of the Ebon Blade and Wyrmrest Accord as per 3.3.0 retail patch notes +UPDATE `quest_template` SET `RewardFactionOverride1`=0 WHERE `RewardFactionID1`=1119; +UPDATE `quest_template` SET `RewardFactionOverride1`=2200000 WHERE `id` IN (12915,12924); +INSERT INTO `reputation_reward_rate` (`faction`) VALUES (1106),(1037),(1052),(1091),(1090),(1098) ON DUPLICATE KEY UPDATE `faction`=`faction`; +UPDATE `reputation_reward_rate` SET `quest_rate`=1.3,`quest_daily_rate`=1.3,`quest_weekly_rate`=1.3,`quest_monthly_rate`=1.3,`quest_repeatable_rate`=1.3 WHERE `faction` IN (1106,1037,1052,1091,1090,1098); diff --git a/sql/updates/world/3.3.5/2016_08_24_08_world.sql b/sql/updates/world/3.3.5/2016_08_24_08_world.sql new file mode 100644 index 00000000000..45b28c4d1d6 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_08_world.sql @@ -0,0 +1,190 @@ +-- !!!!!!!!!!!!!!!!!!!!!!!!!!! -- +-- KEL'THUZAD ENCOUNTER REWORK -- +-- !!!!!!!!!!!!!!!!!!!!!!!!!!! -- + + +-- =============== -- +-- Difficulty data -- +-- =============== -- +DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (28478,28479,28457,28459); +INSERT INTO `spelldifficulty_dbc` (`id`,`spellid0`,`spellid1`) VALUES +(28478,28478,55802), +(28479,28479,55807), +(28457,28457,55714), +(28459,28459,55765); + +-- ======================================================================== -- +-- Summon groups: -- +-- groups 1 to 4 are the 4 guardian of icecrown spawns for P3 -- +-- groups 5 to 11 are the spawn groups for each of the minion pockets in P1 -- +-- ======================================================================== -- +DELETE FROM `creature_summon_groups` WHERE `summonerId`=15990; +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES +(15990,0, 1,16441,3700.7,-5182.372,144.0006,3.525565,5,0), +(15990,0, 2,16441,3759.62,-5172.79,143.835,2.275546,5,0), +(15990,0, 3,16441,3777.213,-5066.177,143.7245,3.854439,5,0), +(15990,0, 4,16441,3732.598,-5028.03,144.1175,5.951573,5,0), +(15990,0, 5,23561,3767.448,-5085.221,143.3204,1.099557,6,2500), +(15990,0, 5,23561,3763.589,-5077.779,143.2613,3.263766,6,2500), +(15990,0, 5,23561,3778.311,-5070.924,143.6698,0.383972,6,2500), +(15990,0, 5,23561,3777.016,-5076.336,143.6931,2.443461,6,2500), +(15990,0, 5,23561,3768.994,-5072.449,143.2920,1.221730,6,2500), +(15990,0, 5,23561,3765.200,-5066.542,143.5911,5.969026,6,2500), +(15990,0, 5,23561,3760.120,-5071.032,143.2545,4.049164,6,2500), +(15990,0, 5,23561,3772.377,-5065.624,143.5756,3.595378,6,2500), +(15990,0, 5,23561,3769.112,-5080.867,143.4122,3.473205,6,2500), +(15990,0, 5,23561,3777.380,-5061.792,143.7722,3.246312,6,2500), +(15990,0, 5,23562,3760.199,-5065.446,143.6439,1.762783,6,2500), +(15990,0, 5,23562,3770.308,-5079.318,143.4988,0.261799,6,2500), +(15990,0, 5,23562,3768.820,-5068.979,143.4071,1.518436,6,2500), +(15990,0, 5,23563,3769.489,-5073.855,143.3546,5.253441,6,2500), +(15990,0, 6,23561,3737.419,-5052.975,143.7604,1.169371,6,2500), +(15990,0, 6,23561,3727.097,-5048.372,143.4038,3.857178,6,2500), +(15990,0, 6,23561,3737.439,-5041.781,143.7740,3.857178,6,2500), +(15990,0, 6,23561,3732.787,-5045.659,143.5814,1.937315,6,2500), +(15990,0, 6,23561,3721.843,-5044.510,143.6988,2.827433,6,2500), +(15990,0, 6,23561,3728.000,-5031.103,143.8964,0.750492,6,2500), +(15990,0, 6,23561,3732.647,-5051.030,143.5529,3.246312,6,2500), +(15990,0, 6,23561,3733.721,-5032.996,143.8625,6.021386,6,2500), +(15990,0, 6,23561,3728.706,-5043.684,143.4527,1.483530,6,2500), +(15990,0, 6,23561,3725.062,-5036.629,143.7767,3.874631,6,2500), +(15990,0, 6,23562,3729.237,-5039.866,143.5873,4.607669,6,2500), +(15990,0, 6,23562,3718.425,-5046.168,143.7998,5.480334,6,2500), +(15990,0, 6,23562,3735.658,-5045.499,143.7014,3.595378,6,2500), +(15990,0, 6,23563,3730.488,-5043.493,143.4955,0.541052,6,2500), +(15990,0, 7,23561,3681.355,-5048.864,143.5021,6.195919,6,2500), +(15990,0, 7,23561,3681.005,-5062.944,143.2552,5.131268,6,2500), +(15990,0, 7,23561,3678.148,-5062.077,143.3822,0.663225,6,2500), +(15990,0, 7,23561,3679.336,-5055.365,143.3906,4.118977,6,2500), +(15990,0, 7,23561,3687.639,-5053.579,143.3244,4.736891,6,2500), +(15990,0, 7,23561,3686.921,-5045.933,143.7372,2.373648,6,2500), +(15990,0, 7,23561,3683.435,-5059.344,143.2643,3.979351,6,2500), +(15990,0, 7,23561,3673.546,-5053.107,143.6368,3.595378,6,2500), +(15990,0, 7,23561,3682.695,-5052.478,143.3708,4.293510,6,2500), +(15990,0, 7,23561,3689.501,-5058.241,143.2562,2.251475,6,2500), +(15990,0, 7,23562,3691.315,-5055.122,143.3179,0.191986,6,2500), +(15990,0, 7,23562,3676.070,-5064.142,143.5163,2.548181,6,2500), +(15990,0, 7,23562,3682.844,-5058.052,143.2656,5.393067,6,2500), +(15990,0, 7,23563,3683.868,-5047.447,143.5984,3.176499,6,2500), +(15990,0, 8,23561,3645.270,-5095.199,143.5504,5.044002,6,2500), +(15990,0, 8,23561,3649.625,-5084.568,143.7628,5.899213,6,2500), +(15990,0, 8,23561,3653.785,-5104.293,143.8255,0.314159,6,2500), +(15990,0, 8,23561,3652.523,-5094.354,143.4423,5.270895,6,2500), +(15990,0, 8,23561,3660.487,-5089.280,143.6040,3.071779,6,2500), +(15990,0, 8,23561,3657.886,-5092.163,143.4859,5.201081,6,2500), +(15990,0, 8,23561,3652.059,-5098.256,143.6083,0.488692,6,2500), +(15990,0, 8,23561,3654.281,-5085.585,143.7745,3.787364,6,2500), +(15990,0, 8,23561,3659.438,-5098.578,143.4740,0.890118,6,2500), +(15990,0, 8,23561,3648.554,-5088.838,143.5358,2.914700,6,2500), +(15990,0, 8,23562,3655.752,-5101.823,143.6867,1.500983,6,2500), +(15990,0, 8,23562,3660.398,-5085.446,143.7791,0.959931,6,2500), +(15990,0, 8,23562,3653.763,-5092.355,143.4888,1.832596,6,2500), +(15990,0, 8,23563,3648.262,-5095.589,143.5233,2.356194,6,2500), +(15990,0, 9,23561,3658.025,-5142.342,143.5081,5.305801,6,2500), +(15990,0, 9,23561,3669.560,-5134.747,143.2598,1.535890,6,2500), +(15990,0, 9,23561,3661.139,-5135.697,143.5744,4.450590,6,2500), +(15990,0, 9,23561,3664.328,-5145.051,143.4375,3.124139,6,2500), +(15990,0, 9,23561,3667.805,-5142.171,143.2627,3.019420,6,2500), +(15990,0, 9,23561,3664.311,-5132.388,143.3373,2.391101,6,2500), +(15990,0, 9,23561,3672.570,-5140.829,143.2567,0.261799,6,2500), +(15990,0, 9,23561,3670.688,-5145.027,143.4145,1.588250,6,2500), +(15990,0, 9,23561,3663.013,-5138.814,143.3694,2.164208,6,2500), +(15990,0, 9,23561,3665.966,-5146.641,143.5444,6.195919,6,2500), +(15990,0, 9,23562,3657.254,-5134.812,143.7300,3.403392,6,2500), +(15990,0, 9,23562,3668.447,-5147.539,143.6403,1.919862,6,2500), +(15990,0, 9,23562,3668.889,-5138.345,143.2660,5.393067,6,2500), +(15990,0, 9,23563,3657.367,-5146.094,143.5471,4.537856,6,2500), +(15990,0,10,23561,3711.224,-5164.672,143.6237,3.246312,6,2500), +(15990,0,10,23561,3700.833,-5172.231,143.5864,5.201081,6,2500), +(15990,0,10,23561,3699.030,-5176.604,143.7459,1.832596,6,2500), +(15990,0,10,23561,3697.229,-5170.590,143.6790,0.296706,6,2500), +(15990,0,10,23561,3704.382,-5182.113,143.8819,1.535890,6,2500), +(15990,0,10,23561,3703.449,-5161.482,143.3858,1.169371,6,2500), +(15990,0,10,23561,3705.811,-5165.041,143.4159,5.096361,6,2500), +(15990,0,10,23561,3709.738,-5173.312,143.7188,3.385939,6,2500), +(15990,0,10,23561,3699.682,-5163.227,143.5664,2.722714,6,2500), +(15990,0,10,23561,3705.211,-5171.760,143.5495,6.003932,6,2500), +(15990,0,10,23562,3713.235,-5169.006,143.7999,5.096361,6,2500), +(15990,0,10,23562,3701.653,-5167.655,143.4993,5.026548,6,2500), +(15990,0,10,23562,3692.469,-5163.676,143.8974,4.468043,6,2500), +(15990,0,10,23563,3704.658,-5178.262,143.7575,0.541052,6,2500), +(15990,0,11,23561,3744.357,-5156.203,143.2584,6.265732,6,2500), +(15990,0,11,23561,3749.947,-5158.716,143.2683,5.916666,6,2500), +(15990,0,11,23561,3751.198,-5167.764,143.6369,3.979351,6,2500), +(15990,0,11,23561,3756.085,-5155.776,143.5713,1.413717,6,2500), +(15990,0,11,23561,3753.844,-5153.094,143.3717,2.129302,6,2500), +(15990,0,11,23561,3757.361,-5169.438,143.6923,3.595378,6,2500), +(15990,0,11,23561,3756.383,-5148.479,143.4877,4.188790,6,2500), +(15990,0,11,23561,3746.525,-5152.034,143.2641,1.483530,6,2500), +(15990,0,11,23561,3743.098,-5161.342,143.5548,1.396263,6,2500), +(15990,0,11,23561,3757.974,-5164.038,143.6063,2.775074,6,2500), +(15990,0,11,23562,3753.185,-5160.274,143.3716,0.680678,6,2500), +(15990,0,11,23562,3757.442,-5152.137,143.6637,2.565634,6,2500), +(15990,0,11,23562,3744.791,-5162.307,143.6026,3.508112,6,2500), +(15990,0,11,23563,3750.655,-5162.939,143.4338,3.176499,6,2500); + +-- =============================== -- +-- Creature hitbox fixes (sniffed) -- +-- =============================== -- +UPDATE `creature_model_info` SET `BoundingRadius`=4,`CombatReach`=6 WHERE `DisplayID`=15945; +UPDATE `creature_model_info` SET `BoundingRadius`=1.25,`CombatReach`=3.125 WHERE `DisplayID`=16178; +UPDATE `creature_model_info` SET `BoundingRadius`=0.25,`CombatReach`=5 WHERE `DisplayID`=16586; + +-- ==================================================== -- +-- New creature_text for Guardian of Icecrown (sniffed) -- +-- ==================================================== -- +DELETE FROM `creature_text` WHERE `entry`=16441; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`probability`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(16441,0,0,"%s fleets after seeing Kel'thuzad fall!",16,100,12391,3,"Guardian of Icecrown EMOTE_FLEE"), +(16441,1,0,"A Guardian of Icecrown enters the fight!",41,100,32804,3,"Guardian of Icecrown EMOTE_APPEAR"); + +-- =============================== -- +-- Fix Void Zone delay from sniffs -- +-- =============================== -- +UPDATE `creature_template` SET `BaseAttackTime`=5500 WHERE `entry`=16129; + +-- ====================================== -- +-- New AI Names & correct movement speeds -- +-- ====================================== -- +DELETE FROM `smart_scripts` WHERE `entryorguid` in (16427,16428,16429,16441,23561,23562,23563) AND `source_type`=0; +UPDATE `creature_template` SET `speed_walk`=0.25,`speed_run`=0.285715,`ScriptName`="npc_kelthuzad_skeleton",`AIName`="" WHERE `Entry` in (16427,23561); +UPDATE `creature_template` SET `speed_walk`=0.1,`speed_run`=0.114286,`ScriptName`="npc_kelthuzad_banshee",`AIName`="" WHERE `Entry` in (16429,23563); +UPDATE `creature_template` SET `speed_walk`=0.7,`speed_run`=0.800002,`ScriptName`="npc_kelthuzad_abomination",`AIName`="" WHERE `Entry` in (16428,23562); +UPDATE `creature_template` SET `ScriptName`="npc_kelthuzad_guardian",`AIName`="" WHERE `Entry`=16441; + +-- ========================================================= -- +-- Trigger aura for Skeleton explosion and Banshee knockback -- +-- ========================================================= -- +DELETE FROM `creature_template_addon` WHERE `entry` in (16427,23561,16429,23563,30015,30016,30018,30047); +INSERT INTO `creature_template_addon` (`entry`,`auras`) VALUES +(16427,"28458"), +(30015,"28458"), +(23561,"28458"), +(30016,"28458"), +(16429,"28460"), +(30018,"28460"), +(23563,"28460"), +(30047,"28460"); + +-- ======================================================= -- +-- Sniffed spawn positions for various objects in the room -- +-- ======================================================= -- +UPDATE `gameobject` SET `position_x`=3635.355, `position_y`=-5090.291, `position_z`=142.9834, `rotation0`=0, `rotation1`=0, `rotation2`=-0.7743921, `rotation3`=0.632706 WHERE `guid`=150159; -- door +UPDATE `gameobject` SET `position_x`=3716.382, `position_y`=-5106.474, `position_z`=141.2899, `rotation0`=0, `rotation1`=0, `rotation2`=-0.6819983, `rotation3`=0.7313538 WHERE `guid`=150160; -- throne +UPDATE `gameobject` SET `position_x`=3732.656, `position_y`=-5026.173, `position_z`=152.7197, `rotation0`=0, `rotation1`=0, `rotation2`=-0.7743921, `rotation3`=0.632706 WHERE `guid`=150155; -- portal 01 +UPDATE `gameobject` SET `position_x`=3784.165, `position_y`=-5062.077, `position_z`=152.5704, `rotation0`=0, `rotation1`=0, `rotation2`=-0.957571, `rotation3`=0.2881973 WHERE `guid`=150156; -- portal 02 +UPDATE `gameobject` SET `position_x`=3760.238, `position_y`=-5175.256, `position_z`=152.5706, `rotation0`=0, `rotation1`=0, `rotation2`=0.8698883, `rotation3`=0.4932488 WHERE `guid`=150157; -- portal 03 +UPDATE `gameobject` SET `position_x`=3698.601, `position_y`=-5187.073, `position_z`=152.7199, `rotation0`=0, `rotation1`=0, `rotation2`=0.6149149, `rotation3`=0.7885935 WHERE `guid`=150158; -- portal 04 + +-- ================================== -- +-- Chains spell script (scale factor) -- +-- ================================== -- +DELETE FROM `spell_script_names` WHERE `ScriptName`="spell_kelthuzad_chains"; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(28410,"spell_kelthuzad_chains"); + +-- ================================================= -- +-- Fix throne to only be interactable after KT death -- +-- Also fix end of wing portals while we're at it -- +-- ================================================= -- +UPDATE `gameobject_template` SET `flags`=16 WHERE `entry`=181640; diff --git a/sql/updates/world/3.3.5/2016_08_24_09_world.sql b/sql/updates/world/3.3.5/2016_08_24_09_world.sql new file mode 100644 index 00000000000..0f8055841f0 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_08_24_09_world.sql @@ -0,0 +1,30 @@ +-- +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (6140, 6141, 6142); +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(6140, 24, 4, 0, ""), +(6141, 24, 5, 0, ""), +(6142, 24, 4, 0, ""); + +DELETE FROM `disables` WHERE `sourceType`=4 AND `entry` BETWEEN 4768 AND 4786; + +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` BETWEEN 4768 AND 4786; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(4768, 24, 4, 0, ""), +(4769, 24, 4, 0, ""), +(4770, 24, 4, 0, ""), +(4771, 24, 4, 0, ""), +(4772, 24, 4, 0, ""), +(4773, 24, 4, 0, ""), +(4774, 24, 4, 0, ""), +(4775, 24, 4, 0, ""), +(4776, 24, 4, 0, ""), +(4777, 24, 4, 0, ""), +(4778, 24, 4, 0, ""), +(4779, 24, 4, 0, ""), +(4780, 24, 4, 0, ""), +(4781, 24, 4, 0, ""), +(4782, 24, 4, 0, ""), +(4783, 24, 4, 0, ""), +(4784, 24, 4, 0, ""), +(4785, 24, 4, 0, ""), +(4786, 24, 4, 0, ""); diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index d5c17cce3ad..ee10242262b 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -817,7 +817,7 @@ PlayerAI::TargetedSpell SimpleCharmedPlayerAI::SelectAppropriateCastForSpec() VerifyAndPushSpellCast(spells, SPELL_HAMMER_OF_JUSTICE, TARGET_VICTIM, 6); VerifyAndPushSpellCast(spells, SPELL_HAND_OF_FREEDOM, TARGET_SELF, 3); VerifyAndPushSpellCast(spells, SPELL_HAND_OF_PROTECTION, TARGET_SELF, 1); - if (Creature* creatureCharmer = ObjectAccessor::GetCreature(*me, me->GetCharmerGUID())) + if (Creature* creatureCharmer = GetCharmer()) { if (creatureCharmer->IsDungeonBoss() || creatureCharmer->isWorldBoss()) VerifyAndPushSpellCast(spells, SPELL_HAND_OF_SACRIFICE, creatureCharmer, 10); @@ -1002,7 +1002,7 @@ PlayerAI::TargetedSpell SimpleCharmedPlayerAI::SelectAppropriateCastForSpec() case SPEC_DEATH_KNIGHT_BLOOD: VerifyAndPushSpellCast(spells, SPELL_RUNE_TAP, TARGET_NONE, 2); VerifyAndPushSpellCast(spells, SPELL_HYSTERIA, TARGET_SELF, 5); - if (Creature* creatureCharmer = ObjectAccessor::GetCreature(*me, me->GetCharmerGUID())) + if (Creature* creatureCharmer = GetCharmer()) if (!creatureCharmer->IsDungeonBoss() && !creatureCharmer->isWorldBoss()) VerifyAndPushSpellCast(spells, SPELL_HYSTERIA, creatureCharmer, 15); VerifyAndPushSpellCast(spells, SPELL_HEART_STRIKE, TARGET_VICTIM, 2); @@ -1180,7 +1180,7 @@ PlayerAI::TargetedSpell SimpleCharmedPlayerAI::SelectAppropriateCastForSpec() } VerifyAndPushSpellCast(spells, SPELL_TRANQUILITY, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_NATURE_SWIFTNESS, TARGET_NONE, 7); - if (Creature* creatureCharmer = ObjectAccessor::GetCreature(*me, me->GetCharmerGUID())) + if (Creature* creatureCharmer = GetCharmer()) { VerifyAndPushSpellCast(spells, SPELL_NOURISH, creatureCharmer, 5); VerifyAndPushSpellCast(spells, SPELL_WILD_GROWTH, creatureCharmer, 5); @@ -1260,7 +1260,7 @@ PlayerAI::TargetedSpell SimpleCharmedPlayerAI::SelectAppropriateCastForSpec() static const float CASTER_CHASE_DISTANCE = 28.0f; void SimpleCharmedPlayerAI::UpdateAI(const uint32 diff) { - Creature* charmer = me->GetCharmer() ? me->GetCharmer()->ToCreature() : nullptr; + Creature* charmer = GetCharmer(); if (!charmer) return; diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h index 18f65485161..b36c0471718 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.h +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -30,6 +30,13 @@ class TC_GAME_API PlayerAI : public UnitAI void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy + Creature* GetCharmer() const + { + if (ObjectGuid charmerGUID = me->GetCharmerGUID()) + if (charmerGUID.IsCreature()) + return ObjectAccessor::GetCreature(*me, charmerGUID); + return nullptr; + } // helper functions to determine player info // Return values range from 0 (left-most spec) to 2 (right-most spec). If two specs have the same number of talent points, the left-most of those specs is returned. static uint8 GetPlayerSpec(Player const* who); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 90fad46c21b..f1beca149d1 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1013,7 +1013,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsCreature(*itr)) - (*itr)->ToCreature()->UpdateEntry(e.action.updateTemplate.creature); + (*itr)->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, nullptr, e.action.updateTemplate.updateLevel != 0); delete targets; break; @@ -2758,6 +2758,11 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* ObjectGuid charmerOrOwnerGuid = me->GetCharmerOrOwnerGUID(); if (!charmerOrOwnerGuid) + if (TempSummon* tempSummon = me->ToTempSummon()) + if (Unit* summoner = tempSummon->GetSummoner()) + charmerOrOwnerGuid = summoner->GetGUID(); + + if (!charmerOrOwnerGuid) charmerOrOwnerGuid = me->GetCreatorGUID(); if (Unit* owner = ObjectAccessor::GetUnit(*me, charmerOrOwnerGuid)) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index e0f5dac4f5e..28d434ad988 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -740,6 +740,7 @@ struct SmartAction struct { uint32 creature; + uint32 updateLevel; } updateTemplate; struct diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2356b2098ff..37b44b3d952 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -77,6 +77,8 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM: + case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM: break; default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) @@ -237,11 +239,12 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: return true; // not check correctness node indexes - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY: if (equipped_item.item_quality >= MAX_ITEM_QUALITY) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) contains an unknown quality state value in value1 (%u), ignored.", - criteria->ID, criteria->Type, dataType, equipped_item.item_quality); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains an unknown quality state value in value1 (%u), ignored.", + criteria->ID, criteria->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY"), dataType, equipped_item.item_quality); return false; } return true; @@ -390,7 +393,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un } return instance->CheckAchievementCriteriaMeet(criteria_id, source, target, miscvalue1); } - case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM: { ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscvalue1); if (!pProto) @@ -418,6 +421,13 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un return source->HasTitle(titleInfo->bit_index); return false; } + case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY: + { + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscvalue1); + if (!pProto) + return false; + return pProto->Quality == item.item_quality; + } default: break; } diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index bdbd9e04446..21ff1b234d8 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -66,14 +66,15 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16, // holiday_id 0 event in holiday time ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17, // min_score max_score player's team win bg and opposition team have team score in range ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23, // title_id known (pvp) title, values from dbc + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY = 24 // item_quality }; -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 25 // maximum value in AchievementCriteriaDataType enum struct AchievementCriteriaData { @@ -164,7 +165,7 @@ struct AchievementCriteriaData uint32 max_score; } bg_loss_team_score; // ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18 (no data) - // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19 + // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM = 19 struct { uint32 item_level; @@ -185,6 +186,11 @@ struct AchievementCriteriaData { uint32 title_id; } known_title; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY = 23 + struct + { + uint32 item_quality; + } item; // ... struct { diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index f44099f6037..85e1c701aff 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -39,7 +39,7 @@ Battlefield::Battlefield() m_TypeId = 0; m_BattleId = 0; m_ZoneId = 0; - m_Map = NULL; + m_Map = nullptr; m_MapId = 0; m_MaxPlayer = 0; m_MinPlayer = 0; @@ -79,7 +79,7 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/) else // No more vacant places { /// @todo Send a packet to announce it to player - m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10; + m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(nullptr) + 10; InvitePlayerToQueue(player); } } @@ -158,14 +158,14 @@ bool Battlefield::Update(uint32 diff) // Kick players who chose not to accept invitation to the battle if (m_uiKickDontAcceptTimer <= diff) { - time_t now = time(NULL); - for (int team = 0; team < 2; team++) + time_t now = time(nullptr); + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); ++itr) if (itr->second <= now) KickPlayerFromBattlefield(itr->first); InvitePlayersInZoneToWar(); - for (int team = 0; team < 2; team++) + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); ++itr) if (itr->second <= now) KickPlayerFromBattlefield(itr->first); @@ -196,7 +196,7 @@ bool Battlefield::Update(uint32 diff) void Battlefield::InvitePlayersInZoneToQueue() { - for (uint8 team = 0; team < 2; ++team) + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) InvitePlayerToQueue(player); @@ -243,7 +243,7 @@ void Battlefield::InvitePlayersInZoneToWar() if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer) InvitePlayerToWar(player); else // Battlefield is full of players - m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10; + m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(nullptr) + 10; } } } @@ -267,7 +267,7 @@ void Battlefield::InvitePlayerToWar(Player* player) if (player->getLevel() < m_MinLevel) { if (m_PlayersWillBeKick[player->GetTeamId()].count(player->GetGUID()) == 0) - m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10; + m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(nullptr) + 10; return; } @@ -276,13 +276,13 @@ void Battlefield::InvitePlayerToWar(Player* player) return; m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID()); - m_InvitedPlayers[player->GetTeamId()][player->GetGUID()] = time(NULL) + m_TimeForAcceptInvite; + m_InvitedPlayers[player->GetTeamId()][player->GetGUID()] = time(nullptr) + m_TimeForAcceptInvite; player->GetSession()->SendBfInvitePlayerToWar(m_BattleId, m_ZoneId, m_TimeForAcceptInvite); } void Battlefield::InitStalker(uint32 entry, Position const& pos) { - if (Creature* creature = SpawnCreature(entry, pos, TEAM_NEUTRAL)) + if (Creature* creature = SpawnCreature(entry, pos)) StalkerGuid = creature->GetGUID(); else TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: Could not spawn Stalker (Creature entry %u), zone messages will be unavailable!", entry); @@ -309,7 +309,7 @@ void Battlefield::StartBattle() if (m_isActive) return; - for (int team = 0; team < BG_TEAMS_COUNT; team++) + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) { m_PlayersInWar[team].clear(); m_Groups[team].clear(); @@ -487,7 +487,7 @@ Group* Battlefield::GetFreeBfRaid(TeamId TeamId) if (!group->IsFull()) return group; - return NULL; + return nullptr; } Group* Battlefield::GetGroupPlayer(ObjectGuid guid, TeamId TeamId) @@ -497,7 +497,7 @@ Group* Battlefield::GetGroupPlayer(ObjectGuid guid, TeamId TeamId) if (group->IsMember(guid)) return group; - return NULL; + return nullptr; } bool Battlefield::AddOrSetPlayerToCorrectBfGroup(Player* player) @@ -549,12 +549,12 @@ BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const else TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u could not be found.", id); - return NULL; + return nullptr; } WorldSafeLocsEntry const* Battlefield::GetClosestGraveYard(Player* player) { - BfGraveyard* closestGY = NULL; + BfGraveyard* closestGY = nullptr; float maxdist = -1; for (uint8 i = 0; i < m_GraveyardList.size(); i++) { @@ -575,7 +575,7 @@ WorldSafeLocsEntry const* Battlefield::GetClosestGraveYard(Player* player) if (closestGY) return sWorldSafeLocsStore.LookupEntry(closestGY->GetGraveyardId()); - return NULL; + return nullptr; } void Battlefield::AddPlayerToResurrectQueue(ObjectGuid npcGuid, ObjectGuid playerGuid) @@ -625,8 +625,6 @@ BfGraveyard::BfGraveyard(Battlefield* battlefield) m_Bf = battlefield; m_GraveyardId = 0; m_ControlTeam = TEAM_NEUTRAL; - m_SpiritGuide[0].Clear(); - m_SpiritGuide[1].Clear(); } void BfGraveyard::Initialize(TeamId startControl, uint32 graveyardId) @@ -649,7 +647,7 @@ void BfGraveyard::SetSpirit(Creature* spirit, TeamId team) float BfGraveyard::GetDistance(Player* player) { - const WorldSafeLocsEntry* safeLoc = sWorldSafeLocsStore.LookupEntry(m_GraveyardId); + WorldSafeLocsEntry const* safeLoc = sWorldSafeLocsStore.LookupEntry(m_GraveyardId); return player->GetDistance2d(safeLoc->x, safeLoc->y); } @@ -718,7 +716,7 @@ void BfGraveyard::GiveControlTo(TeamId team) void BfGraveyard::RelocateDeadPlayers() { - WorldSafeLocsEntry const* closestGrave = NULL; + WorldSafeLocsEntry const* closestGrave = nullptr; for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) { Player* player = ObjectAccessor::FindPlayer(*itr); @@ -738,14 +736,14 @@ void BfGraveyard::RelocateDeadPlayers() bool BfGraveyard::HasNpc(ObjectGuid guid) { - if (!m_SpiritGuide[0] || !m_SpiritGuide[1]) + if (!m_SpiritGuide[TEAM_ALLIANCE] || !m_SpiritGuide[TEAM_HORDE]) return false; - if (!m_Bf->GetCreature(m_SpiritGuide[0]) || - !m_Bf->GetCreature(m_SpiritGuide[1])) + if (!m_Bf->GetCreature(m_SpiritGuide[TEAM_ALLIANCE]) || + !m_Bf->GetCreature(m_SpiritGuide[TEAM_HORDE])) return false; - return (m_SpiritGuide[0] == guid || m_SpiritGuide[1] == guid); + return (m_SpiritGuide[TEAM_ALLIANCE] == guid || m_SpiritGuide[TEAM_HORDE] == guid); } // ******************************************************* @@ -754,12 +752,7 @@ bool BfGraveyard::HasNpc(ObjectGuid guid) // ********************** Misc *************************** // ******************************************************* -Creature* Battlefield::SpawnCreature(uint32 entry, Position const& pos, TeamId teamId) -{ - return SpawnCreature(entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamId); -} - -Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId /*teamId*/) +Creature* Battlefield::SpawnCreature(uint32 entry, Position const& pos) { //Get map object Map* map = sMapMgr->CreateBaseMap(m_MapId); @@ -769,6 +762,9 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl return nullptr; } + float x, y, z, o; + pos.GetPosition(x, y, z, o); + Creature* creature = new Creature(); if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, PHASEMASK_NORMAL, entry, x, y, z, o)) { @@ -779,13 +775,6 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl creature->SetHomePosition(x, y, z, o); - CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); - if (!cinfo) - { - TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Entry %u does not exist.", entry); - return nullptr; - } - // Set creature in world map->AddToMap(creature); creature->setActive(true); @@ -794,19 +783,16 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl } // Method for spawning gameobject on map -GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z, float o) +GameObject* Battlefield::SpawnGameObject(uint32 entry, Position const& pos, G3D::Quat const& rot) { // Get map object Map* map = sMapMgr->CreateBaseMap(m_MapId); if (!map) - return 0; - - // Calculate rotation - G3D::Quat rot = G3D::Matrix3::fromEulerAnglesZYX(o, 0.f, 0.f); + return nullptr; // Create gameobject GameObject* go = new GameObject; - if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, Position(x, y, z, o), rot, 255, GO_STATE_READY)) + if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, pos, rot, 255, GO_STATE_READY)) { TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template %u could not be found in the database! Battlefield has not been created!", entry); TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Could not create gameobject template %u! Battlefield has not been created!", entry); @@ -824,14 +810,14 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z Creature* Battlefield::GetCreature(ObjectGuid guid) { if (!m_Map) - return NULL; + return nullptr; return m_Map->GetCreature(guid); } GameObject* Battlefield::GetGameObject(ObjectGuid guid) { if (!m_Map) - return NULL; + return nullptr; return m_Map->GetGameObject(guid); } @@ -947,7 +933,7 @@ bool BfCapturePoint::DelCapturePoint() { capturePoint->SetRespawnTime(0); // not save respawn time capturePoint->Delete(); - capturePoint = NULL; + capturePoint = nullptr; } m_capturePointGUID.Clear(); } @@ -964,7 +950,7 @@ bool BfCapturePoint::Update(uint32 diff) { float radius = capturePoint->GetGOInfo()->capturePoint.radius; - for (uint8 team = 0; team < 2; ++team) + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) { for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();) { @@ -992,7 +978,7 @@ bool BfCapturePoint::Update(uint32 diff) } // get the difference of numbers - float fact_diff = ((float) m_activePlayers[0].size() - (float) m_activePlayers[1].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL; + float fact_diff = ((float) m_activePlayers[TEAM_ALLIANCE].size() - (float) m_activePlayers[TEAM_HORDE].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL; if (G3D::fuzzyEq(fact_diff, 0.0f)) return false; @@ -1079,7 +1065,7 @@ bool BfCapturePoint::Update(uint32 diff) void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) { - for (uint8 team = 0; team < 2; ++team) + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area if (Player* player = ObjectAccessor::FindPlayer(*itr)) player->SendUpdateWorldState(field, value); @@ -1091,10 +1077,10 @@ void BfCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid) switch (m_State) { case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: - team = 0; + team = TEAM_ALLIANCE; break; case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: - team = 1; + team = TEAM_HORDE; break; default: return; diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 6968e31c7bd..99d92f7a545 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -280,9 +280,8 @@ class TC_GAME_API Battlefield : public ZoneScript BfGraveyard* GetGraveyardById(uint32 id) const; // Misc methods - virtual Creature* SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId /*teamId*/); - Creature* SpawnCreature(uint32 entry, Position const& pos, TeamId /*teamId*/); - GameObject* SpawnGameObject(uint32 entry, float x, float y, float z, float o); + Creature* SpawnCreature(uint32 entry, Position const& pos); + GameObject* SpawnGameObject(uint32 entry, Position const& pos, G3D::Quat const& rot); Creature* GetCreature(ObjectGuid guid); GameObject* GetGameObject(ObjectGuid guid); diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp index 1df87fe1d6f..8eae2f2d9d0 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.cpp +++ b/src/server/game/Battlefield/BattlefieldMgr.cpp @@ -109,11 +109,11 @@ Battlefield* BattlefieldMgr::GetBattlefieldToZoneId(uint32 zoneId) if (itr == _battlefieldMap.end()) { // no handle for this zone, return - return NULL; + return nullptr; } if (!itr->second->IsEnabled()) - return NULL; + return nullptr; return itr->second; } @@ -125,7 +125,7 @@ Battlefield* BattlefieldMgr::GetBattlefieldByBattleId(uint32 battleId) if ((*itr)->GetBattleId() == battleId) return *itr; } - return NULL; + return nullptr; } ZoneScript* BattlefieldMgr::GetZoneScript(uint32 zoneId) @@ -134,7 +134,7 @@ ZoneScript* BattlefieldMgr::GetZoneScript(uint32 zoneId) if (itr != _battlefieldMap.end()) return itr->second; - return NULL; + return nullptr; } void BattlefieldMgr::Update(uint32 diff) diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 3c9bf40f66c..2cf7059f7a8 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -31,6 +31,452 @@ #include "TemporarySummon.h" #include "WorldSession.h" +struct BfWGCoordGY +{ + Position Pos; + uint32 GraveyardID; + uint32 TextID; // for gossip menu + TeamId StartControl; +}; + +// 7 in sql, 7 in header +BfWGCoordGY const WGGraveYard[BATTLEFIELD_WG_GRAVEYARD_MAX] = +{ + { { 5104.750f, 2300.940f, 368.579f, 0.733038f }, 1329, BATTLEFIELD_WG_GOSSIPTEXT_GY_NE, TEAM_NEUTRAL }, + { { 5099.120f, 3466.036f, 368.484f, 5.317802f }, 1330, BATTLEFIELD_WG_GOSSIPTEXT_GY_NW, TEAM_NEUTRAL }, + { { 4314.648f, 2408.522f, 392.642f, 6.268125f }, 1333, BATTLEFIELD_WG_GOSSIPTEXT_GY_SE, TEAM_NEUTRAL }, + { { 4331.716f, 3235.695f, 390.251f, 0.008500f }, 1334, BATTLEFIELD_WG_GOSSIPTEXT_GY_SW, TEAM_NEUTRAL }, + { { 5537.986f, 2897.493f, 517.057f, 4.819249f }, 1285, BATTLEFIELD_WG_GOSSIPTEXT_GY_KEEP, TEAM_NEUTRAL }, + { { 5032.454f, 3711.382f, 372.468f, 3.971623f }, 1331, BATTLEFIELD_WG_GOSSIPTEXT_GY_HORDE, TEAM_HORDE }, + { { 5140.790f, 2179.120f, 390.950f, 1.972220f }, 1332, BATTLEFIELD_WG_GOSSIPTEXT_GY_ALLIANCE, TEAM_ALLIANCE }, +}; + +uint32 const ClockWorldState[] = { 3781, 4354 }; +uint32 const WintergraspFaction[] = { 1732, 1735, 35 }; + +Position const WintergraspStalkerPos = { 4948.985f, 2937.789f, 550.5172f, 1.815142f }; + +Position const WintergraspRelicPos = { 5440.379f, 2840.493f, 430.2816f, -1.832595f }; +G3D::Quat const WintergraspRelicRot = { 0.f, 0.f, -0.7933531f, 0.6087617f }; + +uint8 const WG_MAX_OBJ = 32; +uint8 const WG_MAX_TURRET = 15; +uint8 const WG_MAX_KEEP_NPC = 39; +uint8 const WG_MAX_OUTSIDE_NPC = 14; +uint8 const WG_OUTSIDE_ALLIANCE_NPC = 7; +uint8 const WG_MAX_TELEPORTER = 12; +uint8 const WG_MAX_WORKSHOP = 6; +uint8 const WG_MAX_TOWER = 7; + +// ***************************************************** +// ************ Destructible (Wall, Tower..) *********** +// ***************************************************** + +struct WintergraspBuildingSpawnData +{ + uint32 entry; + uint32 WorldState; + Position pos; + G3D::Quat rot; + WintergraspGameObjectBuildingType type; +}; + +WintergraspBuildingSpawnData const WGGameObjectBuilding[WG_MAX_OBJ] = +{ + // Wall (Not spawned in db) + // Entry WS X Y Z O rX rY rZ rW Type + { 190219, 3749, { 5371.457f, 3047.472f, 407.5710f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190220, 3750, { 5331.264f, 3047.105f, 407.9228f, 0.05235888f }, { 0.f, 0.f, 0.026176450f, 0.99965730f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191795, 3764, { 5385.841f, 2909.490f, 409.7127f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191796, 3772, { 5384.452f, 2771.835f, 410.2704f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191799, 3762, { 5371.436f, 2630.610f, 408.8163f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191800, 3766, { 5301.838f, 2909.089f, 409.8661f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191801, 3770, { 5301.063f, 2771.411f, 409.9014f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191802, 3751, { 5280.197f, 2995.583f, 408.8249f, 1.61442800f }, { 0.f, 0.f, 0.722363500f, 0.69151360f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191803, 3752, { 5279.136f, 2956.023f, 408.6041f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191804, 3767, { 5278.685f, 2882.513f, 409.5388f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191806, 3769, { 5279.502f, 2798.945f, 409.9983f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191807, 3759, { 5279.937f, 2724.766f, 409.9452f, 1.56207000f }, { 0.f, 0.f, 0.704014800f, 0.71018530f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191808, 3760, { 5279.601f, 2683.786f, 409.8488f, 1.55334100f }, { 0.f, 0.f, 0.700908700f, 0.71325110f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191809, 3761, { 5330.955f, 2630.777f, 409.2826f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190369, 3753, { 5256.085f, 2933.963f, 409.3571f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190370, 3758, { 5257.463f, 2747.327f, 409.7427f, -3.13285800f }, { 0.f, 0.f, -0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190371, 3754, { 5214.960f, 2934.089f, 409.1905f, -0.00872424f }, { 0.f, 0.f, -0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190372, 3757, { 5215.821f, 2747.566f, 409.1884f, -3.13285800f }, { 0.f, 0.f, -0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190374, 3755, { 5162.273f, 2883.043f, 410.2556f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.70401500f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 190376, 3756, { 5163.724f, 2799.838f, 409.2270f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.70401500f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + + // Tower of keep (Not spawned in db) + { 190221, 3711, { 5281.154f, 3044.588f, 407.8434f, 3.115388f }, { 0.f, 0.f, 0.9999142f, 0.013101960f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NW + { 190373, 3713, { 5163.757f, 2932.228f, 409.1904f, 3.124123f }, { 0.f, 0.f, 0.9999619f, 0.008734641f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SW + { 190377, 3714, { 5166.397f, 2748.368f, 409.1884f, -1.570796f }, { 0.f, 0.f, -0.7071066f, 0.707106900f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SE + { 190378, 3712, { 5281.192f, 2632.479f, 409.0985f, -1.588246f }, { 0.f, 0.f, -0.7132492f, 0.700910500f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NE + + // Wall (with passage) (Not spawned in db) + { 191797, 3765, { 5343.290f, 2908.860f, 409.5757f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.9999905f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191798, 3771, { 5342.719f, 2771.386f, 409.6249f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.0000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + { 191805, 3768, { 5279.126f, 2840.797f, 409.7826f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.7040150f }, BATTLEFIELD_WG_OBJECTTYPE_WALL }, + + // South tower (Not spawned in db) + { 190356, 3704, { 4557.173f, 3623.943f, 395.8828f, 1.675516f }, { 0.f, 0.f, 0.7431450f, 0.669130400f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // W + { 190357, 3705, { 4398.172f, 2822.497f, 405.6270f, -3.124123f }, { 0.f, 0.f, -0.9999619f, 0.008734641f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // S + { 190358, 3706, { 4459.105f, 1944.326f, 434.9912f, -2.002762f }, { 0.f, 0.f, -0.8422165f, 0.539139500f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // E + + // Door of forteress (Not spawned in db) + { GO_WINTERGRASP_FORTRESS_GATE, 3763, { 5162.991f, 2841.232f, 410.1892f, -3.132858f }, { 0.f, 0.f, -0.9999905f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_DOOR }, + + // Last door (Not spawned in db) + { GO_WINTERGRASP_VAULT_GATE, 3773, { 5397.108f, 2841.54f, 425.9014f, 3.141593f }, { 0.f, 0.f, -1.f, 0.f }, BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST }, +}; + +struct StaticWintergraspTowerInfo +{ + uint8 TowerId; + + struct + { + uint8 Damaged; + uint8 Destroyed; + } TextIds; +}; + +StaticWintergraspTowerInfo const TowerData[WG_MAX_TOWER] = +{ + { BATTLEFIELD_WG_TOWER_FORTRESS_NW, { BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_FORTRESS_SW, { BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_FORTRESS_SE, { BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_FORTRESS_NE, { BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_SHADOWSIGHT, { BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_WINTER_S_EDGE, { BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DESTROY } }, + { BATTLEFIELD_WG_TOWER_FLAMEWATCH, { BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DESTROY } } +}; + +Position const WGTurret[WG_MAX_TURRET] = +{ + { 5391.19f, 3060.8f, 419.616f, 1.69557f }, + { 5266.75f, 2976.5f, 421.067f, 3.20354f }, + { 5234.86f, 2948.8f, 420.88f, 1.61311f }, + { 5323.05f, 2923.7f, 421.645f, 1.5817f }, + { 5363.82f, 2923.87f, 421.709f, 1.60527f }, + { 5264.04f, 2861.34f, 421.587f, 3.21142f }, + { 5264.68f, 2819.78f, 421.656f, 3.15645f }, + { 5322.16f, 2756.69f, 421.646f, 4.69978f }, + { 5363.78f, 2756.77f, 421.629f, 4.78226f }, + { 5236.2f, 2732.68f, 421.649f, 4.72336f }, + { 5265.02f, 2704.63f, 421.7f, 3.12507f }, + { 5350.87f, 2616.03f, 421.243f, 4.72729f }, + { 5390.95f, 2615.5f, 421.126f, 4.6409f }, + { 5148.8f, 2820.24f, 421.621f, 3.16043f }, + { 5147.98f, 2861.93f, 421.63f, 3.18792f }, +}; + +struct WintergraspObjectPositionData +{ + Position Pos; + uint32 HordeEntry; + uint32 AllianceEntry; +}; + +// Here there is all npc keeper spawn point +WintergraspObjectPositionData const WGKeepNPC[WG_MAX_KEEP_NPC] = +{ + // X Y Z O horde alliance + // North East + { { 5326.203125f, 2660.026367f, 409.100891f, 2.543383f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard + { { 5298.430176f, 2738.760010f, 409.316010f, 3.971740f }, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH }, // Vieron Blazefeather + { { 5335.310059f, 2764.110107f, 409.274994f, 4.834560f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5349.810059f, 2763.629883f, 409.333008f, 4.660030f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + // North + { { 5373.470215f, 2789.060059f, 409.322998f, 2.600540f }, BATTLEFIELD_WG_NPC_STONE_GUARD_MUKAR, BATTLEFIELD_WG_NPC_KNIGHT_DAMERON }, // Stone Guard Mukar + { { 5296.560059f, 2789.870117f, 409.274994f, 0.733038f }, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA }, // Voodoo Master Fu'jin + { { 5372.670000f, 2786.740000f, 409.442000f, 2.809980f }, BATTLEFIELD_WG_NPC_CHAMPION_ROS_SLAI, BATTLEFIELD_WG_NPC_MARSHAL_MAGRUDER }, // Wintergrasp Quartermaster + { { 5368.709961f, 2856.360107f, 409.322998f, 2.949610f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5367.910156f, 2826.520020f, 409.322998f, 3.333580f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5389.270020f, 2847.370117f, 418.759003f, 3.106690f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5388.560059f, 2834.770020f, 418.759003f, 3.071780f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5359.129883f, 2837.989990f, 409.364014f, 4.698930f }, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH }, // Commander Dardosh + { { 5366.129883f, 2833.399902f, 409.322998f, 3.141590f }, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS }, // Tactical Officer Kilrath + // X Y Z O horde alliance + // North West + { { 5350.680176f, 2917.010010f, 409.274994f, 1.466080f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5335.120117f, 2916.800049f, 409.444000f, 1.500980f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5295.560059f, 2926.669922f, 409.274994f, 0.872665f }, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE }, // Stronghoof + { { 5371.399902f, 3026.510010f, 409.205994f, 3.250030f }, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA }, // Primalist Mulfort + { { 5392.123535f, 3031.110352f, 409.187683f, 3.677212f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard + // South + { { 5270.060059f, 2847.550049f, 409.274994f, 3.071780f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5270.160156f, 2833.479980f, 409.274994f, 3.124140f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5179.109863f, 2837.129883f, 409.274994f, 3.211410f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5179.669922f, 2846.600098f, 409.274994f, 3.089230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5234.970215f, 2883.399902f, 409.274994f, 4.293510f }, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO }, // Lieutenant Murp + // X Y Z O horde alliance + // Portal guards (from around the fortress) + { { 5319.209473f, 3055.947754f, 409.176636f, 1.020201f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5311.612305f, 3061.207275f, 408.734161f, 0.965223f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5264.713379f, 3017.283447f, 408.479706f, 3.482424f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5269.096191f, 3008.315918f, 408.826294f, 3.843706f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5201.414551f, 2945.096924f, 409.190735f, 0.945592f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5193.386230f, 2949.617188f, 409.190735f, 1.145859f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5148.116211f, 2904.761963f, 409.193756f, 3.368532f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5153.355957f, 2895.501465f, 409.199310f, 3.549174f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5154.353027f, 2787.349365f, 409.250183f, 2.555644f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5150.066406f, 2777.876953f, 409.343903f, 2.708797f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5193.706543f, 2732.882812f, 409.189514f, 4.845073f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5202.126953f, 2737.570557f, 409.189514f, 5.375215f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5269.181152f, 2671.174072f, 409.098999f, 2.457459f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5264.960938f, 2662.332520f, 409.098999f, 2.598828f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5307.111816f, 2616.006836f, 409.095734f, 5.355575f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 5316.770996f, 2619.430176f, 409.027740f, 5.363431f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard +}; + +WintergraspObjectPositionData const WGOutsideNPC[WG_MAX_OUTSIDE_NPC] = +{ + { { 5032.04f, 3681.79f, 362.980f, 4.210f }, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, 0 }, + { { 5020.71f, 3626.19f, 360.150f, 4.640f }, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, 0 }, + { { 4994.85f, 3660.51f, 359.150f, 2.260f }, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, 0 }, + { { 5015.46f, 3677.11f, 362.970f, 6.009f }, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, 0 }, + { { 5031.12f, 3663.77f, 363.500f, 3.110f }, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, 0 }, + { { 5042.74f, 3675.82f, 363.060f, 3.358f }, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, 0 }, + { { 5014.45f, 3640.87f, 361.390f, 3.280f }, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, 0 }, + { { 5100.07f, 2168.89f, 365.779f, 1.972f }, 0, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH }, + { { 5081.70f, 2173.73f, 365.878f, 0.855f }, 0, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA }, + { { 5078.28f, 2183.70f, 365.029f, 1.466f }, 0, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH }, + { { 5088.49f, 2188.18f, 365.647f, 5.253f }, 0, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS }, + { { 5095.67f, 2193.28f, 365.924f, 4.939f }, 0, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE }, + { { 5088.61f, 2167.66f, 365.689f, 0.680f }, 0, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA }, + { { 5080.40f, 2199.00f, 359.489f, 2.967f }, 0, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO }, +}; + +struct WintergraspTeleporterData +{ + uint32 Entry; + Position Pos; + G3D::Quat Rot; +}; + +WintergraspTeleporterData const WGPortalDefenderData[WG_MAX_TELEPORTER + 10] = +{ + // Player teleporter + { 190763, { 5153.408f, 2901.349f, 409.1913f, -0.06981169f }, { 0.f, 0.f, -0.03489876f, 0.9993908f } }, + { 191575, { 5153.408f, 2901.349f, 409.1913f, -0.06981169f }, { 0.f, 0.f, -0.03489876f, 0.9993908f } }, + { 190763, { 5153.931f, 2781.671f, 409.2455f, 1.65806200f }, { 0.f, 0.f, 0.73727700f, 0.6755905f } }, + { 191575, { 5153.931f, 2781.671f, 409.2455f, 1.65806200f }, { 0.f, 0.f, 0.73727700f, 0.6755905f } }, + { 190763, { 5196.671f, 2737.345f, 409.1892f, -2.93213900f }, { 0.f, 0.f, -0.99452110f, 0.1045355f } }, + { 191575, { 5196.671f, 2737.345f, 409.1892f, -2.93213900f }, { 0.f, 0.f, -0.99452110f, 0.1045355f } }, + { 190763, { 5197.050f, 2944.814f, 409.1913f, 2.33874000f }, { 0.f, 0.f, 0.92050460f, 0.3907318f } }, + { 191575, { 5197.050f, 2944.814f, 409.1913f, 2.33874000f }, { 0.f, 0.f, 0.92050460f, 0.3907318f } }, + { 190763, { 5268.698f, 2666.421f, 409.0985f, -0.71558490f }, { 0.f, 0.f, -0.35020730f, 0.9366722f } }, + { 191575, { 5268.698f, 2666.421f, 409.0985f, -0.71558490f }, { 0.f, 0.f, -0.35020730f, 0.9366722f } }, + { 190763, { 5269.208f, 3013.838f, 408.8276f, -1.76278200f }, { 0.f, 0.f, -0.77162460f, 0.6360782f } }, + { 191575, { 5269.208f, 3013.839f, 408.7695f, -1.76277900f }, { 0.f, 0.f, -0.77162360f, 0.6360794f } }, + { 190763, { 5269.208f, 3013.839f, 408.7695f, 4.52040600f }, { 0.f, 0.f, -0.77162360f, 0.6360794f } }, + { 190763, { 5311.445f, 2618.931f, 409.0916f, -2.37364400f }, { 0.f, 0.f, -0.92718320f, 0.3746083f } }, + { 191575, { 5311.445f, 2618.931f, 409.0916f, -2.37364400f }, { 0.f, 0.f, -0.92718320f, 0.3746083f } }, + { 190763, { 5314.580f, 3055.852f, 408.8620f, 0.54105060f }, { 0.f, 0.f, 0.26723770f, 0.9636307f } }, + { 191575, { 5314.580f, 3055.852f, 408.8620f, 0.54105060f }, { 0.f, 0.f, 0.26723770f, 0.9636307f } }, + { 190763, { 5391.277f, 2828.094f, 418.6752f, -2.16420600f }, { 0.f, 0.f, -0.88294700f, 0.4694727f } }, + { 191575, { 5391.277f, 2828.094f, 418.6752f, -2.16420600f }, { 0.f, 0.f, -0.88294700f, 0.4694727f } }, + { 192819, { 5401.634f, 2853.667f, 418.6748f, 2.63544400f }, { 0.f, 0.f, 0.96814730f, 0.2503814f } }, + // Vehicle teleporter + { 192951, { 5314.515f, 2703.687f, 408.5502f, -0.89011660f }, { 0.f, 0.f, -0.43051050f, 0.9025856f } }, + { 192951, { 5316.252f, 2977.042f, 408.5385f, -0.82030330f }, { 0.f, 0.f, -0.39874840f, 0.9170604f } } +}; + +// ********************************************************* +// **********Tower Element(GameObject, Creature)************ +// ********************************************************* + +struct WintergraspGameObjectData +{ + Position Pos; + G3D::Quat Rot; + uint32 HordeEntry; + uint32 AllianceEntry; +}; + +struct WintergraspTowerData +{ + uint32 towerEntry; // Gameobject id of tower + std::vector<WintergraspGameObjectData> GameObject; // Gameobject position and entry (Horde/Alliance) + + // Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming + std::vector<WintergraspObjectPositionData> CreatureBottom; +}; + +uint8 const WG_MAX_ATTACKTOWERS = 3; +// 192414 : 0 in sql, 1 in header +// 192278 : 0 in sql, 3 in header +WintergraspTowerData const AttackTowers[WG_MAX_ATTACKTOWERS] = +{ + // West tower + { + 190356, + { + { { 4559.113f, 3606.216f, 419.9992f, 4.799657f }, { 0.f, 0.f, -0.67558960f, 0.73727790f }, 192488, 192501 }, // Flag on tower + { { 4539.420f, 3622.490f, 420.0342f, 3.211419f }, { 0.f, 0.f, -0.99939060f, 0.03490613f }, 192488, 192501 }, // Flag on tower + { { 4555.258f, 3641.648f, 419.9740f, 1.675514f }, { 0.f, 0.f, 0.74314400f, 0.66913150f }, 192488, 192501 }, // Flag on tower + { { 4574.872f, 3625.911f, 420.0792f, 0.087266f }, { 0.f, 0.f, 0.04361916f, 0.99904820f }, 192488, 192501 }, // Flag on tower + { { 4433.899f, 3534.142f, 360.2750f, 4.433136f }, { 0.f, 0.f, -0.79863550f, 0.60181500f }, 192269, 192278 }, // Flag near workshop + { { 4572.933f, 3475.519f, 363.0090f, 1.422443f }, { 0.f, 0.f, 0.65275960f, 0.75756520f }, 192269, 192277 } // Flag near bridge + }, + { + { { 4418.688477f, 3506.251709f, 358.975494f, 4.293305f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Roaming Guard + } + }, + // South Tower + { + 190357, + { + { { 4416.004f, 2822.666f, 429.8512f, 6.2657330f }, { 0.f, 0.f, -0.00872612f, 0.99996190f }, 192488, 192501 }, // Flag on tower + { { 4398.819f, 2804.698f, 429.7920f, 4.6949370f }, { 0.f, 0.f, -0.71325020f, 0.70090960f }, 192488, 192501 }, // Flag on tower + { { 4387.622f, 2719.566f, 389.9351f, 4.7385700f }, { 0.f, 0.f, -0.69779010f, 0.71630230f }, 192366, 192414 }, // Flag near tower + { { 4464.124f, 2855.453f, 406.1106f, 0.8290324f }, { 0.f, 0.f, 0.40274720f, 0.91531130f }, 192366, 192429 }, // Flag near tower + { { 4526.457f, 2810.181f, 391.1997f, 3.2899610f }, { 0.f, 0.f, -0.99724960f, 0.07411628f }, 192269, 192278 } // Flag near bridge + }, + { + { { 4452.859863f, 2808.870117f, 402.604004f, 6.056290f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4455.899902f, 2835.958008f, 401.122559f, 0.034907f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4412.649414f, 2953.792236f, 374.799957f, 0.980838f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard + { { 4362.089844f, 2811.510010f, 407.337006f, 3.193950f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4412.290039f, 2753.790039f, 401.015015f, 5.829400f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4421.939941f, 2773.189941f, 400.894989f, 5.707230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard + } + }, + // East Tower + { + 190358, + { + { { 4466.793f, 1960.418f, 459.1437f, 1.151916f }, { 0.f, 0.f, 0.5446386f, 0.8386708f }, 192488, 192501 }, // Flag on tower + { { 4475.351f, 1937.031f, 459.0702f, 5.846854f }, { 0.f, 0.f, -0.2164392f, 0.9762961f }, 192488, 192501 }, // Flag on tower + { { 4451.758f, 1928.104f, 459.0759f, 4.276057f }, { 0.f, 0.f, -0.8433914f, 0.5372996f }, 192488, 192501 }, // Flag on tower + { { 4442.987f, 1951.898f, 459.0930f, 2.740162f }, { 0.f, 0.f, 0.9799242f, 0.1993704f }, 192488, 192501 } // Flag on tower + }, + { + { { 4501.060059f, 1990.280029f, 431.157013f, 1.029740f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4463.830078f, 2015.180054f, 430.299988f, 1.431170f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4494.580078f, 1943.760010f, 435.627014f, 6.195920f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4450.149902f, 1897.579956f, 435.045013f, 4.398230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard + { { 4428.870117f, 1906.869995f, 432.648010f, 3.996800f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard + } + } +}; + +struct WintergraspTowerCannonData +{ + uint32 towerEntry; + std::vector<Position> TowerCannonBottom; + std::vector<Position> TurretTop; +}; + +uint8 const WG_MAX_TOWER_CANNON = 7; + +WintergraspTowerCannonData const TowerCannon[WG_MAX_TOWER_CANNON] = +{ + { + 190221, + { + // no cannons at bottom + }, + { + { 5255.88f, 3047.63f, 438.499f, 3.13677f }, + { 5280.90f, 3071.32f, 438.499f, 1.62879f } + } + }, + { + 190373, + { + // no cannons at bottom + }, + { + { 5138.59f, 2935.16f, 439.845f, 3.11723f }, + { 5163.06f, 2959.52f, 439.846f, 1.47258f } + } + }, + { + 190377, + { + // no cannons at bottom + }, + { + { 5163.84f, 2723.74f, 439.844f, 1.39940f }, + { 5139.69f, 2747.40f, 439.844f, 3.17221f } + } + }, + { + 190378, + { + // no cannons at bottom + }, + { + { 5278.21f, 2607.23f, 439.755f, 4.71944f }, + { 5255.01f, 2631.98f, 439.755f, 3.15257f } + } + }, + { + 190356, + { + { 4537.380371f, 3599.531738f, 402.886993f, 3.998462f }, + { 4581.497559f, 3604.087158f, 402.886963f, 5.651723f } + }, + { + { 4469.448242f, 1966.623779f, 465.647217f, 1.153573f }, + { 4581.895996f, 3626.438477f, 426.539062f, 0.117806f } + } + }, + { + 190357, + { + { 4421.640137f, 2799.935791f, 412.630920f, 5.459298f }, + { 4420.263184f, 2845.340332f, 412.630951f, 0.742197f } + }, + { + { 4423.430664f, 2822.762939f, 436.283142f, 6.223487f }, + { 4397.825684f, 2847.629639f, 436.283325f, 1.579430f }, + { 4398.814941f, 2797.266357f, 436.283051f, 4.703747f } + } + }, + { + 190358, + { + { 4448.138184f, 1974.998779f, 441.995911f, 1.967238f }, + { 4448.713379f, 1955.148682f, 441.995178f, 0.380733f } + }, + { + { 4469.448242f, 1966.623779f, 465.647217f, 1.153573f }, + { 4481.996582f, 1933.658325f, 465.647186f, 5.873029f } + } + } +}; + +// ********************************************************* +// *****************WorkShop Data & Element***************** +// ********************************************************* + +struct StaticWintergraspWorkshopInfo +{ + uint8 WorkshopId; + uint32 WorldStateId; + + struct + { + uint8 AllianceCapture; + uint8 AllianceAttack; + uint8 HordeCapture; + uint8 HordeAttack; + } TextIds; +}; + +StaticWintergraspWorkshopInfo const WorkshopData[WG_MAX_WORKSHOP] = +{ + { BATTLEFIELD_WG_WORKSHOP_NE, WORLDSTATE_WORKSHOP_NE, { BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_HORDE } }, + { BATTLEFIELD_WG_WORKSHOP_NW, WORLDSTATE_WORKSHOP_NW, { BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_HORDE } }, + { BATTLEFIELD_WG_WORKSHOP_SE, WORLDSTATE_WORKSHOP_SE, { BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_HORDE } }, + { BATTLEFIELD_WG_WORKSHOP_SW, WORLDSTATE_WORKSHOP_SW, { BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_HORDE } }, + // KEEP WORKSHOPS - It can't be taken, so it doesn't have a textids + { BATTLEFIELD_WG_WORKSHOP_KEEP_WEST, WORLDSTATE_WORKSHOP_K_W, { 0, 0, 0, 0 } }, + { BATTLEFIELD_WG_WORKSHOP_KEEP_EAST, WORLDSTATE_WORKSHOP_K_E, { 0, 0, 0, 0 } } +}; + BattlefieldWG::~BattlefieldWG() { for (WintergraspWorkshop* workshop : Workshops) @@ -95,17 +541,22 @@ bool BattlefieldWG::SetupBattlefield() m_Timer = m_RestartAfterCrash; } + SetData(BATTLEFIELD_WG_DATA_WON_A, uint32(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_A))); + SetData(BATTLEFIELD_WG_DATA_DEF_A, uint32(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_A))); + SetData(BATTLEFIELD_WG_DATA_WON_H, uint32(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_H))); + SetData(BATTLEFIELD_WG_DATA_DEF_H, uint32(sWorld->getWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_H))); + for (uint8 i = 0; i < BATTLEFIELD_WG_GRAVEYARD_MAX; i++) { BfGraveyardWG* graveyard = new BfGraveyardWG(this); // When between games, the graveyard is controlled by the defending team - if (WGGraveYard[i].startcontrol == TEAM_NEUTRAL) - graveyard->Initialize(m_DefenderTeam, WGGraveYard[i].gyid); + if (WGGraveYard[i].StartControl == TEAM_NEUTRAL) + graveyard->Initialize(m_DefenderTeam, WGGraveYard[i].GraveyardID); else - graveyard->Initialize(WGGraveYard[i].startcontrol, WGGraveYard[i].gyid); + graveyard->Initialize(WGGraveYard[i].StartControl, WGGraveYard[i].GraveyardID); - graveyard->SetTextId(WGGraveYard[i].textid); + graveyard->SetTextId(WGGraveYard[i].TextID); m_GraveyardList[i] = graveyard; } @@ -124,13 +575,14 @@ bool BattlefieldWG::SetupBattlefield() } // Spawn NPCs in the defender's keep, both Horde and Alliance - for (uint8 i = 0; i < WG_MAX_KEEP_NPC; i++) + for (uint8 i = 0; i < WG_MAX_KEEP_NPC; ++i) { // Horde npc - if (Creature* creature = SpawnCreature(WGKeepNPC[i].entryHorde, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_HORDE)) + if (Creature* creature = SpawnCreature(WGKeepNPC[i].HordeEntry, WGKeepNPC[i].Pos)) KeepCreature[TEAM_HORDE].insert(creature->GetGUID()); + // Alliance npc - if (Creature* creature = SpawnCreature(WGKeepNPC[i].entryAlliance, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_ALLIANCE)) + if (Creature* creature = SpawnCreature(WGKeepNPC[i].AllianceEntry, WGKeepNPC[i].Pos)) KeepCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); } @@ -140,13 +592,13 @@ bool BattlefieldWG::SetupBattlefield() HideNpc(creature); // Spawn Horde NPCs outside the keep - for (uint8 i = 0; i < WG_OUTSIDE_ALLIANCE_NPC; i++) - if (Creature* creature = SpawnCreature(WGOutsideNPC[i].entryHorde, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_HORDE)) + for (uint8 i = 0; i < WG_OUTSIDE_ALLIANCE_NPC; ++i) + if (Creature* creature = SpawnCreature(WGOutsideNPC[i].HordeEntry, WGOutsideNPC[i].Pos)) OutsideCreature[TEAM_HORDE].insert(creature->GetGUID()); // Spawn Alliance NPCs outside the keep - for (uint8 i = WG_OUTSIDE_ALLIANCE_NPC; i < WG_MAX_OUTSIDE_NPC; i++) - if (Creature* creature = SpawnCreature(WGOutsideNPC[i].entryAlliance, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_ALLIANCE)) + for (uint8 i = WG_OUTSIDE_ALLIANCE_NPC; i < WG_MAX_OUTSIDE_NPC; ++i) + if (Creature* creature = SpawnCreature(WGOutsideNPC[i].AllianceEntry, WGOutsideNPC[i].Pos)) OutsideCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); // Hide units outside the keep that are defenders @@ -158,7 +610,7 @@ bool BattlefieldWG::SetupBattlefield() for (uint8 i = 0; i < WG_MAX_TURRET; i++) { Position towerCannonPos = WGTurret[i].GetPosition(); - if (Creature* creature = SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos, TEAM_ALLIANCE)) + if (Creature* creature = SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos)) { CanonList.insert(creature->GetGUID()); HideNpc(creature); @@ -168,7 +620,7 @@ bool BattlefieldWG::SetupBattlefield() // Spawn all gameobjects for (uint8 i = 0; i < WG_MAX_OBJ; i++) { - if (GameObject* go = SpawnGameObject(WGGameObjectBuilding[i].entry, WGGameObjectBuilding[i].x, WGGameObjectBuilding[i].y, WGGameObjectBuilding[i].z, WGGameObjectBuilding[i].o)) + if (GameObject* go = SpawnGameObject(WGGameObjectBuilding[i].entry, WGGameObjectBuilding[i].pos, WGGameObjectBuilding[i].rot)) { BfWGGameObjectBuilding* b = new BfWGGameObjectBuilding(this, WGGameObjectBuilding[i].type, WGGameObjectBuilding[i].WorldState); b->Init(go); @@ -179,9 +631,10 @@ bool BattlefieldWG::SetupBattlefield() } // Spawning portal defender - for (uint8 i = 0; i < WG_MAX_TELEPORTER; i++) + for (uint8 i = 0; i < WG_MAX_TELEPORTER; ++i) { - if (GameObject* go = SpawnGameObject(WGPortalDefenderData[i].entry, WGPortalDefenderData[i].x, WGPortalDefenderData[i].y, WGPortalDefenderData[i].z, WGPortalDefenderData[i].o)) + WintergraspTeleporterData const& teleporter = WGPortalDefenderData[i]; + if (GameObject* go = SpawnGameObject(teleporter.Entry, teleporter.Pos, teleporter.Rot)) { DefenderPortalList.insert(go->GetGUID()); go->SetFaction(WintergraspFaction[GetDefenderTeam()]); @@ -200,6 +653,10 @@ bool BattlefieldWG::Update(uint32 diff) sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_ACTIVE, m_isActive); sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDER, m_DefenderTeam); sWorld->setWorldState(ClockWorldState[0], m_Timer); + sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_A, GetData(BATTLEFIELD_WG_DATA_WON_A)); + sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_A, GetData(BATTLEFIELD_WG_DATA_DEF_A)); + sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_H, GetData(BATTLEFIELD_WG_DATA_WON_H)); + sWorld->setWorldState(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_H, GetData(BATTLEFIELD_WG_DATA_DEF_H)); m_saveTimer = 60 * IN_MILLISECONDS; } else @@ -211,7 +668,7 @@ bool BattlefieldWG::Update(uint32 diff) void BattlefieldWG::OnBattleStart() { // Spawn titan relic - if (GameObject* relic = SpawnGameObject(GO_WINTERGRASP_TITAN_S_RELIC, 5440.0f, 2840.8f, 430.43f, 0)) + if (GameObject* relic = SpawnGameObject(GO_WINTERGRASP_TITAN_S_RELIC, WintergraspRelicPos, WintergraspRelicRot)) { // Update faction of relic, only attacker can click on relic->SetFaction(WintergraspFaction[GetAttackerTeam()]); @@ -297,6 +754,13 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer) relic->RemoveFromWorld(); m_titansRelicGUID.Clear(); + // successful defense + if (endByTimer) + UpdateData(GetDefenderTeam() == TEAM_HORDE ? BATTLEFIELD_WG_DATA_DEF_H : BATTLEFIELD_WG_DATA_DEF_A, 1); + // successful attack (note that teams have already been swapped, so defender team is the one who won) + else + UpdateData(GetDefenderTeam() == TEAM_HORDE ? BATTLEFIELD_WG_DATA_WON_H : BATTLEFIELD_WG_DATA_WON_A, 1); + // Remove turret for (GuidSet::const_iterator itr = CanonList.begin(); itr != CanonList.end(); ++itr) { @@ -809,18 +1273,22 @@ uint32 BattlefieldWG::GetData(uint32 data) const void BattlefieldWG::FillInitialWorldStates(WorldPacket& data) { + data << uint32(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_A) << uint32(GetData(BATTLEFIELD_WG_DATA_DEF_A)); + data << uint32(BATTLEFIELD_WG_WORLD_STATE_DEFENDED_H) << uint32(GetData(BATTLEFIELD_WG_DATA_DEF_H)); + data << uint32(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_A) << uint32(GetData(BATTLEFIELD_WG_DATA_WON_A)); + data << uint32(BATTLEFIELD_WG_WORLD_STATE_ATTACKED_H) << uint32(GetData(BATTLEFIELD_WG_DATA_WON_H)); data << uint32(BATTLEFIELD_WG_WORLD_STATE_ATTACKER) << uint32(GetAttackerTeam()); data << uint32(BATTLEFIELD_WG_WORLD_STATE_DEFENDER) << uint32(GetDefenderTeam()); data << uint32(BATTLEFIELD_WG_WORLD_STATE_ACTIVE) << uint32(IsWarTime() ? 0 : 1); // Note: cleanup these two, their names look awkward data << uint32(BATTLEFIELD_WG_WORLD_STATE_SHOW_WORLDSTATE) << uint32(IsWarTime() ? 1 : 0); for (uint32 i = 0; i < 2; ++i) - data << ClockWorldState[i] << uint32(time(NULL) + (m_Timer / 1000)); + data << ClockWorldState[i] << uint32(time(nullptr) + (m_Timer / 1000)); data << uint32(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_H) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_H)); - data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_H) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H); + data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_H) << uint32(GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H)); data << uint32(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_A) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_A)); - data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_A) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A); + data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_A) << uint32(GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A)); for (BfWGGameObjectBuilding* building : BuildingsInZone) building->FillInitialWorldStates(data); @@ -831,12 +1299,12 @@ void BattlefieldWG::FillInitialWorldStates(WorldPacket& data) void BattlefieldWG::SendInitWorldStatesTo(Player* player) { - WorldPacket data(SMSG_INIT_WORLD_STATES, 4 + 4 + 4 + 2 + (BuildingsInZone.size() * 8) + (Workshops.size() * 8)); + WorldPacket data(SMSG_INIT_WORLD_STATES, 4 + 4 + 4 + 2 + (14 + WG_MAX_OBJ + WG_MAX_WORKSHOP) * 8); data << uint32(m_MapId); data << uint32(m_ZoneId); data << uint32(0); // AreaId - data << uint16(10 + BuildingsInZone.size() + Workshops.size()); // Number of fields + data << uint16(14 + BuildingsInZone.size() + Workshops.size()); // Number of fields FillInitialWorldStates(data); @@ -853,6 +1321,14 @@ void BattlefieldWG::SendInitWorldStatesToAll() void BattlefieldWG::BrokenWallOrTower(TeamId /*team*/) { +/* +uint32 const WGQuest[2][6] = +{ + { 13186, 13181, 13222, 13538, 13177, 13179 }, + { 13185, 13183, 13223, 13539, 13178, 13180 }, +}; +*/ + // might be some use for this in the future. old code commented out below. KL /* if (team == GetDefenderTeam()) { @@ -1087,7 +1563,7 @@ void BfWGGameObjectBuilding::Rebuild() // Rebuild gameobject if (build->IsDestructibleBuilding()) { - build->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, NULL, true); + build->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true); if (build->GetEntry() == GO_WINTERGRASP_VAULT_GATE) if (GameObject* go = build->FindNearestGameObject(GO_WINTERGRASP_KEEP_COLLISION_WALL, 50.0f)) go->SetGoState(GO_STATE_READY); @@ -1189,7 +1665,7 @@ void BfWGGameObjectBuilding::Init(GameObject* go) case BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_INTACT: case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT: case BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT: - go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, NULL, true); + go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true); break; case BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DESTROY: case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY: @@ -1234,33 +1710,23 @@ void BfWGGameObjectBuilding::Init(GameObject* go) if (towerId > 3) // Attacker towers { // Spawn associate gameobjects - for (uint8 i = 0; i < AttackTowers[towerId - 4].nbObject; i++) + for (WintergraspGameObjectData const& gobData : AttackTowers[towerId - 4].GameObject) { - WintergraspObjectPositionData const& gobData = AttackTowers[towerId - 4].GameObject[i]; - if (GameObject* goHorde = _wg->SpawnGameObject(gobData.entryHorde, gobData.x, gobData.y, gobData.z, gobData.o)) + if (GameObject* goHorde = _wg->SpawnGameObject(gobData.HordeEntry, gobData.Pos, gobData.Rot)) m_GameObjectList[TEAM_HORDE].insert(goHorde->GetGUID()); - if (GameObject* goAlliance = _wg->SpawnGameObject(gobData.entryAlliance, gobData.x, gobData.y, gobData.z, gobData.o)) + + if (GameObject* goAlliance = _wg->SpawnGameObject(gobData.AllianceEntry, gobData.Pos, gobData.Rot)) m_GameObjectList[TEAM_ALLIANCE].insert(goAlliance->GetGUID()); } // Spawn associate npc bottom - for (uint8 i = 0; i < AttackTowers[towerId - 4].nbCreatureBottom; i++) + for (WintergraspObjectPositionData const& creatureData : AttackTowers[towerId - 4].CreatureBottom) { - WintergraspObjectPositionData const& creatureData = AttackTowers[towerId - 4].CreatureBottom[i]; - if (Creature* creature = _wg->SpawnCreature(creatureData.entryHorde, creatureData.x, creatureData.y, creatureData.z, creatureData.o, TEAM_HORDE)) + if (Creature* creature = _wg->SpawnCreature(creatureData.HordeEntry, creatureData.Pos)) m_CreatureBottomList[TEAM_HORDE].insert(creature->GetGUID()); - if (Creature* creature = _wg->SpawnCreature(creatureData.entryAlliance, creatureData.x, creatureData.y, creatureData.z, creatureData.o, TEAM_ALLIANCE)) - m_CreatureBottomList[TEAM_ALLIANCE].insert(creature->GetGUID()); - } - // Spawn associate npc top - for (uint8 i = 0; i < AttackTowers[towerId - 4].nbCreatureTop; i++) - { - WintergraspObjectPositionData const& creatureData = AttackTowers[towerId - 4].CreatureTop[i]; - if (Creature* creature = _wg->SpawnCreature(creatureData.entryHorde, creatureData.x, creatureData.y, creatureData.z, creatureData.o, TEAM_HORDE)) - m_CreatureTopList[TEAM_HORDE].insert(creature->GetGUID()); - if (Creature* creature = _wg->SpawnCreature(creatureData.entryAlliance, creatureData.x, creatureData.y, creatureData.z, creatureData.o, TEAM_ALLIANCE)) - m_CreatureTopList[TEAM_ALLIANCE].insert(creature->GetGUID()); + if (Creature* creature = _wg->SpawnCreature(creatureData.AllianceEntry, creatureData.Pos)) + m_CreatureBottomList[TEAM_ALLIANCE].insert(creature->GetGUID()); } } @@ -1270,10 +1736,9 @@ void BfWGGameObjectBuilding::Init(GameObject* go) _staticTowerInfo = &TowerData[towerId]; // Spawn Turret bottom - for (uint8 i = 0; i < TowerCannon[towerId].nbTowerCannonBottom; i++) + for (Position const& turretPos : TowerCannon[towerId].TowerCannonBottom) { - Position const& turretPos = TowerCannon[towerId].TowerCannonBottom[i]; - if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, turretPos, TEAM_ALLIANCE)) + if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, turretPos)) { m_TowerCannonBottomList.insert(turret->GetGUID()); switch (go->GetEntry()) @@ -1290,15 +1755,15 @@ void BfWGGameObjectBuilding::Init(GameObject* go) turret->setFaction(WintergraspFaction[_wg->GetAttackerTeam()]); break; } + _wg->HideNpc(turret); } } // Spawn Turret top - for (uint8 i = 0; i < TowerCannon[towerId].nbTurretTop; i++) + for (Position const& towerCannonPos : TowerCannon[towerId].TurretTop) { - Position const& towerCannonPos = TowerCannon[towerId].TurretTop[i]; - if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos, TeamId(0))) + if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos)) { m_TurretTopList.insert(turret->GetGUID()); switch (go->GetEntry()) @@ -1432,21 +1897,9 @@ WintergraspWorkshop::WintergraspWorkshop(BattlefieldWG* wg, uint8 type) _staticInfo = &WorkshopData[type]; } -void WintergraspWorkshop::AddCreature(WintergraspObjectPositionData const& obj) -{ - if (Creature* creature = _wg->SpawnCreature(obj.entryHorde, obj.x, obj.y, obj.z, obj.o, TEAM_HORDE)) - _creatureOnPoint[TEAM_HORDE].insert(creature->GetGUID()); - - if (Creature* creature = _wg->SpawnCreature(obj.entryAlliance, obj.x, obj.y, obj.z, obj.o, TEAM_ALLIANCE)) - _creatureOnPoint[TEAM_ALLIANCE].insert(creature->GetGUID()); -} - -void WintergraspWorkshop::AddGameObject(WintergraspObjectPositionData const& obj) +uint8 WintergraspWorkshop::GetId() const { - if (GameObject* go = _wg->SpawnGameObject(obj.entryHorde, obj.x, obj.y, obj.z, obj.o)) - _gameObjectOnPoint[TEAM_HORDE].insert(go->GetGUID()); - if (GameObject* go = _wg->SpawnGameObject(obj.entryAlliance, obj.x, obj.y, obj.z, obj.o)) - _gameObjectOnPoint[TEAM_ALLIANCE].insert(go->GetGUID()); + return _staticInfo->WorkshopId; } void WintergraspWorkshop::GiveControlTo(TeamId teamId, bool init /*= false*/) diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 52789d38d8e..b95a6c93d5c 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -26,6 +26,9 @@ class WintergraspCapturePoint; struct BfWGGameObjectBuilding; struct WintergraspWorkshop; +struct StaticWintergraspTowerInfo; +struct StaticWintergraspWorkshopInfo; +struct WintergraspObjectPositionData; typedef std::set<GameObject*> GameObjectSet; typedef std::set<BfWGGameObjectBuilding*> GameObjectBuildingSet; @@ -33,6 +36,12 @@ typedef std::set<WintergraspWorkshop*> WorkshopSet; typedef std::set<Group*> GroupSet; //typedef std::set<WintergraspCapturePoint *> CapturePointSet; unused ? +// used in Player.cpp +extern uint32 const ClockWorldState[]; + +// used in zone_wintergrasp.cpp +TC_GAME_API extern uint32 const WintergraspFaction[]; + enum WintergrastData { BATTLEFIELD_WG_ZONEID = 4197, // Wintergrasp @@ -93,6 +102,10 @@ enum WintergraspData BATTLEFIELD_WG_DATA_MAX_VEHICLE_H, BATTLEFIELD_WG_DATA_VEHICLE_A, BATTLEFIELD_WG_DATA_VEHICLE_H, + BATTLEFIELD_WG_DATA_WON_A, + BATTLEFIELD_WG_DATA_DEF_A, + BATTLEFIELD_WG_DATA_WON_H, + BATTLEFIELD_WG_DATA_DEF_H, BATTLEFIELD_WG_DATA_MAX }; @@ -125,7 +138,11 @@ enum WintergraspWorldStates BATTLEFIELD_WG_WORLD_STATE_ACTIVE = 3801, BATTLEFIELD_WG_WORLD_STATE_DEFENDER = 3802, BATTLEFIELD_WG_WORLD_STATE_ATTACKER = 3803, - BATTLEFIELD_WG_WORLD_STATE_SHOW_WORLDSTATE = 3710 + BATTLEFIELD_WG_WORLD_STATE_SHOW_WORLDSTATE = 3710, + BATTLEFIELD_WG_WORLD_STATE_ATTACKED_H = 4022, + BATTLEFIELD_WG_WORLD_STATE_ATTACKED_A = 4023, + BATTLEFIELD_WG_WORLD_STATE_DEFENDED_H = 4024, + BATTLEFIELD_WG_WORLD_STATE_DEFENDED_A = 4025 }; enum WintergraspAreaIds @@ -214,36 +231,6 @@ enum WintergraspNpcs NPC_WINTERGRASP_TOWER_CANNON = 28366 }; -struct BfWGCoordGY -{ - float x; - float y; - float z; - float o; - uint32 gyid; - uint8 type; - uint32 textid; // for gossip menu - TeamId startcontrol; -}; - -uint32 const WGQuest[2][6] = -{ - { 13186, 13181, 13222, 13538, 13177, 13179 }, - { 13185, 13183, 13223, 13539, 13178, 13180 }, -}; - -// 7 in sql, 7 in header -BfWGCoordGY const WGGraveYard[BATTLEFIELD_WG_GRAVEYARD_MAX] = -{ - { 5104.750f, 2300.940f, 368.579f, 0.733038f, 1329, BATTLEFIELD_WG_GY_WORKSHOP_NE, BATTLEFIELD_WG_GOSSIPTEXT_GY_NE, TEAM_NEUTRAL }, - { 5099.120f, 3466.036f, 368.484f, 5.317802f, 1330, BATTLEFIELD_WG_GY_WORKSHOP_NW, BATTLEFIELD_WG_GOSSIPTEXT_GY_NW, TEAM_NEUTRAL }, - { 4314.648f, 2408.522f, 392.642f, 6.268125f, 1333, BATTLEFIELD_WG_GY_WORKSHOP_SE, BATTLEFIELD_WG_GOSSIPTEXT_GY_SE, TEAM_NEUTRAL }, - { 4331.716f, 3235.695f, 390.251f, 0.008500f, 1334, BATTLEFIELD_WG_GY_WORKSHOP_SW, BATTLEFIELD_WG_GOSSIPTEXT_GY_SW, TEAM_NEUTRAL }, - { 5537.986f, 2897.493f, 517.057f, 4.819249f, 1285, BATTLEFIELD_WG_GY_KEEP, BATTLEFIELD_WG_GOSSIPTEXT_GY_KEEP, TEAM_NEUTRAL }, - { 5032.454f, 3711.382f, 372.468f, 3.971623f, 1331, BATTLEFIELD_WG_GY_HORDE, BATTLEFIELD_WG_GOSSIPTEXT_GY_HORDE, TEAM_HORDE }, - { 5140.790f, 2179.120f, 390.950f, 1.972220f, 1332, BATTLEFIELD_WG_GY_ALLIANCE, BATTLEFIELD_WG_GOSSIPTEXT_GY_ALLIANCE, TEAM_ALLIANCE }, -}; - /* ######################### * * WintergraspCapturePoint * * ######################### */ @@ -432,22 +419,6 @@ class TC_GAME_API BattlefieldWG : public Battlefield ObjectGuid m_titansRelicGUID; }; -uint32 const VehNumWorldState[] = { 3680, 3490 }; -uint32 const MaxVehNumWorldState[] = { 3681, 3491 }; -uint32 const ClockWorldState[] = { 3781, 4354 }; -uint32 const WintergraspFaction[] = { 1732, 1735, 35 }; - -Position const WintergraspStalkerPos = { 4948.985f, 2937.789f, 550.5172f, 1.815142f }; - -uint8 const WG_MAX_OBJ = 32; -uint8 const WG_MAX_TURRET = 15; -uint8 const WG_MAX_KEEP_NPC = 39; -uint8 const WG_MAX_OUTSIDE_NPC = 14; -uint8 const WG_OUTSIDE_ALLIANCE_NPC = 7; -uint8 const WG_MAX_TELEPORTER = 12; -uint8 const WG_MAX_WORKSHOP = 6; -uint8 const WG_MAX_TOWER = 7; - enum WintergraspGameObjectBuildingType { BATTLEFIELD_WG_OBJECTTYPE_DOOR, @@ -580,519 +551,6 @@ enum WintergraspGameObject GO_WINTERGRASP_KEEP_COLLISION_WALL = 194323 }; -// ***************************************************** -// ************ Destructible (Wall, Tower..) *********** -// ***************************************************** - -struct WintergraspBuildingSpawnData -{ - uint32 entry; - uint32 WorldState; - float x; - float y; - float z; - float o; - WintergraspGameObjectBuildingType type; -}; - -struct WintergraspObjectPositionData -{ - float x; - float y; - float z; - float o; - uint32 entryHorde; - uint32 entryAlliance; -}; - -WintergraspBuildingSpawnData const WGGameObjectBuilding[WG_MAX_OBJ] = -{ - // Wall (Not spawned in db) - // Entry WS X Y Z O Type - { 190219, 3749, 5371.46f, 3047.47f, 407.571f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190220, 3750, 5331.26f, 3047.1f, 407.923f, 0.052359f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191795, 3764, 5385.84f, 2909.49f, 409.713f, 0.00872f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191796, 3772, 5384.45f, 2771.84f, 410.27f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191799, 3762, 5371.44f, 2630.61f, 408.816f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191800, 3766, 5301.84f, 2909.09f, 409.866f, 0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191801, 3770, 5301.06f, 2771.41f, 409.901f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191802, 3751, 5280.2f, 2995.58f, 408.825f, 1.61443f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191803, 3752, 5279.14f, 2956.02f, 408.604f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191804, 3767, 5278.69f, 2882.51f, 409.539f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191806, 3769, 5279.5f, 2798.94f, 409.998f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191807, 3759, 5279.94f, 2724.77f, 409.945f, 1.56207f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191808, 3760, 5279.6f, 2683.79f, 409.849f, 1.55334f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191809, 3761, 5330.96f, 2630.78f, 409.283f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190369, 3753, 5256.08f, 2933.96f, 409.357f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190370, 3758, 5257.46f, 2747.33f, 409.743f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190371, 3754, 5214.96f, 2934.09f, 409.19f, -0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190372, 3757, 5215.82f, 2747.57f, 409.188f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190374, 3755, 5162.27f, 2883.04f, 410.256f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 190376, 3756, 5163.72f, 2799.84f, 409.227f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - - // Tower of keep (Not spawned in db) - { 190221, 3711, 5281.15f, 3044.59f, 407.843f, 3.11539f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NW - { 190373, 3713, 5163.76f, 2932.23f, 409.19f, 3.12412f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SW - { 190377, 3714, 5166.4f, 2748.37f, 409.188f, -1.5708f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SE - { 190378, 3712, 5281.19f, 2632.48f, 409.099f, -1.58825f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NE - - // Wall (with passage) (Not spawned in db) - { 191797, 3765, 5343.29f, 2908.86f, 409.576f, 0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191798, 3771, 5342.72f, 2771.39f, 409.625f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - { 191805, 3768, 5279.13f, 2840.8f, 409.783f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL }, - - // South tower (Not spawned in db) - { 190356, 3704, 4557.17f, 3623.94f, 395.883f, 1.67552f, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // W - { 190357, 3705, 4398.17f, 2822.5f, 405.627f, -3.12412f, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // S - { 190358, 3706, 4459.1f, 1944.33f, 434.991f, -2.00276f, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // E - - // Door of forteress (Not spawned in db) - { GO_WINTERGRASP_FORTRESS_GATE, 3763, 5162.99f, 2841.23f, 410.162f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_DOOR }, - - // Last door (Not spawned in db) - { GO_WINTERGRASP_VAULT_GATE, 3773, 5397.11f, 2841.54f, 425.899f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST }, -}; - -struct StaticWintergraspTowerInfo -{ - uint8 TowerId; - - struct - { - uint8 Damaged; - uint8 Destroyed; - } TextIds; -}; - -StaticWintergraspTowerInfo const TowerData[WG_MAX_TOWER] = -{ - { BATTLEFIELD_WG_TOWER_FORTRESS_NW, { BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_FORTRESS_SW, { BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_FORTRESS_SE, { BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_FORTRESS_NE, { BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_SHADOWSIGHT, { BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_WINTER_S_EDGE, { BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DESTROY } }, - { BATTLEFIELD_WG_TOWER_FLAMEWATCH, { BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DESTROY } } -}; - -Position const WGTurret[WG_MAX_TURRET] = -{ - { 5391.19f, 3060.8f, 419.616f, 1.69557f }, - { 5266.75f, 2976.5f, 421.067f, 3.20354f }, - { 5234.86f, 2948.8f, 420.88f, 1.61311f }, - { 5323.05f, 2923.7f, 421.645f, 1.5817f }, - { 5363.82f, 2923.87f, 421.709f, 1.60527f }, - { 5264.04f, 2861.34f, 421.587f, 3.21142f }, - { 5264.68f, 2819.78f, 421.656f, 3.15645f }, - { 5322.16f, 2756.69f, 421.646f, 4.69978f }, - { 5363.78f, 2756.77f, 421.629f, 4.78226f }, - { 5236.2f, 2732.68f, 421.649f, 4.72336f }, - { 5265.02f, 2704.63f, 421.7f, 3.12507f }, - { 5350.87f, 2616.03f, 421.243f, 4.72729f }, - { 5390.95f, 2615.5f, 421.126f, 4.6409f }, - { 5148.8f, 2820.24f, 421.621f, 3.16043f }, - { 5147.98f, 2861.93f, 421.63f, 3.18792f }, -}; - -// Here there is all npc keeper spawn point -WintergraspObjectPositionData const WGKeepNPC[WG_MAX_KEEP_NPC] = -{ - // X Y Z O horde alliance - // North East - { 5326.203125f, 2660.026367f, 409.100891f, 2.543383f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard - { 5298.430176f, 2738.760010f, 409.316010f, 3.971740f, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH }, // Vieron Blazefeather - { 5335.310059f, 2764.110107f, 409.274994f, 4.834560f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5349.810059f, 2763.629883f, 409.333008f, 4.660030f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - // North - { 5373.470215f, 2789.060059f, 409.322998f, 2.600540f, BATTLEFIELD_WG_NPC_STONE_GUARD_MUKAR, BATTLEFIELD_WG_NPC_KNIGHT_DAMERON }, // Stone Guard Mukar - { 5296.560059f, 2789.870117f, 409.274994f, 0.733038f, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA }, // Voodoo Master Fu'jin - { 5372.670000f, 2786.740000f, 409.442000f, 2.809980f, BATTLEFIELD_WG_NPC_CHAMPION_ROS_SLAI, BATTLEFIELD_WG_NPC_MARSHAL_MAGRUDER }, // Wintergrasp Quartermaster - { 5368.709961f, 2856.360107f, 409.322998f, 2.949610f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5367.910156f, 2826.520020f, 409.322998f, 3.333580f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5389.270020f, 2847.370117f, 418.759003f, 3.106690f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5388.560059f, 2834.770020f, 418.759003f, 3.071780f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5359.129883f, 2837.989990f, 409.364014f, 4.698930f, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH }, // Commander Dardosh - { 5366.129883f, 2833.399902f, 409.322998f, 3.141590f, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS }, // Tactical Officer Kilrath - // X Y Z O horde alliance - // North West - { 5350.680176f, 2917.010010f, 409.274994f, 1.466080f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5335.120117f, 2916.800049f, 409.444000f, 1.500980f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5295.560059f, 2926.669922f, 409.274994f, 0.872665f, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE }, // Stronghoof - { 5371.399902f, 3026.510010f, 409.205994f, 3.250030f, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA }, // Primalist Mulfort - { 5392.123535f, 3031.110352f, 409.187683f, 3.677212f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard - // South - { 5270.060059f, 2847.550049f, 409.274994f, 3.071780f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5270.160156f, 2833.479980f, 409.274994f, 3.124140f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5179.109863f, 2837.129883f, 409.274994f, 3.211410f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5179.669922f, 2846.600098f, 409.274994f, 3.089230f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5234.970215f, 2883.399902f, 409.274994f, 4.293510f, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO }, // Lieutenant Murp - // X Y Z O horde alliance - // Portal guards (from around the fortress) - { 5319.209473f, 3055.947754f, 409.176636f, 1.020201f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5311.612305f, 3061.207275f, 408.734161f, 0.965223f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5264.713379f, 3017.283447f, 408.479706f, 3.482424f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5269.096191f, 3008.315918f, 408.826294f, 3.843706f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5201.414551f, 2945.096924f, 409.190735f, 0.945592f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5193.386230f, 2949.617188f, 409.190735f, 1.145859f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5148.116211f, 2904.761963f, 409.193756f, 3.368532f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5153.355957f, 2895.501465f, 409.199310f, 3.549174f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5154.353027f, 2787.349365f, 409.250183f, 2.555644f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5150.066406f, 2777.876953f, 409.343903f, 2.708797f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5193.706543f, 2732.882812f, 409.189514f, 4.845073f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5202.126953f, 2737.570557f, 409.189514f, 5.375215f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5269.181152f, 2671.174072f, 409.098999f, 2.457459f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5264.960938f, 2662.332520f, 409.098999f, 2.598828f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5307.111816f, 2616.006836f, 409.095734f, 5.355575f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 5316.770996f, 2619.430176f, 409.027740f, 5.363431f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard -}; - -const WintergraspObjectPositionData WGOutsideNPC[WG_MAX_OUTSIDE_NPC] = -{ - { 5032.04f, 3681.79f, 362.980f, 4.210f, BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER, 0 }, - { 5020.71f, 3626.19f, 360.150f, 4.640f, BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN, 0 }, - { 4994.85f, 3660.51f, 359.150f, 2.260f, BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH, 0 }, - { 5015.46f, 3677.11f, 362.970f, 6.009f, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH, 0 }, - { 5031.12f, 3663.77f, 363.500f, 3.110f, BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF, 0 }, - { 5042.74f, 3675.82f, 363.060f, 3.358f, BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT, 0 }, - { 5014.45f, 3640.87f, 361.390f, 3.280f, BATTLEFIELD_WG_NPC_LIEUTENANT_MURP, 0 }, - { 5100.07f, 2168.89f, 365.779f, 1.972f, 0, BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH }, - { 5081.70f, 2173.73f, 365.878f, 0.855f, 0, BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA }, - { 5078.28f, 2183.70f, 365.029f, 1.466f, 0, BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH }, - { 5088.49f, 2188.18f, 365.647f, 5.253f, 0, BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS }, - { 5095.67f, 2193.28f, 365.924f, 4.939f, 0, BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE }, - { 5088.61f, 2167.66f, 365.689f, 0.680f, 0, BATTLEFIELD_WG_NPC_ANCHORITE_TESSA }, - { 5080.40f, 2199.00f, 359.489f, 2.967f, 0, BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO }, -}; - -struct WintergraspTeleporterData -{ - uint32 entry; - float x; - float y; - float z; - float o; -}; - -WintergraspTeleporterData const WGPortalDefenderData[WG_MAX_TELEPORTER] = -{ - // Player teleporter - { 190763, 5153.41f, 2901.35f, 409.191f, -0.069f }, - { 190763, 5268.70f, 2666.42f, 409.099f, -0.715f }, - { 190763, 5197.05f, 2944.81f, 409.191f, 2.3387f }, - { 190763, 5196.67f, 2737.34f, 409.189f, -2.932f }, - { 190763, 5314.58f, 3055.85f, 408.862f, 0.5410f }, - { 190763, 5391.28f, 2828.09f, 418.675f, -2.164f }, - { 190763, 5153.93f, 2781.67f, 409.246f, 1.6580f }, - { 190763, 5311.44f, 2618.93f, 409.092f, -2.373f }, - { 190763, 5269.21f, 3013.84f, 408.828f, -1.762f }, - { 190763, 5401.62f, 2853.66f, 418.674f, 2.6354f }, - // Vehicle teleporter - { 192951, 5314.51f, 2703.69f, 408.550f, -0.890f }, - { 192951, 5316.25f, 2977.04f, 408.539f, -0.820f }, -}; - -// ********************************************************* -// **********Tower Element(GameObject, Creature)************ -// ********************************************************* - -struct WintergraspTowerData -{ - uint32 towerEntry; // Gameobject id of tower - uint8 nbObject; // Number of gameobjects spawned on this point - WintergraspObjectPositionData GameObject[6]; // Gameobject position and entry (Horde/Alliance) - - // Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming - uint8 nbCreatureBottom; - WintergraspObjectPositionData CreatureBottom[9]; - uint8 nbCreatureTop; - WintergraspObjectPositionData CreatureTop[5]; -}; - -uint8 const WG_MAX_ATTACKTOWERS = 3; -// 192414 : 0 in sql, 1 in header -// 192278 : 0 in sql, 3 in header -const WintergraspTowerData AttackTowers[WG_MAX_ATTACKTOWERS] = -{ - // West tower - { - 190356, - 6, - { - { 4559.109863f, 3606.219971f, 419.998993f, -1.483530f, 192488, 192501 }, // Flag on tower - { 4539.419922f, 3622.489990f, 420.033997f, -3.071770f, 192488, 192501 }, // Flag on tower - { 4555.259766f, 3641.649902f, 419.973999f, 1.675510f, 192488, 192501 }, // Flag on tower - { 4574.870117f, 3625.909912f, 420.079010f, 0.080117f, 192488, 192501 }, // Flag on tower - { 4433.899902f, 3534.139893f, 360.274994f, -1.850050f, 192269, 192278 }, // Flag near workshop - { 4572.930176f, 3475.520020f, 363.009003f, 1.42240f, 192269, 192278 } // Flag near bridge - }, - 1, - { - { 4418.688477f, 3506.251709f, 358.975494f, 4.293305f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - 0, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }, - - // South Tower - { - 190357, - 5, - { - { 4416.000000f, 2822.669922f, 429.851013f, -0.017452f, 192488, 192501 }, // Flag on tower - { 4398.819824f, 2804.699951f, 429.791992f, -1.588250f, 192488, 192501 }, // Flag on tower - { 4387.620117f, 2719.570068f, 389.934998f, -1.544620f, 192366, 192414 }, // Flag near tower - { 4464.120117f, 2855.449951f, 406.110992f, 0.829032f, 192366, 192429 }, // Flag near tower - { 4526.459961f, 2810.179932f, 391.200012f, -2.993220f, 192269, 192278 }, // Flag near bridge - { 0, 0, 0, 0, 0, 0 }, - }, - 6, - { - { 4452.859863f, 2808.870117f, 402.604004f, 6.056290f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4455.899902f, 2835.958008f, 401.122559f, 0.034907f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4412.649414f, 2953.792236f, 374.799957f, 0.980838f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard - { 4362.089844f, 2811.510010f, 407.337006f, 3.193950f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4412.290039f, 2753.790039f, 401.015015f, 5.829400f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4421.939941f, 2773.189941f, 400.894989f, 5.707230f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0}, - }, - 0, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }, - - // East Tower - { - 190358, - 4, - { - { 4466.790039f, 1960.420044f, 459.144012f, 1.151920f, 192488, 192501 }, // Flag on tower - { 4475.350098f, 1937.030029f, 459.070007f, -0.43633f, 192488, 192501 }, // Flag on tower - { 4451.759766f, 1928.099976f, 459.075989f, -2.00713f, 192488, 192501 }, // Flag on tower - { 4442.990234f, 1951.900024f, 459.092987f, 2.740160f, 192488, 192501 }, // Flag on tower - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - 5, - { - { 4501.060059f, 1990.280029f, 431.157013f, 1.029740f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4463.830078f, 2015.180054f, 430.299988f, 1.431170f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4494.580078f, 1943.760010f, 435.627014f, 6.195920f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4450.149902f, 1897.579956f, 435.045013f, 4.398230f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 4428.870117f, 1906.869995f, 432.648010f, 3.996800f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - 0, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }, -}; - -struct WintergraspTowerCannonData -{ - uint32 towerEntry; - uint8 nbTowerCannonBottom; - Position TowerCannonBottom[5]; - uint8 nbTurretTop; - Position TurretTop[5]; -}; - -const uint8 WG_MAX_TOWER_CANNON = 7; - -const WintergraspTowerCannonData TowerCannon[WG_MAX_TOWER_CANNON] = -{ - { - 190221, - 0, - { - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 2, - { - { 5255.88f, 3047.63f, 438.499f, 3.13677f }, - { 5280.9f, 3071.32f, 438.499f, 1.62879f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, - { - 190373, - 0, - { - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 2, - { - { 5138.59f, 2935.16f, 439.845f, 3.11723f }, - { 5163.06f, 2959.52f, 439.846f, 1.47258f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, - { - 190377, - 0, - { - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 2, - { - { 5163.84f, 2723.74f, 439.844f, 1.3994f }, - { 5139.69f, 2747.4f, 439.844f, 3.17221f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, - { - 190378, - 0, - { - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 2, - { - { 5278.21f, 2607.23f, 439.755f, 4.71944f }, - { 5255.01f, 2631.98f, 439.755f, 3.15257f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, - { - 190356, - 2, - { - {4537.380371f, 3599.531738f, 402.886993f, 3.998462f}, - {4581.497559f, 3604.087158f, 402.886963f, 5.651723f}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - }, - 2, - { - {4469.448242f, 1966.623779f, 465.647217f, 1.153573f}, - {4581.895996f, 3626.438477f, 426.539062f, 0.117806f}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - }, - }, - { - 190357, - 2, - { - { 4421.640137f, 2799.935791f, 412.630920f, 5.459298f }, - { 4420.263184f, 2845.340332f, 412.630951f, 0.742197f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 3, - { - { 4423.430664f, 2822.762939f, 436.283142f, 6.223487f }, - { 4397.825684f, 2847.629639f, 436.283325f, 1.579430f }, - { 4398.814941f, 2797.266357f, 436.283051f, 4.703747f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, - { - 190358, - 2, - { - { 4448.138184f, 1974.998779f, 441.995911f, 1.967238f }, - { 4448.713379f, 1955.148682f, 441.995178f, 0.380733f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - 2, - { - { 4469.448242f, 1966.623779f, 465.647217f, 1.153573f }, - { 4481.996582f, 1933.658325f, 465.647186f, 5.873029f }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - }, - }, -}; - -// ********************************************************* -// *****************WorkShop Data & Element***************** -// ********************************************************* - -struct StaticWintergraspWorkshopInfo -{ - uint8 WorkshopId; - uint32 WorldStateId; - - struct - { - uint8 AllianceCapture; - uint8 AllianceAttack; - uint8 HordeCapture; - uint8 HordeAttack; - } TextIds; -}; - -StaticWintergraspWorkshopInfo const WorkshopData[WG_MAX_WORKSHOP] = -{ - { BATTLEFIELD_WG_WORKSHOP_NE, WORLDSTATE_WORKSHOP_NE, { BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_HORDE } }, - { BATTLEFIELD_WG_WORKSHOP_NW, WORLDSTATE_WORKSHOP_NW, { BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_HORDE } }, - { BATTLEFIELD_WG_WORKSHOP_SE, WORLDSTATE_WORKSHOP_SE, { BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_HORDE } }, - { BATTLEFIELD_WG_WORKSHOP_SW, WORLDSTATE_WORKSHOP_SW, { BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_HORDE } }, - // KEEP WORKSHOPS - It can't be taken, so it doesn't have a textids - { BATTLEFIELD_WG_WORKSHOP_KEEP_WEST, WORLDSTATE_WORKSHOP_K_W, { 0, 0, 0, 0 } }, - { BATTLEFIELD_WG_WORKSHOP_KEEP_EAST, WORLDSTATE_WORKSHOP_K_E, { 0, 0, 0, 0 } } -}; - // ******************************************************************** // * Structs using for Building, Graveyard, Workshop * // ******************************************************************** @@ -1165,15 +623,9 @@ private: public: WintergraspWorkshop(BattlefieldWG* wg, uint8 type); - uint8 GetId() const { return _staticInfo->WorkshopId; } + uint8 GetId() const; TeamId GetTeamControl() const { return _teamControl; } - // Spawning associate creature and store them - void AddCreature(WintergraspObjectPositionData const& obj); - - // Spawning Associate gameobject and store them - void AddGameObject(WintergraspObjectPositionData const& obj); - // Called on change faction in CapturePoint class void GiveControlTo(TeamId teamId, bool init = false); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 2629013585a..a31d73b6dfb 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -107,7 +107,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { "Sit/stand state", true, true, false }, { "Daily Quest Completed",true, false, false }, { "Charmed", false, false, false }, - { "Pet type", true, false, false } + { "Pet type", true, false, false }, + { "On Taxi", false, false, false } }; // Checks if object meets the condition @@ -471,6 +472,12 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const condMeets = (((1 << pet->getPetType()) & ConditionValue1) != 0); break; } + case CONDITION_TAXI: + { + if (Player* player = object->ToPlayer()) + condMeets = player->IsInFlight(); + break; + } default: condMeets = false; break; @@ -653,6 +660,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const case CONDITION_PET_TYPE: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; + case CONDITION_TAXI: + mask |= GRID_MAP_TYPE_MASK_PLAYER; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -2185,6 +2195,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const break; case CONDITION_IN_WATER: case CONDITION_CHARMED: + case CONDITION_TAXI: default: break; } diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 659cec02d37..f4068842765 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -76,7 +76,8 @@ enum ConditionTypes CONDITION_DAILY_QUEST_DONE = 43, // quest id 0 0 true if daily quest has been completed for the day CONDITION_CHARMED = 44, // 0 0 0 true if unit is currently charmed CONDITION_PET_TYPE = 45, // mask 0 0 true if player has a pet of given type(s) - CONDITION_MAX = 46 // MAX + CONDITION_TAXI = 46, // 0 0 0 true if player is on taxi + CONDITION_MAX = 47 // MAX }; /*! Documentation on implementing a new ConditionSourceType: diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index b556fde1705..05ba2211752 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -183,7 +183,7 @@ m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0 m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0) +m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_focusSpell(nullptr), m_focusDelay(0), m_shouldReacquireTarget(false), m_suppressedOrientation(0.0f) { m_regenTimer = CREATURE_REGEN_INTERVAL; m_valuesCount = UNIT_END; @@ -400,7 +400,7 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/) return true; } -bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/) +bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, bool updateLevel /* = true */) { if (!InitEntry(entry, data)) return false; @@ -434,7 +434,8 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/) SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime); SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime); - SelectLevel(); + if (updateLevel) + SelectLevel(); SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool)); CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class); @@ -571,6 +572,19 @@ void Creature::Update(uint32 diff) if (!IsAlive()) break; + if (m_shouldReacquireTarget && !IsFocusing(nullptr, true)) + { + SetTarget(m_suppressedTarget); + if (m_suppressedTarget) + { + if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget)) + SetFacingToObject(objTarget); + } + else + SetFacingTo(m_suppressedOrientation); + m_shouldReacquireTarget = false; + } + // if creature is charmed, switch to charmed AI (and back) if (NeedChangeAI) { @@ -2781,31 +2795,39 @@ void Creature::SetDisplayId(uint32 modelId) void Creature::SetTarget(ObjectGuid guid) { - if (!IsFocusing()) + if (IsFocusing(nullptr, true)) + m_suppressedTarget = guid; + else SetGuidValue(UNIT_FIELD_TARGET, guid); } -bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) +void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // already focused if (m_focusSpell) - return false; + return; + + // don't use spell focus for vehicle spells + if (focusSpell->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE)) + return; if ((!target || target == this) && !focusSpell->GetCastTime()) // instant cast, untargeted (or self-targeted) spell doesn't need any facing updates - return false; + return; - m_focusSpell = focusSpell; + // store pre-cast values for target and orientation (used to later restore) + if (!IsFocusing(nullptr, true)) + { // only overwrite these fields if we aren't transitioning from one spell focus to another + m_suppressedTarget = GetGuidValue(UNIT_FIELD_TARGET); + m_suppressedOrientation = GetOrientation(); + } - // "instant" creature casts that require re-targeting will be delayed by a short moment to prevent facing bugs - bool shouldDelay = false; + m_focusSpell = focusSpell; // set target, then force send update packet to players if it changed to provide appropriate facing ObjectGuid newTarget = target ? target->GetGUID() : ObjectGuid::Empty; if (GetGuidValue(UNIT_FIELD_TARGET) != newTarget) { SetGuidValue(UNIT_FIELD_TARGET, newTarget); - if (target) - SetFacingToObject(target); if ( // here we determine if the (relatively expensive) forced update is worth it, or whether we can afford to wait until the scheduled update tick ( // only require instant update for spells that actually have a visual @@ -2823,28 +2845,21 @@ bool Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // only update players that are known to the client (have already been created) if (player->HaveAtClient(this)) - { SendUpdateToPlayer(player); - shouldDelay = true; - } } - if (shouldDelay) - shouldDelay = !(focusSpell->IsTriggered() || focusSpell->GetCastTime() || focusSpell->GetSpellInfo()->IsChanneled()); } } bool canTurnDuringCast = !focusSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST); // Face the target - we need to do this before the unit state is modified for no-turn spells if (target) - SetInFront(target); + SetFacingTo(GetAngle(target)); else if (!canTurnDuringCast) if (Unit* victim = GetVictim()) - SetInFront(victim); // ensure server-side orientation is correct at beginning of cast + SetFacingTo(GetAngle(victim)); // ensure orientation is correct at beginning of cast if (!canTurnDuringCast) AddUnitState(UNIT_STATE_CANNOT_TURN); - - return shouldDelay; } bool Creature::IsFocusing(Spell const* focusSpell, bool withDelay) @@ -2882,9 +2897,18 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay) return; if (IsPet()) // player pets do not use delay system - SetGuidValue(UNIT_FIELD_TARGET, GetVictim() ? EnsureVictim()->GetGUID() : ObjectGuid::Empty); + { + SetGuidValue(UNIT_FIELD_TARGET, m_suppressedTarget); + if (m_suppressedTarget) + { + if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, m_suppressedTarget)) + SetFacingTo(GetAngle(objTarget)); + } + else + SetFacingTo(m_suppressedOrientation); + } else - // tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Attack) + // tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Update) // player pets don't need to do this, as they automatically reacquire their target on focus release MustReacquireTarget(); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 57a025fdd88..7e8d5e3a9ad 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -501,7 +501,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma bool HasSpell(uint32 spellID) const override; - bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr); + bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr, bool updateLevel = true); void UpdateMovementFlags(); @@ -689,7 +689,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma // Handling caster facing during spellcast void SetTarget(ObjectGuid guid) override; - bool FocusTarget(Spell const* focusSpell, WorldObject const* target); + void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next ::Update call + void FocusTarget(Spell const* focusSpell, WorldObject const* target); bool IsFocusing(Spell const* focusSpell = nullptr, bool withDelay = false); void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true); @@ -765,8 +766,12 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma CreatureGroup* m_formation; bool m_TriggerJustRespawned; - Spell const* m_focusSpell; ///> Locks the target during spell cast for proper facing + /* Spell focus system */ + Spell const* m_focusSpell; // Locks the target during spell cast for proper facing uint32 m_focusDelay; + bool m_shouldReacquireTarget; + ObjectGuid m_suppressedTarget; // Stores the creature's "real" target while casting + float m_suppressedOrientation; // Stores the creature's "real" orientation while casting CreatureTextRepeatGroup m_textRepeat; }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e77e20d323a..dce0d9b6ad7 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14821,7 +14821,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest_id); - SendQuestUpdate(); + SendQuestUpdate(quest_id); if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled { @@ -15071,7 +15071,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, UpdatePvPState(); } - SendQuestUpdate(); + SendQuestUpdate(quest_id); SendQuestGiverStatusMultiple(); @@ -15735,7 +15735,7 @@ void Player::SetQuestStatus(uint32 questId, QuestStatus status, bool update /*= } if (update) - SendQuestUpdate(); + SendQuestUpdate(questId); sScriptMgr->OnQuestStatusChange(this, questId, status); } @@ -15750,7 +15750,7 @@ void Player::RemoveActiveQuest(uint32 questId, bool update /*= true*/) } if (update) - SendQuestUpdate(); + SendQuestUpdate(questId); } void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/) @@ -15763,19 +15763,19 @@ void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/) } if (update) - SendQuestUpdate(); + SendQuestUpdate(questId); } -void Player::SendQuestUpdate() +void Player::SendQuestUpdate(uint32 questId) { uint32 zone = 0, area = 0; GetZoneAndAreaId(zone, area); - SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForAreaMapBounds(area); + SpellAreaForQuestAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestAreaMapBounds(area, questId); if (saBounds.first != saBounds.second) { - for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) + for (SpellAreaForQuestAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { if (!itr->second->IsFitToRequirements(this, zone, area)) RemoveAurasDueToSpell(itr->second->spellId); @@ -17113,7 +17113,10 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { // leave bg if (player_at_bg) + { + player_at_bg = false; currentBg->RemovePlayerAtLeave(GetGUID(), false, true); + } // Do not look for instance if bg not found WorldLocation const& _loc = GetBattlegroundEntryPoint(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1559963ef92..a6af559b519 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1364,7 +1364,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SetQuestStatus(uint32 questId, QuestStatus status, bool update = true); void RemoveActiveQuest(uint32 questId, bool update = true); void RemoveRewardedQuest(uint32 questId, bool update = true); - void SendQuestUpdate(); + void SendQuestUpdate(uint32 questId); QuestGiverStatus GetQuestDialogStatus(Object* questGiver); void SetDailyQuestStatus(uint32 quest_id); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index def6c382893..d1984da9648 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1426,7 +1426,7 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; // Pet's base damage changes depending on happiness - if (IsHunterPet() && attType == BASE_ATTACK) + if (IsHunterPet()) { switch (ToPet()->GetHappinessState()) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6ab10158b3c..e004ef25411 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -247,7 +247,6 @@ Unit::Unit(bool isWorldObject) : m_createStats[i] = 0.0f; m_attacking = nullptr; - m_shouldReacquireTarget = false; m_modMeleeHitChance = 0.0f; m_modRangedHitChance = 0.0f; m_modSpellHitChance = 0.0f; @@ -882,10 +881,6 @@ void Unit::CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo return; } - /// @todo this is a workaround - not needed anymore, but required for some scripts :( - if (!originalCaster && triggeredByAura) - originalCaster = triggeredByAura->GetCasterGUID(); - Spell* spell = new Spell(this, spellInfo, triggerFlags, originalCaster); if (value) @@ -8558,12 +8553,6 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) RemoveAurasByType(SPELL_AURA_MOD_UNATTACKABLE); - if (m_shouldReacquireTarget) - { - SetTarget(victim->GetGUID()); - m_shouldReacquireTarget = false; - } - if (m_attacking) { if (m_attacking == victim) @@ -12731,7 +12720,7 @@ float Unit::GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spell return 0; if (spellInfo->RangeEntry->maxRangeFriend == spellInfo->RangeEntry->maxRangeHostile) return spellInfo->GetMaxRange(); - if (target == NULL) + if (!target) return spellInfo->GetMaxRange(true); return spellInfo->GetMaxRange(!IsHostileTo(target)); } @@ -12742,6 +12731,8 @@ float Unit::GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spell return 0; if (spellInfo->RangeEntry->minRangeFriend == spellInfo->RangeEntry->minRangeHostile) return spellInfo->GetMinRange(); + if (!target) + return spellInfo->GetMinRange(true); return spellInfo->GetMinRange(!IsHostileTo(target)); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8441252bef6..61b7665254b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1300,7 +1300,6 @@ class TC_GAME_API Unit : public WorldObject void _removeAttacker(Unit* pAttacker); // must be called only from Unit::AttackStop() Unit* getAttackerForHelper() const; // If someone wants to help, who to give them bool Attack(Unit* victim, bool meleeAttack); - void MustReacquireTarget() { m_shouldReacquireTarget = true; } // flags the Unit for forced (client displayed) target reacquisition in the next ::Attack call void CastStop(uint32 except_spellid = 0); bool AttackStop(); void RemoveAllAttackers(); @@ -2203,7 +2202,6 @@ class TC_GAME_API Unit : public WorldObject AttackerSet m_attackers; Unit* m_attacking; - bool m_shouldReacquireTarget; DeathState m_deathState; diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index bb8e89d4829..39d55ef784e 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -139,6 +139,9 @@ bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite) if (data.end <= data.start) data.end = data.start + data.length; } + + // When event is started, set its worldstate to current time + sWorld->setWorldState(event_id, time(NULL)); return false; } else @@ -174,6 +177,9 @@ void GameEventMgr::StopEvent(uint16 event_id, bool overwrite) RemoveActiveEvent(event_id); UnApplyEvent(event_id); + // When event is stopped, clean up its worldstate + sWorld->setWorldState(event_id, 0); + if (overwrite && !serverwide_evt) { data.start = time(NULL) - data.length * MINUTE; @@ -1033,6 +1039,8 @@ uint32 GameEventMgr::Update() // return the next e } else { + // If event is inactive, periodically clean up its worldstate + sWorld->setWorldState(itr, 0); //TC_LOG_DEBUG("misc", "GameEvent %u is not active", itr->first); if (IsActiveEvent(itr)) deactivate.insert(itr); @@ -1115,8 +1123,10 @@ void GameEventMgr::ApplyNewEvent(uint16 event_id) UpdateEventNPCVendor(event_id, true); // update bg holiday UpdateBattlegroundSettings(); - // check for seasonal quest reset. - sWorld->ResetEventSeasonalQuests(event_id); + // If event's worldstate is 0, it means the event hasn't been started yet. In that case, reset seasonal quests. + // When event ends (if it expires or if it's stopped via commands) worldstate will be set to 0 again, ready for another seasonal quest reset. + if (sWorld->getWorldState(event_id) == 0) + sWorld->ResetEventSeasonalQuests(event_id); } void GameEventMgr::UpdateEventNPCFlags(uint16 event_id) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 5283805c59d..8304054c663 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -1156,7 +1156,7 @@ namespace Trinity bool operator()(Creature* u) { - if (u->GetEntry() == i_entry && u->IsAlive() == i_alive && i_obj.IsWithinDistInMap(u, i_range)) + if (u->getDeathState() != DEAD && u->GetEntry() == i_entry && u->IsAlive() == i_alive && i_obj.IsWithinDistInMap(u, i_range)) { i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check return true; diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index 55bfb93c1c4..2de9ff2bc46 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -777,7 +777,7 @@ void WorldSession::HandleReportPvPAFK(WorldPacket& recvData) if (!reportedPlayer) { - TC_LOG_INFO("bg.reportpvpafk", "WorldSession::HandleReportPvPAFK: %s [IP: %s] reported %s [IP: %s]", _player->GetName().c_str(), _player->GetSession()->GetRemoteAddress().c_str(), reportedPlayer->GetName().c_str(), reportedPlayer->GetSession()->GetRemoteAddress().c_str()); + TC_LOG_INFO("bg.reportpvpafk", "WorldSession::HandleReportPvPAFK: %s [IP: %s] reported %s", _player->GetName().c_str(), _player->GetSession()->GetRemoteAddress().c_str(), playerGuid.ToString().c_str()); return; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 9545b957c57..ce5d3c9f8a1 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -603,8 +603,6 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO //Auto Shot & Shoot (wand) m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell(); - m_isDelayedInstantCast = false; - m_runesState = 0; m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before. m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before. @@ -2977,21 +2975,9 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (!(IsNextMeleeSwingSpell() || IsAutoRepeat() || _triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) { if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) - { - if (m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget())) - { - m_isDelayedInstantCast = true; - m_timer = 100; // 100ms delay ensures client has updated creature orientation when cast goes off - } - } + m_caster->ToCreature()->FocusTarget(this, m_targets.GetObjectTarget()); else if (m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) - { - if (m_caster->ToCreature()->FocusTarget(this, nullptr)) - { - m_isDelayedInstantCast = true; - m_timer = 100; - } - } + m_caster->ToCreature()->FocusTarget(this, nullptr); } // don't allow channeled spells / spells with cast time to be cast while moving @@ -3034,14 +3020,13 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered } m_caster->SetCurrentCastSpell(this); - if (!m_isDelayedInstantCast) - SendSpellStart(); + SendSpellStart(); if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD)) TriggerGlobalCooldown(); //item: first cast may destroy item and second cast causes crash - if (!m_casttime && !m_isDelayedInstantCast && !m_spellInfo->StartRecoveryTime && !m_castItemGUID && GetCurrentContainer() == CURRENT_GENERIC_SPELL) + if (!m_casttime && !m_spellInfo->StartRecoveryTime && !m_castItemGUID && GetCurrentContainer() == CURRENT_GENERIC_SPELL) cast(true); } } @@ -3050,9 +3035,6 @@ void Spell::cancel() { if (m_spellState == SPELL_STATE_FINISHED) return; - // delayed instant casts are used for client-side visual orientation; they are treated as instant for all intents and purposes server-side, and thus cannot be interrupted by another cast - if (m_isDelayedInstantCast) - return; uint32 oldState = m_spellState; m_spellState = SPELL_STATE_FINISHED; @@ -3122,9 +3104,6 @@ void Spell::cast(bool skipCheck) return; } - if (m_isDelayedInstantCast) - SendSpellStart(); - if (Player* playerCaster = m_caster->ToPlayer()) { // now that we've done the basic check, now run the scripts @@ -3209,10 +3188,7 @@ void Spell::cast(bool skipCheck) if (m_caster->GetTypeId() == TYPEID_UNIT && !m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) if (!m_spellInfo->HasAttribute(SPELL_ATTR5_DONT_TURN_DURING_CAST)) if (WorldObject* objTarget = m_targets.GetObjectTarget()) - { m_caster->SetInFront(objTarget); - m_caster->SetFacingToObject(objTarget); - } SelectSpellTargets(); @@ -4773,7 +4749,7 @@ SpellCastResult Spell::CheckCast(bool strict) // Check global cooldown if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_GCD) && HasGlobalCooldown()) - return SPELL_FAILED_NOT_READY; + return !m_spellInfo->HasAttribute(SPELL_ATTR0_DISABLED_WHILE_ACTIVE) ? SPELL_FAILED_NOT_READY : SPELL_FAILED_DONT_REPORT; // only triggered spells can be processed an ended battleground if (!IsTriggered() && m_caster->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index c834d187720..016af275141 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -527,7 +527,6 @@ class TC_GAME_API Spell int32 m_channeledDuration; // Calculated channeled spell duration in order to calculate correct pushback. bool m_canReflect; // can reflect this spell? bool m_autoRepeat; - bool m_isDelayedInstantCast; // whether this is a creature's delayed instant cast uint8 m_runesState; uint8 m_delayAtDamageCount; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ed0d95f0a58..be2d11fdf52 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -1125,6 +1125,11 @@ SpellAreaForAreaMapBounds SpellMgr::GetSpellAreaForAreaMapBounds(uint32 area_id) return mSpellAreaForAreaMap.equal_range(area_id); } +SpellAreaForQuestAreaMapBounds SpellMgr::GetSpellAreaForQuestAreaMapBounds(uint32 area_id, uint32 quest_id) const +{ + return mSpellAreaForQuestAreaMap.equal_range(std::pair<uint32, uint32>(area_id, quest_id)); +} + bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const { if (gender != GENDER_NONE) // is not expected gender @@ -2720,6 +2725,12 @@ void SpellMgr::LoadSpellAreas() if (spellArea.auraSpell) mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa)); + if (spellArea.areaId && spellArea.questStart) + mSpellAreaForQuestAreaMap.insert(SpellAreaForQuestAreaMap::value_type(std::pair<uint32, uint32>(spellArea.areaId, spellArea.questStart), sa)); + + if (spellArea.areaId && spellArea.questEnd) + mSpellAreaForQuestAreaMap.insert(SpellAreaForQuestAreaMap::value_type(std::pair<uint32, uint32>(spellArea.areaId, spellArea.questEnd), sa)); + ++count; } while (result->NextRow()); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 75da933636c..23329c1ff1e 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -509,10 +509,12 @@ typedef std::multimap<uint32, SpellArea> SpellAreaMap; typedef std::multimap<uint32, SpellArea const*> SpellAreaForQuestMap; typedef std::multimap<uint32, SpellArea const*> SpellAreaForAuraMap; typedef std::multimap<uint32, SpellArea const*> SpellAreaForAreaMap; +typedef std::multimap<std::pair<uint32, uint32>, SpellArea const*> SpellAreaForQuestAreaMap; typedef std::pair<SpellAreaMap::const_iterator, SpellAreaMap::const_iterator> SpellAreaMapBounds; typedef std::pair<SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator> SpellAreaForQuestMapBounds; typedef std::pair<SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator> SpellAreaForAuraMapBounds; typedef std::pair<SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator> SpellAreaForAreaMapBounds; +typedef std::pair<SpellAreaForQuestAreaMap::const_iterator, SpellAreaForQuestAreaMap::const_iterator> SpellAreaForQuestAreaMapBounds; // Spell rank chain (accessed using SpellMgr functions) struct SpellChainNode @@ -688,6 +690,7 @@ class TC_GAME_API SpellMgr SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const; SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const; SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const; + SpellAreaForQuestAreaMapBounds GetSpellAreaForQuestAreaMapBounds(uint32 area_id, uint32 quest_id) const; // SpellInfo object management SpellInfo const* GetSpellInfo(uint32 spellId) const { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } @@ -759,6 +762,7 @@ class TC_GAME_API SpellMgr SpellAreaForQuestMap mSpellAreaForQuestEndMap; SpellAreaForAuraMap mSpellAreaForAuraMap; SpellAreaForAreaMap mSpellAreaForAreaMap; + SpellAreaForQuestAreaMap mSpellAreaForQuestAreaMap; SkillLineAbilityMap mSkillLineAbilityMap; PetLevelupSpellMap mPetLevelupSpellMap; PetDefaultSpellsMap mPetDefaultSpellsMap; // only spells not listed in related mPetLevelupSpellMap entry diff --git a/src/server/scripts/Commands/cs_cheat.cpp b/src/server/scripts/Commands/cs_cheat.cpp index 0adff61c9ec..af78eaf3a3b 100644 --- a/src/server/scripts/Commands/cs_cheat.cpp +++ b/src/server/scripts/Commands/cs_cheat.cpp @@ -246,7 +246,6 @@ public: if (!*args) return false; - // std::int flag = (char*)args; int flag = atoi((char*)args); Player* chr = handler->getSelectedPlayer(); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 3cf78b79f67..95082a4268a 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -1023,7 +1023,6 @@ class npc_scarlet_miner_cart : public CreatureScript { npc_scarlet_miner_cartAI(Creature* creature) : PassiveAI(creature) { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); // Modelid2 is a horse. } diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp index 68391c65655..eb4db03e20a 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp @@ -98,7 +98,7 @@ class boss_archaedas : public CreatureScript instance->SetData(0, 5); // respawn any dead minions me->setFaction(35); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); me->AddAura(SPELL_FREEZE_ANIM, me); } @@ -111,7 +111,7 @@ class boss_archaedas : public CreatureScript DoCast(minion, SPELL_AWAKEN_VAULT_WALKER, flag); minion->CastSpell(minion, SPELL_ARCHAEDAS_AWAKEN, true); minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + minion->SetControlled(false, UNIT_STATE_ROOT); minion->setFaction(14); minion->RemoveAura(SPELL_MINION_FREEZE_ANIM); } @@ -121,7 +121,7 @@ class boss_archaedas : public CreatureScript { me->setFaction(14); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(false, UNIT_STATE_ROOT); } void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override @@ -261,7 +261,7 @@ class npc_archaedas_minions : public CreatureScript me->setFaction(35); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); me->RemoveAllAuras(); me->AddAura(SPELL_MINION_FREEZE_ANIM, me); } @@ -270,8 +270,8 @@ class npc_archaedas_minions : public CreatureScript { me->setFaction (14); me->RemoveAllAuras(); - me->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_ROOT); bAmIAwake = true; } @@ -350,7 +350,7 @@ class npc_stonekeepers : public CreatureScript { me->setFaction(35); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); me->RemoveAllAuras(); me->AddAura(SPELL_MINION_FREEZE_ANIM, me); } @@ -359,7 +359,7 @@ class npc_stonekeepers : public CreatureScript { me->setFaction(14); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(false, UNIT_STATE_ROOT); } void UpdateAI(uint32 /*diff*/) override diff --git a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp index 28a3a4eb4e0..604174a8935 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp @@ -147,7 +147,7 @@ class instance_uldaman : public InstanceMapScript creature->setFaction(35); creature->RemoveAllAuras(); creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + creature->SetControlled(true, UNIT_STATE_ROOT); creature->AddAura(SPELL_MINION_FREEZE_ANIM, creature); } @@ -178,7 +178,7 @@ class instance_uldaman : public InstanceMapScript Creature* target = instance->GetCreature(*i); if (!target || !target->IsAlive()) continue; - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + target->SetControlled(false, UNIT_STATE_ROOT); target->setFaction(14); target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); target->RemoveAura(SPELL_MINION_FREEZE_ANIM); @@ -202,7 +202,7 @@ class instance_uldaman : public InstanceMapScript Creature* target = instance->GetCreature(*i); if (!target || !target->IsAlive() || target->getFaction() == 14) continue; - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + target->SetControlled(false, UNIT_STATE_ROOT); target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); target->setFaction(14); target->RemoveAura(SPELL_MINION_FREEZE_ANIM); @@ -268,7 +268,7 @@ class instance_uldaman : public InstanceMapScript return; ironaya->setFaction(415); - ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + ironaya->SetControlled(false, UNIT_STATE_ROOT); ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); ironaya->GetMotionMaster()->Clear(); diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index 2df0fceab9c..95335393942 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -156,7 +156,8 @@ public: ImpaleTarget = impaleTarget->GetGUID(); impaleTarget->SetReactState(REACT_PASSIVE); impaleTarget->SetDisplayId(DISPLAY_INVISIBLE); - impaleTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + impaleTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + impaleTarget->SetControlled(true, UNIT_STATE_ROOT); return impaleTarget; } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index b2283ec6fde..69a9e354660 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -646,7 +646,7 @@ struct boss_jormungarAI : public BossAI // if the worm was mobile before submerging, make him stationary now if (WasMobile) { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); SetCombatMovement(false); me->SetDisplayId(ModelStationary); me->CastSpell(me, SPELL_GROUND_VISUAL_1, true); @@ -658,7 +658,7 @@ struct boss_jormungarAI : public BossAI } else { - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(false, UNIT_STATE_ROOT); SetCombatMovement(true); me->GetMotionMaster()->MoveChase(me->GetVictim()); me->SetDisplayId(ModelMobile); @@ -1023,7 +1023,8 @@ class boss_icehowl : public CreatureScript me->SetTarget(_trampleTargetGUID); _trampleCast = false; SetCombatMovement(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetControlled(true, UNIT_STATE_ROOT); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); events.ScheduleEvent(EVENT_TRAMPLE, 4*IN_MILLISECONDS); @@ -1107,7 +1108,8 @@ class boss_icehowl : public CreatureScript Talk(EMOTE_TRAMPLE_FAIL); } _movementStarted = false; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetControlled(false, UNIT_STATE_ROOT); SetCombatMovement(true); me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->Clear(); diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp index 94d1d93225c..e49f7044c0a 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp @@ -144,7 +144,7 @@ class boss_devourer_of_souls : public CreatureScript void Reset() override { _Reset(); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(false, UNIT_STATE_ROOT); me->SetDisplayId(DISPLAY_ANGER); me->SetReactState(REACT_AGGRESSIVE); @@ -297,7 +297,7 @@ class boss_devourer_of_souls : public CreatureScript me->SetTarget(ObjectGuid::Empty); me->GetMotionMaster()->Clear(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); wailingSoulTick = 15; events.DelayEvents(18000); // no other events during wailing souls @@ -317,7 +317,7 @@ class boss_devourer_of_souls : public CreatureScript { me->SetReactState(REACT_AGGRESSIVE); me->SetDisplayId(DISPLAY_ANGER); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(false, UNIT_STATE_ROOT); me->GetMotionMaster()->MoveChase(me->GetVictim()); events.ScheduleEvent(EVENT_WAILING_SOULS, urand(60000, 70000)); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 42efdfbfe67..2452385b97c 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -16,27 +16,19 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_KelThuzad -SD%Complete: 80% -SDComment: VERIFY SCRIPT -SDCategory: Naxxramas -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" #include "naxxramas.h" -#include "Player.h" +#include "PlayerAI.h" enum Texts { SAY_AGGRO = 7, SAY_SLAY = 8, SAY_DEATH = 9, - SAY_CHAIN = 10, - SAY_FROST_BLAST = 11, + SAY_CHAINS = 10, SAY_REQUEST_AID = 12, //start of phase 3 EMOTE_PHASE_TWO = 13, SAY_SUMMON_MINIONS = 14, //start of phase 1 @@ -45,219 +37,165 @@ enum Texts // The Lich King SAY_ANSWER_REQUEST = 3, - // Old World Trigger - SAY_GUARDIAN_SPAWNED = 0 + // Guardian of Icecrown + EMOTE_GUARDIAN_FLEE = 0, + EMOTE_GUARDIAN_APPEAR = 1 }; enum Events { - EVENT_NONE, - EVENT_BOLT, - EVENT_NOVA, - EVENT_CHAIN, - EVENT_CHAINED_SPELL, - EVENT_DETONATE, - EVENT_FISSURE, - EVENT_BLAST, - - EVENT_WASTE, - EVENT_ABOMIN, - EVENT_WEAVER, - EVENT_ICECROWN, - EVENT_TRIGGER, - - EVENT_PHASE, - EVENT_MORTAL_WOUND, - - EVENT_ANSWER_REQUEST, - EVENT_SUMMON_GUARDIANS + // phase one + EVENT_SKELETON = 1, + EVENT_BANSHEE, + EVENT_ABOMINATION, + EVENT_DESPAWN_MINIONS, + EVENT_PHASE_TWO, + + // phase two + EVENT_FROSTBOLT_VOLLEY, + EVENT_SHADOW_FISSURE, + EVENT_DETONATE_MANA, + EVENT_FROST_BLAST, + EVENT_CHAINS, + + // phase three transition + EVENT_TRANSITION_REPLY, + EVENT_TRANSITION_SUMMON, }; -enum Spells +enum Actions { - SPELL_FROST_BOLT = 28478, - SPELL_FROST_BOLT_AOE = 28479, - SPELL_SHADOW_FISURE = 27810, - SPELL_VOID_BLAST = 27812, - SPELL_MANA_DETONATION = 27819, - SPELL_MANA_DETONATION_DAMAGE = 27820, - SPELL_FROST_BLAST = 27808, - SPELL_CHAINS_OF_KELTHUZAD = 28410, //28408 script effect - SPELL_KELTHUZAD_CHANNEL = 29423, - SPELL_BERSERK = 28498, - - //spells for chained - //warlock - SPELL_CURSE_OF_AGONY = 47864, - SPELL_SHADOW_BOLT = 47809, - //shaman - SPELL_EARTH_SHOCK = 49231, - SPELL_HEALING_WAVE = 49273, - //mage - SPELL_FROST_FIREBOLT = 47610, - SPELL_ARCANE_MISSILES = 42846, - //rogue - SPELL_HEMORRHAGE = 48660, - SPELL_MUTILATE = 48666, - //paladin - SPELL_HOLY_SHOCK = 48825, - SPELL_HAMMER_OF_JUSTICE = 10308, - //priest - SPELL_VAMPIRIC_TOUCH = 48160, - SPELL_RENEW = 48068, - //hunter - SPELL_MULTI_SHOT = 49048, - SPELL_VOLLEY = 58434, - //warrior - SPELL_BLADESTORM = 46924, - SPELL_CLEAVE = 47520, - //druid - SPELL_MOONFIRE = 48463, - SPELL_LIFEBLOOM = 48451, - //death knight - SPELL_PLAGUE_STRIKE = 49921, - SPELL_HOWLING_BLAST = 51411, - - // Abomination spells - SPELL_FRENZY = 28468, - SPELL_MORTAL_WOUND = 28467 + ACTION_BEGIN_ENCOUNTER, + ACTION_JUST_SUMMONED, + ACTION_ABOMINATION_DIED, + ACTION_KELTHUZAD_DIED }; -enum Phases +enum KTData { - PHASE_ONE = 1, // Players move in the circle and Kel'Thuzad spawns his minions. - PHASE_TWO = 2, // Starts on a timer. - PHASE_THREE = 3 // At 45% health. + DATA_MINION_POCKET_ID, + DATA_ABOMINATION_DEATH_COUNT }; -enum Creatures +enum Spells { - NPC_WASTE = 16427, // Soldiers of the Frozen Wastes - NPC_ABOMINATION = 16428, // Unstoppable Abominations - NPC_WEAVER = 16429, // Soul Weavers - NPC_ICECROWN = 16441 // Guardians of Icecrown + // Kel'thuzad - Phase one + SPELL_VISUAL_CHANNEL = 29423, // channeled throughout phase one + + // Kel'thuzad - Phase two + SPELL_FROSTBOLT_SINGLE = 28478, + SPELL_FROSTBOLT_VOLLEY = 28479, + SPELL_SHADOW_FISSURE = 27810, + SPELL_DETONATE_MANA = 27819, + SPELL_MANA_DETONATION_DAMAGE = 27820, + SPELL_FROST_BLAST = 27808, + SPELL_CHAINS = 28410, + SPELL_CHAINS_DUMMY = 28408, // this holds the category cooldown - the main chains spell can't have one as it is cast multiple times + + SPELL_BERSERK = 28498, + + // Unstoppable Abomination + SPELL_MORTAL_WOUND = 28467, + + // Guardian of Icecrown + SPELL_BLOOD_TAP = 28470 }; -Position const Pos[12] = +static const uint8 nGuardianSpawns = 4; +static const uint8 nMinionGroups = 7; +enum SummonGroups { - {3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, //LEFT_FAR - {3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, //LEFT_MIDDLE - {3757.6f, -5172.0f, 143.7f, 1.97f}, //WINDOW_PORTAL05 - {3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, //RIGHT_FAR - {3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, //RIGHT_MIDDLE - {3700.86f, -5181.29f, 143.928024f, 1.42f}, //WINDOW_PORTAL04 - {3754.431396f, -5080.727734f, 142.036316f, 3.736189f}, //LEFT_FAR - {3724.396484f, -5061.330566f, 142.032700f, 4.564785f}, //LEFT_MIDDLE - {3732.02f, -5028.53f, 143.92f, 4.49f}, //WINDOW_PORTAL02 - {3687.571777f, -5126.831055f, 142.017807f, 0.604023f}, //RIGHT_FAR - {3707.990733f, -5151.450195f, 142.032562f, 1.376855f}, //RIGHT_MIDDLE - {3782.76f, -5062.97f, 143.79f, 3.82f} //WINDOW_PORTAL03 + SUMMON_GROUP_GUARDIAN_FIRST = 01 /*..04 */, + SUMMON_GROUP_MINION_FIRST = 05 /*..11 */ }; +static const std::initializer_list<Data64> portalList = { DATA_KELTHUZAD_PORTAL01, DATA_KELTHUZAD_PORTAL02, DATA_KELTHUZAD_PORTAL03, DATA_KELTHUZAD_PORTAL04 }; -//creatures in corners -//Unstoppable Abominations -#define MAX_ABOMINATIONS 21 -Position const PosAbominations[MAX_ABOMINATIONS] = +enum Phases { - {3755.52f, -5155.22f, 143.480f, 2.0f}, - {3744.35f, -5164.03f, 143.590f, 2.00f}, - {3749.28f, -5159.04f, 143.190f, 2.0f}, - {3774.47f, -5076.28f, 143.528f, 2.15912f}, - {3765.94f, -5074.15f, 143.186f, 3.77233f}, - {3763.15f, -5063.36f, 143.694f, 3.77233f}, - {3737.81f, -5045.69f, 143.709f, 4.9033f}, - {3728.13f, -5045.01f, 143.355f, 1.45069f}, - {3721.56f, -5048.35f, 143.542f, 1.45069f}, - {3689.55f, -5049.66f, 143.637f, 5.2104f}, - {3681.71f, -5053.03f, 143.242f, 2.47957f}, - {3677.64f, -5061.44f, 143.358f, 2.47957f}, - {3654.2f, -5090.87f, 143.469f, 1.0313f}, - {3650.39f, -5097.45f, 143.496f, 2.5047f}, - {3658.7f, -5103.59f, 143.607f, 3.3278f}, - {3659.02f, -5133.97f, 143.624f, 3.84538f}, - {3666.33f, -5139.34f, 143.183f, 3.84538f}, - {3669.74f, -5149.63f, 143.678f, 0.528643f}, - {3695.53f, -5169.53f, 143.671f, 2.11908f}, - {3701.98f, -5166.51f, 143.395f, 1.24257f}, - {3709.62f, -5169.15f, 143.576f, 5.97695f} + PHASE_ONE = 1, + PHASE_TWO = 2 // "phase three" is not actually a phase in events, as timers from phase two carry over }; -//Soldiers of the Frozen Wastes -#define MAX_WASTES 49 -Position const PosWastes[MAX_WASTES] = +enum Movements { - {3754.41f, -5147.24f, 143.204f, 2.0f}, - {3754.68f, -5156.17f, 143.418f, 2.0f}, - {3757.91f, -5160.12f, 143.503f, 2.0f}, - {3752.67f, -5164.6f, 143.395f, 2.0f}, - {3745.42f, -5164.47f, 143.565f, 2.74587f}, - {3741.2f, -5155.92f, 143.17f, 5.29134f}, - {3746.57f, -5148.82f, 143.176f, 5.07772f}, - {3778.14f, -5070.1f, 143.568f, 3.16208f}, - {3775.09f, -5078.97f, 143.65f, 2.81022f}, - {3773.54f, -5083.47f, 143.758f, 3.21549f}, - {3765, -5078.29f, 143.176f, 4.36688f}, - {3766.94f, -5072.63f, 143.184f, 5.27951f}, - {3762.68f, -5064.94f, 143.635f, 3.95297f}, - {3769.9f, -5059.94f, 143.74f, 3.36549f}, - {3736.33f, -5042.18f, 143.643f, 5.9471f}, - {3727.51f, -5040.58f, 143.502f, 0.871859f}, - {3719.89f, -5049.64f, 143.58f, 4.75172f}, - {3720.69f, -5044.43f, 143.662f, 1.87245f}, - {3725.69f, -5048.99f, 143.363f, 2.48271f}, - {3732.33f, -5054.01f, 143.44f, 3.59405f}, - {3738.09f, -5051.06f, 143.718f, 4.70931f}, - {3682.76f, -5063.5f, 143.175f, 0.636238f}, - {3686.7f, -5060.58f, 143.18f, 0.636238f}, - {3682.45f, -5057.21f, 143.184f, 5.61252f}, - {3677.57f, -5053.34f, 143.369f, 1.52531f}, - {3677.3f, -5062.26f, 143.369f, 2.73482f}, - {3691.21f, -5053.02f, 143.421f, 5.93218f}, - {3685.22f, -5053.34f, 143.314f, 4.70303f}, - {3652.11f, -5088.47f, 143.555f, 0.793317f}, - {3648.23f, -5093.21f, 143.311f, 1.18837f}, - {3648.14f, -5100.11f, 143.632f, 2.12221f}, - {3653.88f, -5099.7f, 143.558f, 3.04348f}, - {3661.23f, -5100.33f, 143.42f, 4.08335f}, - {3663.49f, -5092.77f, 143.346f, 4.47134f}, - {3661.85f, -5087.99f, 143.571f, 1.0148f}, - {3664.56f, -5149.01f, 143.532f, 0.0762528f}, - {3665.01f, -5142.04f, 143.201f, 1.72009f}, - {3671.15f, -5142.92f, 143.174f, 4.81535f}, - {3670.18f, -5134.38f, 143.177f, 5.37534f}, - {3664.33f, -5131.69f, 143.262f, 5.39576f}, - {3658.21f, -5133.63f, 143.662f, 1.3863f}, - {3659.7f, -5144.49f, 143.363f, 2.32328f}, - {3705.71f, -5179.63f, 143.746f, 1.06743f}, - {3696.77f, -5177.45f, 143.759f, 5.36748f}, - {3700.97f, -5173.13f, 143.52f, 3.26575f}, - {3708.53f, -5172.19f, 143.573f, 3.26575f}, - {3712.49f, -5167.62f, 143.657f, 5.63295f}, - {3704.89f, -5161.84f, 143.239f, 5.63295f}, - {3695.66f, -5164.63f, 143.674f, 1.54416f} + MOVEMENT_MINION_RANDOM = 1, }; -//Soul Weavers -#define MAX_WEAVERS 7 -Position const PosWeavers[MAX_WEAVERS] = +enum Creatures { - {3752.45f, -5168.35f, 143.562f, 1.6094f}, - {3772.2f, -5070.04f, 143.329f, 1.93686f}, - {3732.28f, -5032.88f, 143.771f, 3.08355f}, - {3689.05f, -5055.7f, 143.172f, 6.09554f}, - {3649.45f, -5093.17f, 143.299f, 2.51805f}, - {3659.7f, -5144.49f, 143.363f, 4.08806f}, - {3704.71f, -5175.96f, 143.597f, 3.36549f} + NPC_SKELETON1 = 16427, // Soldiers of the Frozen Wastes + NPC_SKELETON2 = 23561, + NPC_ABOMINATION1 = 16428, // Unstoppable Abominations + NPC_ABOMINATION2 = 23562, + NPC_BANSHEE1 = 16429, // Soul Weavers + NPC_BANSHEE2 = 23563, + NPC_GUARDIAN = 16441 // Guardians of Icecrown +}; + +static const uint8 nMinionSpawnPoints = 7; +static const Position minionSpawnPoints[nMinionSpawnPoints] = { + { 3768.40f, -5072.00f, 143.65f }, // summon group 5 + { 3729.30f, -5044.10f, 143.65f }, // summon group 6 + { 3683.00f, -5054.05f, 143.65f }, // summon group 7 + { 3654.15f, -5093.48f, 143.65f }, // summon group 8 + { 3664.55f, -5140.50f, 143.65f }, // summon group 9 + { 3704.00f, -5170.00f, 143.65f }, // summon group 10 + { 3751.95f, -5158.90f, 143.65f } // summon group 11 }; +static inline Position const& GetRandomMinionSpawnPoint() +{ + return minionSpawnPoints[urand(0, nMinionSpawnPoints - 1)]; +} + +// uniformly distribute on the circle +static Position GetRandomPositionOnCircle(Position const& center, float radius) +{ + double angle = rand_norm() * M_2_PI; + double relDistance = rand_norm() + rand_norm(); + if (relDistance > 1) + relDistance = 1 - relDistance; + return Position(center.GetPositionX() + std::sin(angle)*relDistance*radius, center.GetPositionY() + std::cos(angle)*relDistance*radius, center.GetPositionZ()); +} -// predicate function to select not charmed target -struct NotCharmedTargetSelector : public std::unary_function<Unit*, bool> +class KelThuzadCharmedPlayerAI : public SimpleCharmedPlayerAI { - NotCharmedTargetSelector() { } + public: + KelThuzadCharmedPlayerAI(Player* player) : SimpleCharmedPlayerAI(player) { } + + struct CharmedPlayerTargetSelectPred : public std::unary_function<Unit*, bool> + { + bool operator()(Unit const* target) const + { + Player const* pTarget = target->ToPlayer(); + if (!pTarget) + return false; + if (pTarget->HasAura(SPELL_CHAINS)) + return false; + if (pTarget->HasBreakableByDamageCrowdControlAura()) + return false; + // We _really_ dislike healers. So we hit them in the face. Repeatedly. Exclusively. + return PlayerAI::IsPlayerHealer(pTarget); + } + }; + + Unit* SelectAttackTarget() const override + { + if (Creature* charmer = GetCharmer()) + { + if (Unit* target = charmer->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, CharmedPlayerTargetSelectPred())) + return target; + if (Unit* target = charmer->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_CHAINS)) + return target; + } + return nullptr; + } +}; +struct ManaUserTargetSelector : public std::unary_function<Unit*, bool> +{ bool operator()(Unit const* target) const { - return !target->IsCharmed(); + return target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() == POWER_MANA; } }; @@ -268,355 +206,362 @@ public: struct boss_kelthuzadAI : public BossAI { - boss_kelthuzadAI(Creature* creature) : BossAI(creature, BOSS_KELTHUZAD), spawns(creature) - { - Initialize(); - uiFaction = me->getFaction(); - } - - void Initialize() - { - nGuardiansOfIcecrownCount = 0; - - nAbomination = 0; - nWeaver = 0; - } - - uint32 uiFaction; - - uint8 nGuardiansOfIcecrownCount; - uint8 nAbomination; - uint8 nWeaver; - - std::map<ObjectGuid, float> chained; - - SummonList spawns; // adds spawn by the trigger. kept in separated list (i.e. not in summons) - - void ResetPlayerScale() - { - std::map<ObjectGuid, float>::const_iterator itr; - for (itr = chained.begin(); itr != chained.end(); ++itr) + public: + boss_kelthuzadAI(Creature* creature) : BossAI(creature, BOSS_KELTHUZAD), _skeletonCount(0), _bansheeCount(0), _abominationCount(0), _abominationDeathCount(0), _frostboltCooldown(0), _phaseThree(false), _guardianCount(0) { - if (Player* charmed = ObjectAccessor::GetPlayer(*me, itr->first)) - charmed->SetObjectScale(itr->second); + for (uint8 i = 0; i < nGuardianSpawns; ++i) + _guardianGroups[i] = SUMMON_GROUP_GUARDIAN_FIRST + i; } - chained.clear(); - } - - void Reset() override - { - _Reset(); - - me->setFaction(35); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NOT_SELECTABLE); - - ResetPlayerScale(); - spawns.DespawnAll(); - - instance->SetData(DATA_ABOMINATION_KILLED, 0); - - if (GameObject* trigger = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_TRIGGER))) + void Reset() override { - trigger->ResetDoorOrButton(); - trigger->SetPhaseMask(1, true); + if (!me->IsAlive()) + return; + _Reset(); + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE); + _skeletonCount = 0; + _bansheeCount = 0; + _abominationCount = 0; + _abominationDeathCount = 0; + _phaseThree = false; } - - for (uint8 i = 0; i <= 3; ++i) + void EnterEvadeMode(EvadeReason /*why*/) override { - if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i))) - if (!((portal->getLootState() == GO_READY) || (portal->getLootState() == GO_NOT_READY))) - portal->ResetDoorOrButton(); - } + for (Data64 portalData : portalList) + if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(portalData))) + portal->SetGoState(GO_STATE_READY); - Initialize(); - } + Reset(); + _DespawnAtEvade(); + } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + void JustSummoned (Creature* summon) override + { // prevent DoZoneInCombat + summons.Summon(summon); + } - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - Talk(SAY_DEATH); + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } - ResetPlayerScale(); - } + void JustDied(Unit* /*killer*/) override + { + SummonList::iterator it = summons.begin(); + while (it != summons.end()) + if (Creature* cSummon = ObjectAccessor::GetCreature(*me, *it)) + { + if (cSummon->IsAlive() && cSummon->GetEntry() == NPC_GUARDIAN) + { + cSummon->AI()->DoAction(ACTION_KELTHUZAD_DIED); + it = summons.erase(it); // prevent them from being despawned by _JustDied + } + else + ++it; + } - void EnterCombat(Unit* /*who*/) override - { - me->setFaction(uiFaction); - _EnterCombat(); - for (uint8 i = 0; i <= 3; ++i) + _JustDied(); + Talk(SAY_DEATH); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i))) - portal->ResetDoorOrButton(); + if (events.IsInPhase(PHASE_ONE)) + damage = 0; } - DoCast(me, SPELL_KELTHUZAD_CHANNEL, false); - Talk(SAY_SUMMON_MINIONS); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NOT_SELECTABLE); - me->SetFloatValue(UNIT_FIELD_COMBATREACH, 4); - me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 4); - events.SetPhase(PHASE_ONE); - events.ScheduleEvent(EVENT_TRIGGER, 5000); - events.ScheduleEvent(EVENT_WASTE, 15000); - events.ScheduleEvent(EVENT_ABOMIN, 30000); - events.ScheduleEvent(EVENT_WEAVER, 50000); - events.ScheduleEvent(EVENT_PHASE, 228000); - } - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (events.IsInPhase(PHASE_TWO) && me->HealthBelowPctDamaged(45, damage)) + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override { - Talk(SAY_REQUEST_AID); - events.SetPhase(PHASE_THREE); - events.ScheduleEvent(EVENT_ANSWER_REQUEST, 4000); - - for (uint8 i = 0; i <= 3; ++i) + if (spell->Id == SPELL_CHAINS_DUMMY) { - if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i))) - if (portal->getLootState() == GO_READY) - portal->UseDoorOrButton(); + Talk(SAY_CHAINS); + std::list<Unit*> targets; + SelectTargetList(targets, 3, SELECT_TARGET_RANDOM, 0.0f, true); + for (Unit* target : targets) + if (me->GetVictim() != target) // skip MT + DoCast(target, SPELL_CHAINS); } } - } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - events.Update(diff); + events.Update(diff); - if (events.IsInPhase(PHASE_ONE)) - { - while (uint32 eventId = events.ExecuteEvent()) + if (_frostboltCooldown < diff) + _frostboltCooldown = 0; + else + _frostboltCooldown -= diff; + + if (!events.IsInPhase(PHASE_ONE) && me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!_phaseThree && HealthBelowPct(45)) { - switch (eventId) + _phaseThree = true; + _guardianCount = 0; + Talk(SAY_REQUEST_AID); + events.ScheduleEvent(EVENT_TRANSITION_REPLY, Seconds(4), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSITION_SUMMON, randtime(Seconds(7), Seconds(9)), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSITION_SUMMON, randtime(Seconds(13), Seconds(15)), 0, PHASE_TWO); + if (Is25ManRaid()) { - case EVENT_WASTE: - DoSummon(NPC_WASTE, Pos[RAND(0, 3, 6, 9)]); - events.Repeat(2000, 5000); - break; - case EVENT_ABOMIN: - if (nAbomination < 8) - { - DoSummon(NPC_ABOMINATION, Pos[RAND(1, 4, 7, 10)]); - nAbomination++; - events.Repeat(20000); - } - break; - case EVENT_WEAVER: - if (nWeaver < 8) - { - DoSummon(NPC_WEAVER, Pos[RAND(0, 3, 6, 9)]); - nWeaver++; - events.Repeat(25000); - } - break; - case EVENT_TRIGGER: - if (GameObject* trigger = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_TRIGGER))) - trigger->SetPhaseMask(2, true); - break; - case EVENT_PHASE: - events.Reset(); - Talk(SAY_AGGRO); - Talk(EMOTE_PHASE_TWO); - spawns.DespawnAll(); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NOT_SELECTABLE); - me->CastStop(); - - DoStartMovement(me->GetVictim()); - events.ScheduleEvent(EVENT_BOLT, urand(5000, 10000)); - events.ScheduleEvent(EVENT_NOVA, 15000); - events.ScheduleEvent(EVENT_DETONATE, urand(30000, 40000)); - events.ScheduleEvent(EVENT_FISSURE, urand(10000, 30000)); - events.ScheduleEvent(EVENT_BLAST, urand(60000, 120000)); - if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) - events.ScheduleEvent(EVENT_CHAIN, urand(30000, 60000)); - events.SetPhase(PHASE_TWO); - break; - default: - break; + events.ScheduleEvent(EVENT_TRANSITION_SUMMON, randtime(Seconds(19), Seconds(21)), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSITION_SUMMON, randtime(Seconds(25), Seconds(27)), 0, PHASE_TWO); } } - } - else - { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - if (uint32 eventId = events.ExecuteEvent()) + while (uint32 eventId = events.ExecuteEvent()) { + if (_frostboltCooldown <= 4 * IN_MILLISECONDS) // stop casting bolts for 4 seconds after doing another action + _frostboltCooldown = 4 * IN_MILLISECONDS; switch (eventId) { - case EVENT_BOLT: - DoCastVictim(SPELL_FROST_BOLT); - events.Repeat(5000, 10000); - break; - case EVENT_NOVA: - DoCastAOE(SPELL_FROST_BOLT_AOE); - events.Repeat(15000, 30000); - break; - case EVENT_CHAIN: + case EVENT_SKELETON: { - uint32 count = urand(1, 3); - for (uint8 i = 1; i <= count; i++) + ++_skeletonCount; + if (_skeletonCount == 1) // the first skeleton is actually one of the pre-existing ones - I'm not sure why, but that's what the sniffs say { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true); - if (target && !target->IsCharmed() && (chained.find(target->GetGUID()) == chained.end())) - { - DoCast(target, SPELL_CHAINS_OF_KELTHUZAD); - float scale = target->GetObjectScale(); - chained.insert(std::make_pair(target->GetGUID(), scale)); - target->SetObjectScale(scale * 2); - events.ScheduleEvent(EVENT_CHAINED_SPELL, 2000); //core has 2000ms to set unit flag charm + std::list<Creature*> skeletons; + me->GetCreatureListWithEntryInGrid(skeletons, NPC_SKELETON2, 200.0f); + if (skeletons.empty()) + { // prevent UB + EnterEvadeMode(EVADE_REASON_OTHER); + return; } + std::list<Creature*>::iterator it = skeletons.begin(); + std::advance(it, urand(0, skeletons.size() - 1)); + (*it)->SetReactState(REACT_AGGRESSIVE); + (*it)->AI()->DoZoneInCombat(); // will select a player on our threat list as we are the summoner } - if (!chained.empty()) - Talk(SAY_CHAIN); - events.Repeat(100000, 180000); - break; - } - case EVENT_CHAINED_SPELL: - { - std::map<ObjectGuid, float>::iterator itr; - for (itr = chained.begin(); itr != chained.end();) + else { - if (Unit* player = ObjectAccessor::GetPlayer(*me, itr->first)) - { - if (!player->IsCharmed()) - { - player->SetObjectScale(itr->second); - std::map<ObjectGuid, float>::iterator next = itr; - ++next; - chained.erase(itr); - itr = next; - continue; - } - - if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, NotCharmedTargetSelector())) - { - switch (player->getClass()) - { - case CLASS_DRUID: - if (urand(0, 1)) - player->CastSpell(target, SPELL_MOONFIRE, false); - else - player->CastSpell(me, SPELL_LIFEBLOOM, false); - break; - case CLASS_HUNTER: - player->CastSpell(target, RAND(SPELL_MULTI_SHOT, SPELL_VOLLEY), false); - break; - case CLASS_MAGE: - player->CastSpell(target, RAND(SPELL_FROST_FIREBOLT, SPELL_ARCANE_MISSILES), false); - break; - case CLASS_WARLOCK: - player->CastSpell(target, RAND(SPELL_CURSE_OF_AGONY, SPELL_SHADOW_BOLT), true); - break; - case CLASS_WARRIOR: - player->CastSpell(target, RAND(SPELL_BLADESTORM, SPELL_CLEAVE), false); - break; - case CLASS_PALADIN: - if (urand(0, 1)) - player->CastSpell(target, SPELL_HAMMER_OF_JUSTICE, false); - else - player->CastSpell(me, SPELL_HOLY_SHOCK, false); - break; - case CLASS_PRIEST: - if (urand(0, 1)) - player->CastSpell(target, SPELL_VAMPIRIC_TOUCH, false); - else - player->CastSpell(me, SPELL_RENEW, false); - break; - case CLASS_SHAMAN: - if (urand(0, 1)) - player->CastSpell(target, SPELL_EARTH_SHOCK, false); - else - player->CastSpell(me, SPELL_HEALING_WAVE, false); - break; - case CLASS_ROGUE: - player->CastSpell(target, RAND(SPELL_HEMORRHAGE, SPELL_MUTILATE), false); - break; - case CLASS_DEATH_KNIGHT: - if (urand(0, 1)) - player->CastSpell(target, SPELL_PLAGUE_STRIKE, true); - else - player->CastSpell(target, SPELL_HOWLING_BLAST, true); - break; - } - } - } - ++itr; + // retail uses server-side spell 28421 for this + Creature* summon = me->SummonCreature(NPC_SKELETON1, GetRandomMinionSpawnPoint(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2 * IN_MILLISECONDS); + summon->AI()->DoZoneInCombat(); } - if (!chained.empty()) - events.Repeat(5000); + uint8 nextTime = 0; + if (_skeletonCount < 10) + nextTime = 5; + else if (_skeletonCount < 19) + nextTime = 4; + else if (_skeletonCount < 31) + nextTime = 3; + else if (_skeletonCount == 31) + nextTime = 4; + else if (_skeletonCount < 72) + nextTime = 2; + + if (nextTime) + events.ScheduleEvent(EVENT_SKELETON, Seconds(nextTime), 0, PHASE_ONE); + break; + } + + case EVENT_BANSHEE: + { + ++_bansheeCount; + // retail uses server-side spell 28423 for this + Creature* summon = me->SummonCreature(NPC_BANSHEE1, GetRandomMinionSpawnPoint(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2 * IN_MILLISECONDS); + summon->AI()->DoZoneInCombat(); + + uint8 nextTime = 0; + if (_bansheeCount < 3) + nextTime = 30; + else if (_bansheeCount < 7) + nextTime = 20; + else if (_bansheeCount < 9) + nextTime = 15; + + if (nextTime) + events.ScheduleEvent(EVENT_BANSHEE, Seconds(nextTime), 0, PHASE_ONE); + break; + } + case EVENT_ABOMINATION: + { + ++_abominationCount; + // retail uses server-side spell 28422 for this + Creature* summon = me->SummonCreature(NPC_ABOMINATION1, GetRandomMinionSpawnPoint(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2 * IN_MILLISECONDS); + summon->AI()->DoZoneInCombat(); + + uint8 nextTime = 0; + if (_abominationCount < 3) + nextTime = 30; + else if (_abominationCount < 7) + nextTime = 20; + else if (_abominationCount < 9) + nextTime = 15; + + if (nextTime) + events.ScheduleEvent(EVENT_ABOMINATION, Seconds(nextTime), 0, PHASE_ONE); break; } - case EVENT_DETONATE: + + case EVENT_DESPAWN_MINIONS: { - std::vector<Unit*> unitList; - ThreatContainer::StorageType const &threatList = me->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) - { - Unit* const target = (*itr)->getTarget(); + // we need a temp vector, as we can't modify summons while iterating (this would cause UB) + std::vector<Creature*> toDespawn; + toDespawn.reserve(summons.size()); + for (ObjectGuid sGuid : summons) + if (Creature* summon = ObjectAccessor::GetCreature(*me, sGuid)) + if (!summon->IsInCombat()) + toDespawn.push_back(summon); + for (Creature* summon : toDespawn) + summon->DespawnOrUnsummon(); + Talk(SAY_AGGRO); + break; + } - if (target->GetTypeId() == TYPEID_PLAYER - && target->getPowerType() == POWER_MANA - && target->GetPower(POWER_MANA)) - { - unitList.push_back(target); - } - } + case EVENT_PHASE_TWO: + me->CastStop(); + events.SetPhase(PHASE_TWO); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC); + me->getThreatManager().resetAllAggro(); + me->SetReactState(REACT_AGGRESSIVE); + Talk(EMOTE_PHASE_TWO); - if (!unitList.empty()) - { - std::vector<Unit*>::const_iterator itr = unitList.begin(); - advance(itr, rand32() % unitList.size()); - DoCast(*itr, SPELL_MANA_DETONATION); - Talk(SAY_SPECIAL); - } + _frostboltCooldown = 2 * IN_MILLISECONDS; + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, randtime(Seconds(24), Seconds(28)), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_SHADOW_FISSURE, randtime(Seconds(6), Seconds(10)), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_DETONATE_MANA, randtime(Seconds(27), Seconds(33)), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_FROST_BLAST, randtime(Seconds(25), Seconds(45)), 0, PHASE_TWO); + if (Is25ManRaid()) + events.ScheduleEvent(EVENT_CHAINS, randtime(Seconds(60), Seconds(80)), 0, PHASE_TWO); + break; + + case EVENT_FROSTBOLT_VOLLEY: + DoCastAOE(SPELL_FROSTBOLT_VOLLEY); + events.Repeat(randtime(Seconds(16), Seconds(18))); + break; - events.Repeat(20000, 50000); + case EVENT_SHADOW_FISSURE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SHADOW_FISSURE); + events.Repeat(randtime(Seconds(14), Seconds(17))); break; - } - case EVENT_FISSURE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_SHADOW_FISURE); - events.Repeat(10000, 45000); + + case EVENT_DETONATE_MANA: + { + ManaUserTargetSelector pred; + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, pred)) + DoCast(target, SPELL_DETONATE_MANA); + events.Repeat(randtime(Seconds(30), Seconds(40))); break; - case EVENT_BLAST: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, RAID_MODE(1, 0), 0, true)) + } + + case EVENT_FROST_BLAST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) DoCast(target, SPELL_FROST_BLAST); - if (rand32() % 2) - Talk(SAY_FROST_BLAST); - events.Repeat(30000, 90000); + events.Repeat(randtime(Seconds(25), Seconds(45))); break; - case EVENT_ANSWER_REQUEST: + + case EVENT_CHAINS: + { + DoCastAOE(SPELL_CHAINS_DUMMY); + events.Repeat(Minutes(1) + randtime(Seconds(0), Seconds(20))); + break; + } + + case EVENT_TRANSITION_REPLY: if (Creature* lichKing = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_LICH_KING))) lichKing->AI()->Talk(SAY_ANSWER_REQUEST); - events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000); + for (Data64 portalData : portalList) + if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(portalData))) + portal->SetGoState(GO_STATE_ACTIVE); break; - case EVENT_SUMMON_GUARDIANS: - if (Creature* guardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)])) - guardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2); - ++nGuardiansOfIcecrownCount; - if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4)) - events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000); - break; - default: + + case EVENT_TRANSITION_SUMMON: + { + uint8 selected = urand(_guardianCount, nGuardianSpawns - 1); + if (selected != _guardianCount) + std::swap(_guardianGroups[selected], _guardianGroups[_guardianCount]); + + std::list<TempSummon*> summoned; + // server-side spell 28454 is used on retail - no point replicating this in spell_dbc + me->SummonCreatureGroup(_guardianGroups[_guardianCount++], &summoned); + for (TempSummon* guardian : summoned) + guardian->AI()->DoAction(ACTION_JUST_SUMMONED); break; + } } } - DoMeleeAttackIfReady(); + if (!_frostboltCooldown) + { + DoCastVictim(SPELL_FROSTBOLT_SINGLE); + _frostboltCooldown = 3 * IN_MILLISECONDS; + } + else + DoMeleeAttackIfReady(); } - } + + uint32 GetData(uint32 data) const override + { + if (data == DATA_ABOMINATION_DEATH_COUNT) + return _abominationDeathCount; + return 0; + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_BEGIN_ENCOUNTER: + if (instance->GetBossState(BOSS_KELTHUZAD) != NOT_STARTED) + return; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + instance->SetBossState(BOSS_KELTHUZAD, IN_PROGRESS); + events.SetPhase(PHASE_ONE); + DoZoneInCombat(); + DoCastAOE(SPELL_VISUAL_CHANNEL); + Talk(SAY_SUMMON_MINIONS); + + for (uint8 group = SUMMON_GROUP_MINION_FIRST; group < SUMMON_GROUP_MINION_FIRST + nMinionGroups; ++group) + { + std::list<TempSummon*> summoned; + me->SummonCreatureGroup(group, &summoned); + for (TempSummon* summon : summoned) + { + summon->SetReactState(REACT_PASSIVE); + summon->AI()->SetData(DATA_MINION_POCKET_ID, group); + } + } + + events.ScheduleEvent(EVENT_SKELETON, Seconds(5), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_BANSHEE, Seconds(30), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_ABOMINATION, Seconds(30), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_DESPAWN_MINIONS, Minutes(3) + Seconds(33), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_PHASE_TWO, Minutes(3) + Seconds(48), 0, PHASE_ONE); + break; + + case ACTION_ABOMINATION_DIED: + ++_abominationDeathCount; + break; + + default: + break; + } + } + + PlayerAI* GetAIForCharmedPlayer(Player* player) override + { + return new KelThuzadCharmedPlayerAI(player); + } + + private: + uint8 _skeletonCount; + uint8 _bansheeCount; + uint8 _abominationCount; + uint8 _abominationDeathCount; + uint32 _frostboltCooldown; + bool _phaseThree; + uint32 _guardianCount; + std::array<uint32, nGuardianSpawns> _guardianGroups; }; CreatureAI* GetAI(Creature* creature) const override @@ -625,188 +570,427 @@ public: } }; -class at_kelthuzad_center : public AreaTriggerScript +static const float MINION_AGGRO_DISTANCE = 20.0f; +// @hack the entire _movementTimer logic only exists because RandomMovementGenerator gets really confused due to the unique map geography of KT's room (it's placed on top of a copy of Winterspring). +// As of the time of writing, RMG sometimes selects positions on the "floor" below the room, causing Abominations to path wildly through the room. +// This custom movement code prevents this by simply ignoring z coord calculation (the floor of the minion coves is flat anyway). +// Dev from the future that is reading this, if RMG has been fixed on the current core revision, please get rid of this hack. Thank you! +struct npc_kelthuzad_minionAI : public ScriptedAI { -public: - at_kelthuzad_center() : AreaTriggerScript("at_kelthuzad_center") { } - - bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override - { - if (player->IsGameMaster()) - return false; - - InstanceScript* instance = player->GetInstanceScript(); - if (!instance || instance->IsEncounterInProgress() || instance->GetBossState(BOSS_KELTHUZAD) == DONE) - return false; - - Creature* pKelthuzad = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_KELTHUZAD)); - if (!pKelthuzad) - return false; + public: + npc_kelthuzad_minionAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), _movementTimer(urandms(4,12)), _home(me->GetPosition()) { } - boss_kelthuzad::boss_kelthuzadAI* pKelthuzadAI = CAST_AI(boss_kelthuzad::boss_kelthuzadAI, pKelthuzad->AI()); - if (!pKelthuzadAI) - return false; + void Reset() override + { + } - pKelthuzadAI->AttackStart(player); - if (GameObject* trigger = ObjectAccessor::GetGameObject(*player, instance->GetGuidData(DATA_KELTHUZAD_TRIGGER))) + void EnterEvadeMode(EvadeReason why) override { - if (trigger->getLootState() == GO_READY) - trigger->UseDoorOrButton(); + ScriptedAI::EnterEvadeMode(why); + if (Creature* kelThuzad = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KELTHUZAD))) + kelThuzad->AI()->EnterEvadeMode(EVADE_REASON_OTHER); + } - // Note: summon must be done by trigger and not by KT. - // Otherwise, they attack immediately as KT is in combat. - for (uint8 i = 0; i < MAX_ABOMINATIONS; ++i) + void EnterCombat(Unit* who) override + { + _movementTimer = 0; // once it's zero, it'll never get checked again + if (!me->HasReactState(REACT_PASSIVE)) { - if (Creature* sum = trigger->SummonCreature(NPC_ABOMINATION, PosAbominations[i])) - { - pKelthuzadAI->spawns.Summon(sum); - sum->GetMotionMaster()->MoveRandom(9.0f); - sum->SetReactState(REACT_DEFENSIVE); - } + DoZoneInCombat(); + return; } - for (uint8 i = 0; i < MAX_WASTES; ++i) - { - if (Creature* sum = trigger->SummonCreature(NPC_WASTE, PosWastes[i])) + + std::list<Creature*> others; + me->GetCreatureListWithEntryInGrid(others, me->GetEntry(), 80.0f); + for (Creature* other : others) + if (other->AI()->GetData(DATA_MINION_POCKET_ID) == pocketId) { - pKelthuzadAI->spawns.Summon(sum); - sum->GetMotionMaster()->MoveRandom(5.0f); - sum->SetReactState(REACT_DEFENSIVE); + other->SetReactState(REACT_AGGRESSIVE); + other->AI()->AttackStart(who); } + me->SetReactState(REACT_AGGRESSIVE); + AttackStart(who); + ScriptedAI::EnterCombat(who); + } + + void AttackStart(Unit* who) override + { + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!me->HasReactState(REACT_PASSIVE)) + { + ScriptedAI::MoveInLineOfSight(who); + return; } - for (uint8 i = 0; i < MAX_WEAVERS; ++i) + + if (me->CanStartAttack(who, false) && me->GetDistance2d(who) <= MINION_AGGRO_DISTANCE) + EnterCombat(who); + } + + void SetData(uint32 data, uint32 value) override + { + if (data == DATA_MINION_POCKET_ID) + pocketId = value; + } + + uint32 GetData(uint32 data) const override + { + if (data == DATA_MINION_POCKET_ID) + return pocketId; + return 0; + } + + void MovementInform(uint32 /*type*/, uint32 id) override + { + if (id == MOVEMENT_MINION_RANDOM) + _movementTimer = urandms(2, 10) + urandms(2, 10); + } + + void UpdateRandomMovement(uint32 diff) + { + if (!_movementTimer) + return; + + if (_movementTimer <= diff) { - if (Creature* sum = trigger->SummonCreature(NPC_WEAVER, PosWeavers[i])) - { - pKelthuzadAI->spawns.Summon(sum); - sum->GetMotionMaster()->MoveRandom(9.0f); - sum->SetReactState(REACT_DEFENSIVE); - } + _movementTimer = 0; + me->GetMotionMaster()->MovePoint(MOVEMENT_MINION_RANDOM, GetRandomPositionOnCircle(_home, 3.0f)); } + else + _movementTimer -= diff; } - return true; + protected: + InstanceScript* const instance; + uint32 pocketId; + + private: + uint32 _movementTimer; + Position const _home; +}; + +class npc_kelthuzad_skeleton : public CreatureScript +{ +public: + npc_kelthuzad_skeleton() : CreatureScript("npc_kelthuzad_skeleton") { } + + struct npc_kelthuzad_skeletonAI : public npc_kelthuzad_minionAI + { + npc_kelthuzad_skeletonAI(Creature* creature) : npc_kelthuzad_minionAI(creature) { } + + void UpdateAI(uint32 diff) override + { + UpdateRandomMovement(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_kelthuzad_skeletonAI>(creature); + } +}; + +class npc_kelthuzad_banshee : public CreatureScript +{ +public: + npc_kelthuzad_banshee() : CreatureScript("npc_kelthuzad_banshee") { } + + struct npc_kelthuzad_bansheeAI : public npc_kelthuzad_minionAI + { + npc_kelthuzad_bansheeAI(Creature* creature) : npc_kelthuzad_minionAI(creature) { } + + void UpdateAI(uint32 diff) override + { + UpdateRandomMovement(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_kelthuzad_bansheeAI>(creature); } }; class npc_kelthuzad_abomination : public CreatureScript { - public: - npc_kelthuzad_abomination() : CreatureScript("npc_kelthuzad_abomination") { } +public: + npc_kelthuzad_abomination() : CreatureScript("npc_kelthuzad_abomination") { } + + struct npc_kelthuzad_abominationAI : public npc_kelthuzad_minionAI + { + npc_kelthuzad_abominationAI(Creature* creature) : npc_kelthuzad_minionAI(creature), _woundTimer(urandms(10, 20)) { } - struct npc_kelthuzad_abominationAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - npc_kelthuzad_abominationAI(Creature* creature) : ScriptedAI(creature) + UpdateRandomMovement(diff); + + if (!UpdateVictim()) + return; + + if (_woundTimer <= diff) { - _instance = creature->GetInstanceScript(); + _woundTimer = urandms(14, 18); + DoCastVictim(SPELL_MORTAL_WOUND); + } + else + _woundTimer -= diff; + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) override + { + if (Creature* kelThuzad = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KELTHUZAD))) + kelThuzad->AI()->DoAction(ACTION_ABOMINATION_DIED); + npc_kelthuzad_minionAI::JustDied(killer); + } + + uint32 _woundTimer; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_kelthuzad_abominationAI>(creature); + } +}; + +class npc_kelthuzad_guardian : public CreatureScript +{ +public: + npc_kelthuzad_guardian() : CreatureScript("npc_kelthuzad_guardian") { } + + struct npc_kelthuzad_guardianAI : public ScriptedAI + { + public: + npc_kelthuzad_guardianAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), _visibilityTimer(0), _bloodTapTimer(0) { } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_JUST_SUMMONED: + me->SetVisible(false); + me->SetHomePosition(me->GetPosition()); + DoZoneInCombat(); + me->SetCombatPulseDelay(5); + _visibilityTimer = 2 * IN_MILLISECONDS; + _bloodTapTimer = 25 * IN_MILLISECONDS; + break; + case ACTION_KELTHUZAD_DIED: + Talk(EMOTE_GUARDIAN_FLEE); + me->SetReactState(REACT_PASSIVE); + me->RemoveAllAuras(); + me->CombatStop(); + me->StopMoving(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + me->DespawnOrUnsummon(30 * IN_MILLISECONDS); // just in case anything interrupts the movement + me->GetMotionMaster()->MoveTargetedHome(); + default: + break; + } + } + + void EnterEvadeMode(EvadeReason why) override + { + if (Creature* kelthuzad = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KELTHUZAD))) + kelthuzad->AI()->EnterEvadeMode(); + ScriptedAI::EnterEvadeMode(why); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); } void Reset() override { - _events.Reset(); - _events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(2000, 5000)); - DoCast(me, SPELL_FRENZY, true); + me->SetCombatPulseDelay(0); + ScriptedAI::Reset(); } void UpdateAI(uint32 diff) override { + if (_visibilityTimer) + { + if (diff > _visibilityTimer) + _visibilityTimer -= diff; + else + { + me->SetVisible(true); + Talk(EMOTE_GUARDIAN_APPEAR); + _visibilityTimer = 0; + } + } + if (!UpdateVictim()) return; - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) + if (_bloodTapTimer <= diff) { - switch (eventId) - { - case EVENT_MORTAL_WOUND: - DoCastVictim(SPELL_MORTAL_WOUND, true); - _events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(10000, 15000)); - break; - default: - break; - } + DoCastVictim(SPELL_BLOOD_TAP); + _bloodTapTimer = urandms(18, 26); } - } + else + _bloodTapTimer -= diff; - void JustDied(Unit* /*killer*/) override - { - _instance->SetData(DATA_ABOMINATION_KILLED, _instance->GetData(DATA_ABOMINATION_KILLED) + 1); + DoMeleeAttackIfReady(); } private: - InstanceScript* _instance; - EventMap _events; - }; + InstanceScript* const instance; + uint32 _visibilityTimer; + uint32 _bloodTapTimer; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_kelthuzad_guardianAI>(creature); + } +}; + +class spell_kelthuzad_chains : public SpellScriptLoader +{ +public: + spell_kelthuzad_chains() : SpellScriptLoader("spell_kelthuzad_chains") { } + + class spell_kelthuzad_chains_AuraScript : public AuraScript + { + PrepareAuraScript(spell_kelthuzad_chains_AuraScript); + + void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + float scale = target->GetObjectScale(); + ApplyPercentModFloatVar(scale, 200.0f, true); + target->SetObjectScale(scale); + } + + void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + float scale = target->GetObjectScale(); + ApplyPercentModFloatVar(scale, 200.0f, false); + target->SetObjectScale(scale); + } - CreatureAI* GetAI(Creature* creature) const override + void Register() override { - return GetInstanceAI<npc_kelthuzad_abominationAI>(creature); + AfterEffectApply += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectApplyFn(spell_kelthuzad_chains_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_kelthuzad_chains_AuraScript(); + } }; class spell_kelthuzad_detonate_mana : public SpellScriptLoader { - public: - spell_kelthuzad_detonate_mana() : SpellScriptLoader("spell_kelthuzad_detonate_mana") { } - - class spell_kelthuzad_detonate_mana_AuraScript : public AuraScript - { - PrepareAuraScript(spell_kelthuzad_detonate_mana_AuraScript); +public: + spell_kelthuzad_detonate_mana() : SpellScriptLoader("spell_kelthuzad_detonate_mana") { } - bool Validate(SpellInfo const* /*spell*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_MANA_DETONATION_DAMAGE)) - return false; - return true; - } + class spell_kelthuzad_detonate_mana_AuraScript : public AuraScript + { + PrepareAuraScript(spell_kelthuzad_detonate_mana_AuraScript); - void HandleScript(AuraEffect const* aurEff) - { - PreventDefaultAction(); + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_MANA_DETONATION_DAMAGE)) + return false; + return true; + } - Unit* target = GetTarget(); - if (int32 mana = int32(target->GetMaxPower(POWER_MANA) / 10)) - { - mana = target->ModifyPower(POWER_MANA, -mana); - target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, NULL, aurEff); - } - } + void HandleScript(AuraEffect const* aurEff) + { + PreventDefaultAction(); - void Register() override + Unit* target = GetTarget(); + if (int32 mana = int32(target->GetMaxPower(POWER_MANA) / 10)) { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_AuraScript::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + mana = target->ModifyPower(POWER_MANA, -mana); + target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, NULL, aurEff); } - }; + } - AuraScript* GetAuraScript() const override + void Register() override { - return new spell_kelthuzad_detonate_mana_AuraScript(); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_AuraScript::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_kelthuzad_detonate_mana_AuraScript(); + } +}; + +class at_kelthuzad_center : public AreaTriggerScript +{ +public: + at_kelthuzad_center() : AreaTriggerScript("at_kelthuzad_center") { } + + bool OnTrigger(Player* player, const AreaTriggerEntry* /*at*/) override + { + InstanceScript* instance = player->GetInstanceScript(); + if (!instance || instance->GetBossState(BOSS_KELTHUZAD) != NOT_STARTED) + return true; + + if (player->IsGameMaster()) + return true; + + Creature* kelThuzad = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_KELTHUZAD)); + if (!kelThuzad) + return true; + + kelThuzad->AI()->DoAction(ACTION_BEGIN_ENCOUNTER); + + return true; + } }; class achievement_just_cant_get_enough : public AchievementCriteriaScript { public: - achievement_just_cant_get_enough() : AchievementCriteriaScript("achievement_just_cant_get_enough") { } + achievement_just_cant_get_enough() : AchievementCriteriaScript("achievement_just_cant_get_enough") { } - bool OnCheck(Player* /*player*/, Unit* target) override - { - if (!target) - return false; + bool OnCheck(Player* /*player*/, Unit* target) override + { + if (!target) + return false; - if (InstanceScript* instance = target->GetInstanceScript()) - if (instance->GetData(DATA_ABOMINATION_KILLED) >= 18) - return true; + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* kelThuzad = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_KELTHUZAD))) + if (kelThuzad->AI()->GetData(DATA_ABOMINATION_DEATH_COUNT) >= 18) + return true; - return false; - } + return false; + } }; void AddSC_boss_kelthuzad() { new boss_kelthuzad(); - new at_kelthuzad_center(); + new npc_kelthuzad_skeleton(); + new npc_kelthuzad_banshee(); new npc_kelthuzad_abomination(); + new npc_kelthuzad_guardian(); + new spell_kelthuzad_chains(); new spell_kelthuzad_detonate_mana(); + new at_kelthuzad_center(); new achievement_just_cant_get_enough(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 720549de0b2..aa043316088 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -97,6 +97,7 @@ ObjectData const objectData[] = { GO_NAXX_PORTAL_CONSTRUCT, DATA_NAXX_PORTAL_CONSTRUCT }, { GO_NAXX_PORTAL_PLAGUE, DATA_NAXX_PORTAL_PLAGUE }, { GO_NAXX_PORTAL_MILITARY, DATA_NAXX_PORTAL_MILITARY }, + { GO_KELTHUZAD_THRONE, DATA_KELTHUZAD_THRONE }, { 0, 0, } }; @@ -115,7 +116,6 @@ class instance_naxxramas : public InstanceMapScript LoadDoorData(doorData); LoadObjectData(nullptr, objectData); - AbominationCount = 0; hadAnubRekhanGreet = false; hadFaerlinaGreet = false; hadThaddiusGreet = false; @@ -230,6 +230,10 @@ class instance_naxxramas : public InstanceMapScript if (GetBossState(BOSS_HORSEMEN) == DONE) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; + case GO_KELTHUZAD_THRONE: + if (GetBossState(BOSS_KELTHUZAD) == DONE) + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + break; case GO_BIRTH: if (hadSapphironBirth || GetBossState(BOSS_SAPPHIRON) == DONE) { @@ -270,9 +274,6 @@ class instance_naxxramas : public InstanceMapScript if (GameObject* gate = instance->GetGameObject(GothikGateGUID)) gate->SetGoState(GOState(value)); break; - case DATA_ABOMINATION_KILLED: - AbominationCount = value; - break; case DATA_HAD_ANUBREKHAN_GREET: hadAnubRekhanGreet = (value == 1u); break; @@ -294,8 +295,6 @@ class instance_naxxramas : public InstanceMapScript { switch (id) { - case DATA_ABOMINATION_KILLED: - return AbominationCount; case DATA_HAD_ANUBREKHAN_GREET: return hadAnubRekhanGreet ? 1u : 0u; case DATA_HAD_FAERLINA_GREET: @@ -418,6 +417,12 @@ class instance_naxxramas : public InstanceMapScript case BOSS_SAPPHIRON: if (state == DONE) events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, Seconds(6)); + HandleGameObject(KelthuzadDoorGUID, false); + break; + case BOSS_KELTHUZAD: + if (state == DONE) + if (GameObject* throne = GetGameObject(DATA_KELTHUZAD_THRONE)) + throne->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; default: break; @@ -493,7 +498,6 @@ class instance_naxxramas : public InstanceMapScript case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD: if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD); - HandleGameObject(KelthuzadDoorGUID, false); events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, Seconds(6)); break; case EVENT_DIALOGUE_SAPPHIRON_LICHKING: @@ -616,7 +620,6 @@ class instance_naxxramas : public InstanceMapScript ObjectGuid PortalsGUID[4]; ObjectGuid KelthuzadDoorGUID; ObjectGuid LichKingGUID; - uint8 AbominationCount; bool hadAnubRekhanGreet; bool hadFaerlinaGreet; bool hadThaddiusGreet; diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 75e7314c5d0..b1f51172280 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -50,12 +50,12 @@ enum Data DATA_HAD_SAPPHIRON_BIRTH, DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT, - DATA_ABOMINATION_KILLED, DATA_NAXX_PORTAL_ARACHNID, DATA_NAXX_PORTAL_CONSTRUCT, DATA_NAXX_PORTAL_PLAGUE, - DATA_NAXX_PORTAL_MILITARY + DATA_NAXX_PORTAL_MILITARY, + DATA_KELTHUZAD_THRONE }; enum Data64 @@ -121,6 +121,7 @@ enum GameObjectsIds GO_KELTHUZAD_PORTAL03 = 181404, GO_KELTHUZAD_PORTAL04 = 181405, GO_KELTHUZAD_TRIGGER = 181444, + GO_KELTHUZAD_THRONE = 181640, GO_ROOM_ANUBREKHAN = 181126, GO_PASSAGE_ANUBREKHAN = 181195, GO_PASSAGE_FAERLINA = 194022, @@ -138,14 +139,20 @@ enum GameObjectsIds GO_ROOM_HORSEMEN = 181119, GO_PASSAGE_SAPPHIRON = 181225, GO_ROOM_KELTHUZAD = 181228, + + // End of wing portals GO_ARAC_PORTAL = 181575, GO_PLAG_PORTAL = 181577, GO_MILI_PORTAL = 181578, GO_CONS_PORTAL = 181576, + + // "Glow" effect on center-side portal GO_ARAC_EYE_RAMP = 181212, GO_PLAG_EYE_RAMP = 181211, GO_MILI_EYE_RAMP = 181210, GO_CONS_EYE_RAMP = 181213, + + // "Glow" effect on boss-side portal GO_ARAC_EYE_RAMP_BOSS = 181233, GO_PLAG_EYE_RAMP_BOSS = 181231, GO_MILI_EYE_RAMP_BOSS = 181230, diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 55295a534e1..5cfabb42797 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -113,7 +113,8 @@ public: Initialize(); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_ROOT); if (!me->IsVisible()) me->SetVisible(true); @@ -152,7 +153,8 @@ public: me->AttackStop(); me->SetVisible(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(true, UNIT_STATE_ROOT); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); @@ -236,7 +238,8 @@ public: else if (lSparkList.empty()) { me->SetVisible(true); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_ROOT); DoCast(me, SPELL_SPARK_DESPAWN, false); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index f20de459b12..70c1c0221c4 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -204,12 +204,15 @@ public: } } - void JustReachedHome() override + void MovementInform(uint32 type, uint32 data) override { - if (m_uiSummonPhase == 2) + if (type == POINT_MOTION_TYPE && data == EVENT_FORGE_CAST) { - me->SetOrientation(2.29f); - m_uiSummonPhase = 3; + if (m_uiSummonPhase == 2) + { + me->SetOrientation(2.29f); + m_uiSummonPhase = 3; + } } } @@ -298,12 +301,12 @@ public: case 1: // 1 - Start run to Anvil Talk(EMOTE_TO_ANVIL); - me->GetMotionMaster()->MoveTargetedHome(); + me->GetMotionMaster()->MovePoint(EVENT_FORGE_CAST, me->GetHomePosition()); m_uiSummonPhase = 2; // Set Next Phase break; case 2: // 2 - Check if reached Anvil - // This is handled in: void JustReachedHome() override + // This is handled in: void MovementInform(uint32, uint32) override break; case 3: // 3 - Cast Temper on the Anvil diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index cbd24141bdf..21d42d57a5e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -415,7 +415,8 @@ class npc_saronite_vapors : public CreatureScript if (damage >= me->GetHealth()) { damage = 0; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(true, UNIT_STATE_ROOT); me->SetStandState(UNIT_STAND_STATE_DEAD); me->SetHealth(me->GetMaxHealth()); me->RemoveAllAuras(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index c03a1c6fbc1..d600eabd462 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -186,7 +186,8 @@ class npc_flash_freeze : public CreatureScript Initialize(); instance = me->GetInstanceScript(); me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->SetControlled(true, UNIT_STATE_ROOT); } void Initialize() @@ -261,7 +262,8 @@ class npc_ice_block : public CreatureScript { instance = me->GetInstanceScript(); me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + me->SetControlled(true, UNIT_STATE_ROOT); } InstanceScript* instance; @@ -271,7 +273,8 @@ class npc_ice_block : public CreatureScript void IsSummonedBy(Unit* summoner) override { targetGUID = summoner->GetGUID(); - summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + summoner->SetControlled(true, UNIT_STATE_ROOT); me->SetInCombatWith(summoner); me->AddThreat(summoner, 250.0f); summoner->AddThreat(me, 250.0f); @@ -287,7 +290,8 @@ class npc_ice_block : public CreatureScript { if (Creature* Helper = ObjectAccessor::GetCreature(*me, targetGUID)) { - Helper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + Helper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED); + Helper->SetControlled(false, UNIT_STATE_ROOT); if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_HODIR))) { @@ -390,7 +394,8 @@ class boss_hodir : public CreatureScript me->RemoveAllAttackers(); me->AttackStop(); me->SetReactState(REACT_PASSIVE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetControlled(true, UNIT_STATE_ROOT); me->InterruptNonMeleeSpells(true); me->StopMoving(); me->GetMotionMaster()->Clear(); @@ -547,7 +552,8 @@ class npc_icicle : public CreatureScript { Initialize(); me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(true, UNIT_STATE_ROOT); me->SetReactState(REACT_PASSIVE); } @@ -601,7 +607,8 @@ class npc_snowpacked_icicle : public CreatureScript { Initialize(); me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + me->SetControlled(true, UNIT_STATE_ROOT); me->SetReactState(REACT_PASSIVE); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index a50643c5deb..1a515e5d4a5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -178,7 +178,8 @@ class boss_ignis : public CreatureScript { summon->setFaction(16); summon->SetReactState(REACT_AGGRESSIVE); - summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_IMMUNE_TO_PC); + summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_IMMUNE_TO_PC); + summon->SetControlled(false, UNIT_STATE_ROOT); } summon->AI()->AttackStart(me->GetVictim()); @@ -375,7 +376,8 @@ class npc_scorch_ground : public CreatureScript npc_scorch_groundAI(Creature* creature) : ScriptedAI(creature) { Initialize(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL |UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + me->SetControlled(true, UNIT_STATE_ROOT); creature->SetDisplayId(16925); //model 2 in db cannot overwrite wdb fields } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index 45d4fa58a03..f4ea5a826c2 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -104,7 +104,7 @@ class boss_kologarn : public CreatureScript left(false), right(false) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL); + me->SetControlled(true, UNIT_STATE_ROOT); DoCast(SPELL_KOLOGARN_REDUCE_PARRY); SetCombatMovement(false); diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp index e7305e53808..c9d78441e5b 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp @@ -247,7 +247,8 @@ class npc_frozen_orb_stalker : public CreatureScript npc_frozen_orb_stalkerAI(Creature* creature) : ScriptedAI(creature) { creature->SetVisible(false); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL); + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + me->SetControlled(true, UNIT_STATE_ROOT); creature->SetReactState(REACT_PASSIVE); instance = creature->GetInstanceScript(); diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 03af1a6417f..ac05c421efb 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -115,7 +115,6 @@ public: } break; } - me->SetOrientation(me->GetHomePosition().GetOrientation()); return; } diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 3d801cc2fbb..a99803ee99a 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -215,17 +215,6 @@ class npc_tournament_training_dummy : public CreatureScript me->SetControlled(true, UNIT_STATE_STUNNED); Initialize(); - // Cast Defend spells to max stack size - switch (me->GetEntry()) - { - case NPC_CHARGE_TARGET: - DoCast(SPELL_CHARGE_DEFEND); - break; - case NPC_RANGED_TARGET: - me->CastCustomSpell(SPELL_RANGED_DEFEND, SPELLVALUE_AURA_STACK, 3, me); - break; - } - events.Reset(); events.ScheduleEvent(EVENT_DUMMY_RECAST_DEFEND, 5000); } @@ -286,14 +275,14 @@ class npc_tournament_training_dummy : public CreatureScript case NPC_CHARGE_TARGET: { if (!me->HasAura(SPELL_CHARGE_DEFEND)) - DoCast(SPELL_CHARGE_DEFEND); + DoCast(me, SPELL_CHARGE_DEFEND, true); break; } case NPC_RANGED_TARGET: { Aura* defend = me->GetAura(SPELL_RANGED_DEFEND); if (!defend || defend->GetStackAmount() < 3 || defend->GetDuration() <= 8000) - DoCast(SPELL_RANGED_DEFEND); + DoCast(me, SPELL_RANGED_DEFEND, true); break; } } diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index 56d333b2dda..699dd578b8d 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -241,7 +241,6 @@ public: boss_teron_gorefiendAI(Creature* creature) : BossAI(creature, DATA_TERON_GOREFIEND) { Initialize(); - instance = creature->GetInstanceScript(); } void Initialize() @@ -259,8 +258,6 @@ public: Done = false; } - InstanceScript* instance; - uint32 IncinerateTimer; uint32 SummonDoomBlossomTimer; uint32 EnrageTimer; diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp index bd36e3cb765..a7b58737374 100644 --- a/src/server/scripts/Spells/spell_holiday.cpp +++ b/src/server/scripts/Spells/spell_holiday.cpp @@ -846,6 +846,7 @@ enum RamBlaBla { SPELL_GIDDYUP = 42924, SPELL_RENTAL_RACING_RAM = 43883, + SPELL_SWIFT_WORK_RAM = 43880, SPELL_RENTAL_RACING_RAM_AURA = 42146, SPELL_RAM_LEVEL_NEUTRAL = 43310, SPELL_RAM_TROT = 42992, @@ -853,6 +854,7 @@ enum RamBlaBla SPELL_RAM_GALLOP = 42994, SPELL_RAM_FATIGUE = 43052, SPELL_EXHAUSTED_RAM = 43332, + SPELL_RELAY_RACE_TURN_IN = 44501, // Quest SPELL_BREWFEST_QUEST_SPEED_BUNNY_GREEN = 43345, @@ -873,7 +875,7 @@ class spell_brewfest_giddyup : public SpellScriptLoader void OnChange(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); - if (!target->HasAura(SPELL_RENTAL_RACING_RAM)) + if (!target->HasAura(SPELL_RENTAL_RACING_RAM) && !target->HasAura(SPELL_SWIFT_WORK_RAM)) { target->RemoveAura(GetId()); return; @@ -1110,6 +1112,38 @@ class spell_brewfest_relay_race_intro_force_player_to_throw : public SpellScript } }; +class spell_brewfest_relay_race_turn_in : public SpellScriptLoader +{ +public: + spell_brewfest_relay_race_turn_in() : SpellScriptLoader("spell_brewfest_relay_race_turn_in") { } + + class spell_brewfest_relay_race_turn_in_SpellScript : public SpellScript + { + PrepareSpellScript(spell_brewfest_relay_race_turn_in_SpellScript); + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Aura* aura = GetHitUnit()->GetAura(SPELL_SWIFT_WORK_RAM)) + { + aura->SetDuration(aura->GetDuration() + 30 * IN_MILLISECONDS); + GetCaster()->CastSpell(GetHitUnit(), SPELL_RELAY_RACE_TURN_IN, TRIGGERED_FULL_MASK); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_brewfest_relay_race_turn_in_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_brewfest_relay_race_turn_in_SpellScript(); + } +}; + // 43876 - Dismount Ram class spell_brewfest_dismount_ram : public SpellScriptLoader { @@ -1382,6 +1416,7 @@ void AddSC_holiday_spell_scripts() new spell_brewfest_apple_trap(); new spell_brewfest_exhausted_ram(); new spell_brewfest_relay_race_intro_force_player_to_throw(); + new spell_brewfest_relay_race_turn_in(); new spell_brewfest_dismount_ram(); new spell_brewfest_barker_bunny(); // Midsummer Fire Festival diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 715e4d4ed2d..bf0fc3d0565 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1127,6 +1127,75 @@ class spell_q9452_cast_net: public SpellScriptLoader } }; +enum PoundDrumSpells +{ + SPELL_SUMMON_DEEP_JORMUNGAR = 66510, + SPELL_STORMFORGED_MOLE_MACHINE = 66492 +}; + +class spell_q14076_14092_pound_drum : public SpellScriptLoader +{ + public: + spell_q14076_14092_pound_drum() : SpellScriptLoader("spell_q14076_14092_pound_drum") { } + + class spell_q14076_14092_pound_drum_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q14076_14092_pound_drum_SpellScript); + + void HandleSummon() + { + Unit* caster = GetCaster(); + + if (roll_chance_i(80)) + caster->CastSpell(caster, SPELL_SUMMON_DEEP_JORMUNGAR, true); + else + caster->CastSpell(caster, SPELL_STORMFORGED_MOLE_MACHINE, true); + } + + void HandleActiveObject(SpellEffIndex /*effIndex*/) + { + GetHitGObj()->SetLootState(GO_JUST_DEACTIVATED); + } + + void Register() override + { + OnCast += SpellCastFn(spell_q14076_14092_pound_drum_SpellScript::HandleSummon); + OnEffectHitTarget += SpellEffectFn(spell_q14076_14092_pound_drum_SpellScript::HandleActiveObject, EFFECT_0, SPELL_EFFECT_ACTIVATE_OBJECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q14076_14092_pound_drum_SpellScript(); + } +}; + +class spell_q12279_cast_net : public SpellScriptLoader +{ + public: + spell_q12279_cast_net() : SpellScriptLoader("spell_q12279_cast_net") { } + + class spell_q12279_cast_net_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12279_cast_net_SpellScript); + + void HandleActiveObject(SpellEffIndex /*effIndex*/) + { + GetHitGObj()->SetLootState(GO_JUST_DEACTIVATED); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q12279_cast_net_SpellScript::HandleActiveObject, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q12279_cast_net_SpellScript(); + } +}; + enum HodirsHelm { SAY_1 = 1, @@ -2523,6 +2592,8 @@ void AddSC_quest_spell_scripts() new spell_q13280_13283_plant_battle_standard(); new spell_q14112_14145_chum_the_water(); new spell_q9452_cast_net(); + new spell_q12279_cast_net(); + new spell_q14076_14092_pound_drum(); new spell_q12987_read_pronouncement(); new spell_q12277_wintergarde_mine_explosion(); new spell_q12066_bunny_kill_credit(); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 5e6407e361e..c33d74d0faa 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -586,7 +586,7 @@ public: events.Reset(); running = false; } - + void Reset() override { Initialize(); @@ -1660,25 +1660,25 @@ public: # npc_wormhole ######*/ -#define GOSSIP_ENGINEERING1 "Borean Tundra" -#define GOSSIP_ENGINEERING2 "Howling Fjord" -#define GOSSIP_ENGINEERING3 "Sholazar Basin" -#define GOSSIP_ENGINEERING4 "Icecrown" -#define GOSSIP_ENGINEERING5 "Storm Peaks" -#define GOSSIP_ENGINEERING6 "Underground..." - -enum WormholeSpells +enum NPC_Wormhole { - SPELL_BOREAN_TUNDRA = 67834, - SPELL_SHOLAZAR_BASIN = 67835, - SPELL_ICECROWN = 67836, - SPELL_STORM_PEAKS = 67837, - SPELL_HOWLING_FJORD = 67838, - SPELL_UNDERGROUND = 68081, - - TEXT_WORMHOLE = 907, - - DATA_SHOW_UNDERGROUND = 1, + DATA_SHOW_UNDERGROUND = 1, // -> Random 0 or 1 + + MENU_ID_WORMHOLE = 10668, // "This tear in the fabric of time and space looks ominous." + NPC_TEXT_WORMHOLE = 14785, // (not 907 "What brings you to this part of the world, $n?") + GOSSIP_OPTION_1 = 0, // "Borean Tundra" + GOSSIP_OPTION_2 = 1, // "Howling Fjord" + GOSSIP_OPTION_3 = 2, // "Sholazar Basin" + GOSSIP_OPTION_4 = 3, // "Icecrown" + GOSSIP_OPTION_5 = 4, // "Storm Peaks" + GOSSIP_OPTION_6 = 5, // "Underground..." + + SPELL_BOREAN_TUNDRA = 67834, // 0 + SPELL_HOWLING_FJORD = 67838, // 1 + SPELL_SHOLAZAR_BASIN = 67835, // 2 + SPELL_ICECROWN = 67836, // 3 + SPELL_STORM_PEAKS = 67837, // 4 + SPELL_UNDERGROUND = 68081 // 5 }; class npc_wormhole : public CreatureScript @@ -1718,16 +1718,16 @@ class npc_wormhole : public CreatureScript { if (player == creature->ToTempSummon()->GetSummoner()) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); if (creature->AI()->GetData(DATA_SHOW_UNDERGROUND)) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ENGINEERING6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_WORMHOLE, GOSSIP_OPTION_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->PlayerTalkClass->SendGossipMenu(TEXT_WORMHOLE, creature->GetGUID()); + player->SEND_GOSSIP_MENU(NPC_TEXT_WORMHOLE, creature->GetGUID()); } } diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index fe0e3ffd13d..bf157a228dd 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -70,6 +70,10 @@ namespace MMAP m_rcContext = new rcContext(false); + // percentageDone - Initializing + m_totalTiles = 0; + m_totalTilesBuilt = 0; + discoverTiles(); } @@ -152,6 +156,9 @@ namespace MMAP } } printf("found %u.\n\n", count); + + // percentageDone - total tiles to process + m_totalTiles = count; } /**************************************************************************/ @@ -424,7 +431,8 @@ namespace MMAP /**************************************************************************/ void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh) { - printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY); + // percentageDone - added, now it will show addional reference percentage done of the overall process + printf("%u%% [Map %03i] Building tile [%02u,%02u]\n", percentageDone(m_totalTiles, m_totalTilesBuilt), mapID, tileX, tileY); MeshData meshData; @@ -458,6 +466,9 @@ namespace MMAP // build navmesh tile buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh); + + // percentageDone - increment tiles built + m_totalTilesBuilt++; } /**************************************************************************/ @@ -1015,4 +1026,13 @@ namespace MMAP return true; } + /**************************************************************************/ + uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt) + { + if (totalTiles) + return totalTilesBuilt * 100 / totalTiles; + + return 0; + } + } diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h index d4b1bdf00fc..9c22a66ea87 100644 --- a/src/tools/mmaps_generator/MapBuilder.h +++ b/src/tools/mmaps_generator/MapBuilder.h @@ -123,6 +123,8 @@ namespace MMAP bool shouldSkipMap(uint32 mapID); bool isTransportMap(uint32 mapID); bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY); + // percentageDone - method to calculate percentage + uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone); TerrainBuilder* m_terrainBuilder; TileList m_tiles; @@ -136,6 +138,9 @@ namespace MMAP float m_maxWalkableAngle; bool m_bigBaseUnit; + // percentageDone - variables to calculate percentage + uint32 m_totalTiles; + std::atomic<uint32> m_totalTilesBuilt; // build performance - not really used for now rcContext* m_rcContext; |
