diff options
49 files changed, 6739 insertions, 83 deletions
diff --git a/Wintergrasp_TODO.txt b/Wintergrasp_TODO.txt new file mode 100644 index 00000000000..9d6729c432e --- /dev/null +++ b/Wintergrasp_TODO.txt @@ -0,0 +1,12 @@ +TODO (add new things to sort out here) : +- Move spawns to database : NPCs / GOs +- Spawn NPC/GO in their correct phase +- Fix teleport spells for vehicles/drivers +- Get official texts for horde in db +- Clean up code to use phases-system / spells instead of hardcoded spawn/despawn functionality +- Remove hardcoded entities from headerfile +- Spawn horde/alliance spiritguides spawn/change depending on holder +- Clean up some minor hacks + +COMPLETED (move completed things from the above list here) : + diff --git a/Wintergrasp_spells.txt b/Wintergrasp_spells.txt new file mode 100644 index 00000000000..1db15ce5069 --- /dev/null +++ b/Wintergrasp_spells.txt @@ -0,0 +1,18 @@ +Spell 56617 "Alliance Controls Factory Phase Shift" Adds Phase 32 +Spell 56618 "Horde Controls Factory Phase Shift" Adds Phase 16 + +Spell 55773 "Horde Control Phase Shift" Adds Phase 64 +Spell 55774 "Alliance Control Phase Shift" Adds Phase 128 + +Spell 58045 "Essence of Wintergrasp" Adds Phase 256 + +Spell 37795 "Recruit" Gained when joining WG battle + +Spell 74411 "Battleground - Dampening" Gained when joining WG battle + + +Wintergrasp Vehicle On spawn entries: 28312,27881,28094,32627 +set x,y,z,o to nearest trigger entry: 23472 +make player cast 60968 on vehicle +aura 14267 on self if player is horde +aura 14268 on self if player is alliance
\ No newline at end of file diff --git a/sql/updates/Wintergrasp_spawning.sql b/sql/updates/Wintergrasp_spawning.sql new file mode 100644 index 00000000000..7e157229279 --- /dev/null +++ b/sql/updates/Wintergrasp_spawning.sql @@ -0,0 +1,474 @@ +-- Replace Wintergrasp spawns with properly phased spawns +SET @GUID := 290000; +DELETE FROM `creature` WHERE `id` IN (31841,31842,30400,30499,30489,30869,31036,31051,31052,31054,31108,31109,31153,39172,30870,31053,31091,31101,31102,31106,31107,31151,32294,39173,32296,30488); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +-- Horde Spirt Guides +(@GUID+0,31841,571,1,0x00000010,0,0,4318.436,2408.06738,392.675751,6.23082542,120,0,0,1,0,0,0), -- Eastspark Workshop +(@GUID+1,31841,571,1,0x00000010,0,0,4336.25439,3235.51978,390.334,0.628318548,120,0,0,1,0,0,0), -- Westspark Workshop +(@GUID+2,31841,571,1,0x00000010,0,0,5104.753,2300.9458,368.568054,0.7330383,120,0,0,1,0,0,0), -- The Sunken Ring +(@GUID+3,31841,571,1,0x00000010,0,0,5103.133,3462.128,368.568054,5.270895,120,0,0,1,0,0,0), -- The Chilled Quagmire "Outside broker Temple" +(@GUID+4,31841,571,1,0x00000040,0,0,5537.482,2898.90674,517.2589,4.86946869,120,0,0,1,0,0,0), -- Fortress +(@GUID+5,31841,571,1,0x00000001,0,0,5031.84131,3710.74878,372.4835,0,120,5,0,1,0,0,0), -- Horde Landing Zone +-- Alliance Spirt Guides +(@GUID+6,31842,571,1,0x00000020,0,0,4318.436,2408.06738,392.675751,6.23082542,120,0,0,1,0,0,0), -- Eastspark Workshop +(@GUID+7,31842,571,1,0x00000020,0,0,4336.25439,3235.51978,390.334,0.628318548,120,0,0,1,0,0,0), -- Westspark Workshop +(@GUID+8,31842,571,1,0x00000020,0,0,5104.753,2300.9458,368.568054,0.7330383,120,0,0,1,0,0,0), -- The Sunken Ring +(@GUID+9,31842,571,1,0x00000020,0,0,5103.133,3462.128,368.568054,5.270895,120,0,0,1,0,0,0), -- The Chilled Quagmire "Outside The Broken Temple" +(@GUID+10,31842,571,1,0x00000080,0,0,5537.482,2898.90674,517.2589,4.86946869,120,0,0,1,0,0,0), -- Fortress +(@GUID+11,31842,571,1,0x00000001,0,0,5140.7876,2179.12451,390.9512,1.97222209,120,0,0,1,0,0,0), -- Aliance Landing Zone +-- Horde Engineers +(@GUID+12,30400,571,1,0x00000010,0,0,4964.89,3383.06,382.911,6.12611,180,0,0,1,0,0,0), -- The Broken Temple +(@GUID+13,30400,571,1,0x00000010,0,0,4939.76,2389.06,326.153,3.26377,180,0,0,1,0,0,0), -- The Sunken Ring +(@GUID+14,30400,571,1,0x00000010,0,0,4357.67,2357.99,382.007,1.67552,180,0,0,1,0,0,0), -- Eastspark Workshop +(@GUID+15,30400,571,1,0x00000010,0,0,4354.15,3312.82,378.046,1.67552,180,0,0,1,0,0,0), -- Westspark Workshop +(@GUID+16,30400,571,1,0x00000040,0,0,5391.61,2707.72,415.051,4.55531,180,0,0,1,0,0,0), -- Wintergrasp Fortress +(@GUID+17,30400,571,1,0x00000040,0,0,5392.91,2975.26,415.223,4.55531,180,0,0,1,0,0,0), -- Wintergrasp Fortress +-- Alliance Engineers +(@GUID+18,30499,571,1,0x00000020,0,0,4964.89,3383.06,382.911,6.12611,180,0,0,1,0,0,0), -- The Broken Temple +(@GUID+19,30499,571,1,0x00000020,0,0,4939.76,2389.06,326.153,3.26377,180,0,0,1,0,0,0), -- The Sunken Ring +(@GUID+20,30499,571,1,0x00000020,0,0,4357.67,2357.99,382.007,1.67552,180,0,0,1,0,0,0), -- Eastspark Workshop +(@GUID+21,30499,571,1,0x00000020,0,0,4354.15,3312.82,378.046,1.67552,180,0,0,1,0,0,0), -- Westspark Workshop +(@GUID+22,30499,571,1,0x00000080,0,0,5391.61,2707.72,415.051,4.55531,180,0,0,1,0,0,0), -- Wintergrasp Fortress +(@GUID+23,30499,571,1,0x00000080,0,0,5392.91,2975.26,415.223,4.55531,180,0,0,1,0,0,0), -- Wintergrasp Fortress +-- Alliance NPC's +(@GUID+24,30489,571,1,0x00000080,0,0,5369.973,2874.83081,409.3225,3.12413931,120,0,0,1,0,0,0), +(@GUID+25,30869,571,1,0x00000001,0,0,5102.75049,2187.82837,365.707855,3.996804,120,0,0,1,0,0,0), +(@GUID+26,31036,571,1,0x00000040,0,0,5078.281,2183.704,365.028564,1.46607661,120,0,0,1,0,0,0), +(@GUID+27,31036,571,1,0x00000080,0,0,5358.641,2841.76416,409.3225,1.13262534,120,0,0,1,0,0,0), +(@GUID+28,31051,571,1,0x00000040,0,0,5081.697,2173.73,365.8777,0.8552113,120,0,0,1,0,0,0), +(@GUID+29,31051,571,1,0x00000080,0,0,5296.869,2887.67114,409.274658,5.60250664,120,0,0,1,0,0,0), +(@GUID+30,31052,571,1,0x00000040,0,0,5100.06543,2168.89,365.7788,1.97222209,120,0,0,1,0,0,0), +(@GUID+31,31052,571,1,0x00000080,0,0,5302.57373,2750.40332,409.274658,5.46288061,120,0,0,1,0,0,0), +(@GUID+32,31054,571,1,0x00000040,0,0,5088.611,2167.66235,365.688751,0.6806784,120,0,0,1,0,0,0), +(@GUID+33,31054,571,1,0x00000080,0,0,5372.05859,3028.33618,409.206024,0.012565271,120,0,0,1,0,0,0), +(@GUID+34,31108,571,1,0x00000040,0,0,5095.673,2193.284,365.9236,4.939282,120,0,0,1,0,0,0), +(@GUID+35,31108,571,1,0x00000080,0,0,5298.267,2924.97632,409.274658,0.9075712,120,0,0,1,0,0,0), +(@GUID+36,31109,571,1,0x00000040,0,0,5080.403,2199.00244,359.4894,2.96705961,120,0,0,1,0,0,0), +(@GUID+37,31109,571,1,0x00000080,0,0,5228.2915,2809.888,409.274658,3.19395256,120,0,0,1,0,0,0), +(@GUID+38,31153,571,1,0x00000040,0,0,5088.48633,2188.17871,365.646973,5.253441,120,0,0,1,0,0,0), +(@GUID+39,31153,571,1,0x00000080,0,0,5364.784,2835.135,409.3225,3.12413931,120,0,0,1,0,0,0), +(@GUID+40,32294,571,1,0x00000080,0,0,5374.568,2790.784,409.3225,2.72271371,120,0,0,1,0,0,0), +(@GUID+41,39172,571,1,0x00000080,0,0,5372.672,2786.74048,409.4423,2.80998015,120,0,0,1,0,0,0), +(@GUID+42,30488,571,1,0x00000080,0,0,5370.428,2814.274,409.3225,3.054326,120,0,0,1,0,0,0), +-- Horde NPC's +(@GUID+43,30870,571,1,0x00000001,0,0,5023.4043,3686.03345,363.1192,5.131268,120,0,0,1,0,0,0), +(@GUID+44,31053,571,1,0x00000040,0,0,5379.875,3027.43359,409.206024,0,120,0,0,1,0,0,0), +(@GUID+45,31053,571,1,0x00000080,0,0,5034.703125,3666.703125,363.273865,4.310963,120,0,0,1,0,0,0), +(@GUID+46,31091,571,1,0x00000040,0,0,5347.7915,2837.38574,409.3466,2.62603331,120,0,0,1,0,0,0), +(@GUID+47,31091,571,1,0x00000080,0,0,5018.662109,3672.279541,362.862885,2.209141,120,0,0,1,0,0,0), +(@GUID+48,31101,571,1,0x00000040,0,0,5296.564,2789.87378,409.274658,0.7330383,120,0,0,1,0,0,0), +(@GUID+49,31101,571,1,0x00000080,0,0,5014.065430,3678.846436,362.995575,5.096361,120,0,0,1,0,0,0), +(@GUID+50,31102,571,1,0x00000040,0,0,5295.455,2732.87549,409.274658,4.7211113,120,0,0,1,0,0,0), +(@GUID+51,31102,571,1,0x00000080,0,0,5031.676270,3655.820801,362.234558,5.131268,120,0,0,1,0,0,0), +(@GUID+52,31106,571,1,0x00000040,0,0,5295.56348,2926.67188,409.274658,0.87266463,120,0,0,1,0,0,0), +(@GUID+53,31106,571,1,0x00000080,0,0,5037.602051,3675.459717,363.147888,3.176499,120,0,0,1,0,0,0), +(@GUID+54,31107,571,1,0x00000040,0,0,5230.09033,2876.635,409.316254,-2.19854617,120,0,0,1,0,0,0), +(@GUID+55,31107,571,1,0x00000080,0,0,5004.455078,3661.089111,361.335785,3.979351,120,0,0,1,0,0,0), +(@GUID+56,31151,571,1,0x00000040,0,0,5363.2876,2834.52954,409.3606,2.76273036,120,0,0,1,0,0,0), +(@GUID+57,31151,571,1,0x00000080,0,0,5034.698242,3683.268799,363.129120,4.310963,120,0,0,1,0,0,0), +(@GUID+58,32296,571,1,0x00000040,0,0,5374.568,2790.784,409.3225,2.60054,120,0,0,1,0,0,0), +-- Missing noc in fortress +(@GUID+60,39173,571,1,0x00000040,0,0,5372.672,2786.74048,409.4423,2.80998015,120,0,0,1,0,0,0); + +DELETE FROM `creature_addon` WHERE `guid` IN (@GUID+26,@GUID+27,@GUID+38,@GUID+39,@GUID+40,@GUID+41,@GUID+57,@GUID+58,@GUID+59,@GUID+60); +INSERT INTO `creature_addon` (`guid`,`mount`,`path_id`,`bytes2`) VALUES +(@GUID+26,14337,0,257), -- Commander Zanneth "Horde Controlled" +(@GUID+27,14337,0,257), -- Commander Zanneth "Alliance Controlled" +(@GUID+38,6569,0,257), -- Tactical Officer Ahbramis "Horde Controlled" +(@GUID+39,6569,0,257), -- Tactical Officer Ahbramis "Alliance Controlled" +(@GUID+40,27247,0,1), -- Knight Dameron "Alliance Controlled" +(@GUID+41,28912,0,1), -- Marshal Magruder "Alliance Controlled" +(@GUID+58,27245,0,1), -- Stone Guard Mukar "Horde Controlled" +(@GUID+60,29261,0,1); -- Champion Ros'slai "Horde Controlled" + +-- Pathing for Anchorite Tessa Entry: 31054 +SET @NPC := @GUID+33; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5382.507,3028.468,409.206,0,0,0,100,0), +(@PATH,2,5392.744,3028.737,409.206,0,0,0,100,0), +(@PATH,3,5382.507,3028.468,409.206,0,0,0,100,0), +(@PATH,4,5371.491,3028.329,409.206,0,0,0,100,0), +(@PATH,5,5360.032,3028.516,409.3161,0,0,0,100,0), +(@PATH,6,5371.491,3028.329,409.206,0,0,0,100,0); + +-- Pathing for Commander Zanneth Entry: 31036 +SET @NPC := @GUID+27; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=5358.854,`position_y`=2859.232,`position_z`=409.5425 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,1,14337, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5359.788,2846.359,409.3642,0,0,0,100,0), +(@PATH,2,5359.187,2839.211,409.3642,0,0,0,100,0), +(@PATH,3,5360.083,2823.116,409.5381,0,0,0,100,0), +(@PATH,4,5359.187,2839.211,409.3642,0,0,0,100,0), +(@PATH,5,5359.788,2846.359,409.3642,0,0,0,100,0), +(@PATH,6,5358.854,2859.232,409.5425,0,0,0,100,0); + +-- Pathing for Commander Dardosh Entry: 31091 +SET @NPC := @GUID+46; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `MovementType`=2,`position_x`=5359.546,`position_y`=2858.049,`position_z`=409.3642 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,257,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5359.202,2843.208,409.3642,0,0,0,100,0), +(@PATH,2,5358.997,2827.974,409.3639,0,0,0,100,0), +(@PATH,3,5359.202,2843.208,409.3642,0,0,0,100,0), +(@PATH,4,5359.546,2858.049,409.3642,0,0,0,100,0); + +-- Pathing for Commander Dardosh Entry: 31091 +SET @NPC := @GUID+47; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `MovementType`=2,`position_x`=5018.411133,`position_y`=3672.615967,`position_z`=362.863525 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,257,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5022.827637,3666.665771,362.205750,0,0,0,100,0), +(@PATH,2,5024.270508,3658.739258,361.705750,0,0,0,100,0), +(@PATH,3,5022.827637,3666.665771,362.205750,0,0,0,100,0), +(@PATH,4,5018.411133,3672.615967,362.863525,0,0,0,100,0); + +-- Pathing for Primalist Mulfort Entry: 31053 +SET @NPC := @GUID+44; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `MovementType`=2 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,257,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5390.624,3027.994,409.206,0,0,0,100,0), +(@PATH,2,5379.875,3027.434,409.206,0,0,0,100,0), +(@PATH,3,5371.404,3026.511,409.206,0,0,0,100,0), +(@PATH,4,5379.875,3027.434,409.206,0,0,0,100,0); + +-- Pathing for Vieron Blazefeather Entry: 31102 +SET @NPC := @GUID+50; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `MovementType`=2,`position_x`=5296.644,`position_y`=2731.107,`position_z`=409.3163 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`bytes2`,`mount`,`auras`) VALUES (@NPC,@PATH,1,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`delay`,`move_flag`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,5295.544,2722.631,409.3163,0,0,0,100,0), +(@PATH,2,5296.644,2731.107,409.3163,0,0,0,100,0), +(@PATH,3,5297.874,2738.155,409.3163,0,0,0,100,0), +(@PATH,4,5305.192,2746.161,409.3061,0,0,0,100,0), +(@PATH,5,5297.874,2738.155,409.3163,0,0,0,100,0), +(@PATH,6,5296.644,2731.107,409.3163,0,0,0,100,0); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (30740); +INSERT INTO `creature_template_addon` (`entry`,`bytes2`,`emote`) VALUES +(30740,257,375); -- Guards "Alliance" + +-- Guards "Alliance" +SET @GUID := 291000; +DELETE FROM `creature` WHERE `id` IN (30740); +INSERT INTO `creature` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`modelid`,`equipment_id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`,`spawndist`,`currentwaypoint`,`curhealth`,`curmana`,`DeathState`,`MovementType`) VALUES +-- Fortress +(@GUID+0,30740,571,1,0x00000080,0,0,5150.26855,2786.02173,409.5469,3.22885919,120,0,0,1,0,0,0), +(@GUID+1,30740,571,1,0x00000080,0,0,5150.657,2777.9502,409.4053,2.94960642,120,0,0,1,0,0,0), +(@GUID+2,30740,571,1,0x00000080,0,0,5193.632,2734.172,409.272552,4.694936,120,0,0,1,0,0,0), +(@GUID+3,30740,571,1,0x00000080,0,0,5200.497,2733.88843,409.272552,4.677482,120,0,0,1,0,0,0), +(@GUID+4,30740,571,1,0x00000080,0,0,5264.64648,2670.1936,409.1819,3.07177949,120,0,0,1,0,0,0), +(@GUID+5,30740,571,1,0x00000080,0,0,5265.30566,2663.15381,409.1819,3.12413931,120,0,0,1,0,0,0), +(@GUID+6,30740,571,1,0x00000080,0,0,5307.02051,2613.89771,409.172363,4.694936,120,0,0,1,0,0,0), +(@GUID+7,30740,571,1,0x00000080,0,0,5311.133,3061.04248,408.809937,1.50098312,120,0,0,1,0,0,0), +(@GUID+8,30740,571,1,0x00000080,0,0,5315.87354,2614.21924,408.972748,4.677482,120,0,0,1,0,0,0), +(@GUID+9,30740,571,1,0x00000080,0,0,5318.09,3060.634,408.882782,1.62315619,120,0,0,1,0,0,0), +(@GUID+10,30740,571,1,0x00000080,0,0,5149.395,2897.044,409.304443,3.03687286,120,0,0,1,0,0,0), +(@GUID+11,30740,571,1,0x00000080,0,0,5149.51953,2904.19336,409.276062,3.07177949,120,0,0,1,0,0,0), +(@GUID+12,30740,571,1,0x00000080,0,0,5192.79248,2948.454,409.2746,1.50098312,120,0,0,1,0,0,0), +(@GUID+13,30740,571,1,0x00000080,0,0,5201.645,2948.77612,409.2746,1.62315619,120,0,0,1,0,0,0), +(@GUID+14,30740,571,1,0x00000080,0,0,5265.28,3010.10083,408.895782,2.82743335,120,0,0,1,0,0,0), +(@GUID+15,30740,571,1,0x00000080,0,0,5265.47559,3017.39941,408.582977,3.07177949,120,0,0,1,0,0,0), +(@GUID+16,30740,571,1,0x00000080,0,0,5367.91455,2826.52026,409.3225,3.33357882,120,0,0,1,0,0,0), +(@GUID+17,30740,571,1,0x00000080,0,0,5368.71338,2856.36035,409.3225,2.94960642,120,0,0,1,0,0,0), +(@GUID+18,30740,571,1,0x00000080,0,0,5388.56,2834.76782,418.7585,3.07177949,120,0,0,1,0,0,0), +(@GUID+19,30740,571,1,0x00000080,0,0,5389.272,2847.36816,418.7585,3.106686,120,0,0,1,0,0,0), +(@GUID+20,30740,571,1,0x00000080,0,0,4684.475,2414.28979,369.9621,-2.85779858,120,0,0,1,0,0,0), +(@GUID+21,30740,571,1,0x00000080,0,0,4692.75635,2392.88574,369.0177,-2.82921553,120,0,0,1,0,0,0), +(@GUID+22,30740,571,1,0x00000080,0,0,5327.264648,2659.455322,409.178711,3.069901,120,0,0,1,0,0,0), -- F1307814000A2DAD path +(@GUID+23,30740,571,1,0x00000080,0,0,5154.225586,2833.824219,409.262451,3.124139,120,0,0,1,0,0,0), +(@GUID+24,30740,571,1,0x00000080,0,0,5154.119629,2847.892822,409.247559,3.071779,120,0,0,1,0,0,0), +(@GUID+25,30740,571,1,0x00000080,0,0,5179.111328,2837.129639,409.274658,3.211406,120,0,0,1,0,0,0), +(@GUID+26,30740,571,1,0x00000080,0,0,5179.666504,2846.597900,409.274658,3.089233,120,0,0,1,0,0,0), +(@GUID+27,30740,571,1,0x00000080,0,0,5270.163086,2833.479248,409.274658,3.124139,120,0,0,1,0,0,0), +(@GUID+28,30740,571,1,0x00000080,0,0,5270.057129,2847.547607,409.274658,3.071779,120,0,0,1,0,0,0), +(@GUID+29,30740,571,1,0x00000080,0,0,5307.750000,3008.872559,409.193024,4.781681,120,0,0,1,0,0,0), -- F1307814000A43AE path +(@GUID+30,30740,571,1,0x00000080,0,0,5335.117188,2916.802002,409.443756,1.500983,120,0,0,1,0,0,0), +(@GUID+31,30740,571,1,0x00000080,0,0,5350.681152,2917.011719,409.274658,1.466077,120,0,0,1,0,0,0), +(@GUID+32,30740,571,1,0x00000080,0,0,5335.306152,2764.110352,409.274567,4.834562,120,0,0,1,0,0,0), +(@GUID+33,30740,571,1,0x00000080,0,0,5349.811523,2763.634766,409.333374,4.660029,120,0,0,1,0,0,0), +-- -- Eastspark Workshop +(@GUID+34,30740,571,1,0x00000080,0,0,4349.537,2411.25781,374.743317,2.05948853,120,0,0,1,0,0,0), +(@GUID+35,30740,571,1,0x00000080,0,0,4388.13135,2411.97827,374.743317,1.6406095,120,0,0,1,0,0,0), +(@GUID+36,30740,571,1,0x00000080,0,0,4391.6665,2300.60913,374.7433,4.92182827,120,0,0,1,0,0,0), +(@GUID+37,30740,571,1,0x00000080,0,0,4413.42969,2393.44946,376.3599,1.06465089,120,0,0,1,0,0,0), +(@GUID+38,30740,571,1,0x00000080,0,0,4417.92,2331.237,370.9189,5.846853,120,0,0,1,0,0,0), +(@GUID+39,30740,571,1,0x00000080,0,0,4349.11768,2299.27954,374.7433,4.904375,120,0,0,1,0,0,0), +(@GUID+40,30740,571,1,0x00000080,0,0,4418.608,2355.28735,372.4907,6.02138567,120,0,0,1,0,0,0); + +-- banners +SET @OGUID := 281000; +DELETE FROM `gameobject` WHERE `id` IN (192269,192284,192285,192338,192339,192488,192254,192255,192336,192501,192502); +DELETE FROM `gameobject` WHERE `id` BETWEEN 192349 AND 192379; +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID AND @OGUID+115; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +-- Fortress Banners "Alliance" +(@OGUID+0,192286,571,1,128,5371.44873,2820.79346,409.426575,3.124123,0,0,0,0,120,0,1), +(@OGUID+1,192287,571,1,128,5372.42432,2862.47925,409.3659,3.14159274,0,0,0,0,120,0,1), +(@OGUID+2,192292,571,1,128,5154.35059,2862.08423,445.0105,3.14159274,0,0,0,0,120,0,1), +(@OGUID+3,192299,571,1,128,5155.21631,2820.63013,444.9789,-3.115388,0,0,0,0,120,0,1), +(@OGUID+4,192304,571,1,128,5398.03564,2873.013,455.203552,3.132858,0,0,0,0,120,0,1), +(@OGUID+5,192305,571,1,128,5397.31348,2809.264,455.101624,3.132858,0,0,0,0,120,0,1), +(@OGUID+6,192306,571,1,128,5270.55469,2861.68237,444.917236,-3.124123,0,0,0,0,120,0,1), +(@OGUID+7,192307,571,1,128,5271.16064,2820.10864,445.109,-3.132858,0,0,0,0,120,0,1), +(@OGUID+8,192308,571,1,128,5235.12744,2942.12329,444.2792,1.58824873,0,0,0,0,120,0,1), +(@OGUID+9,192309,571,1,128,5272.549,2976.54175,444.493,3.132858,0,0,0,0,120,0,1), +(@OGUID+10,192310,571,1,128,5352.19775,3055.0166,444.5646,1.57952213,0,0,0,0,120,0,1), +(@OGUID+11,192312,571,1,128,5236.315,2739.21533,444.992828,-1.60570168,0,0,0,0,120,0,1), +(@OGUID+12,192313,571,1,128,5271.634,2704.829,445.182617,-3.124123,0,0,0,0,120,0,1), +(@OGUID+13,192314,571,1,128,5350.905,2622.48,444.649323,-1.56206989,0,0,0,0,120,0,1), +(@OGUID+14,192316,571,1,128,5322.013,2781.13281,435.6727,1.57952213,0,0,0,0,120,0,1), +(@OGUID+15,192317,571,1,128,5363.387,2781.27856,435.634125,1.58824873,0,0,0,0,120,0,1), +(@OGUID+16,192318,571,1,128,5322.24854,2898.94629,435.642975,-1.57952213,0,0,0,0,120,0,1), +(@OGUID+17,192319,571,1,128,5364.30371,2899.216,435.690826,-1.55334139,0,0,0,0,120,0,1), +(@OGUID+18,192320,571,1,128,5289.048,2820.22656,435.6738,0,0,0,0,0,120,0,1), +(@OGUID+19,192321,571,1,128,5288.847,2861.82128,435.590485,0.0261791088,0,0,0,0,120,0,1), +(@OGUID+20,192322,571,1,128,5322.89258,2917.14233,445.1543,1.56206989,0,0,0,0,120,0,1), +(@OGUID+21,192323,571,1,128,5364.283,2917.264,445.332184,1.58824611,0,0,0,0,120,0,1), +(@OGUID+22,192324,571,1,128,5290.514,2976.56177,435.087463,0.008724241,0,0,0,0,120,0,1), +(@OGUID+23,192325,571,1,128,5352.37744,3036.95483,435.111053,-1.56206989,0,0,0,0,120,0,1), +(@OGUID+24,192326,571,1,128,5392.64063,3036.967,433.648682,-1.51843357,0,0,0,0,120,0,1), +(@OGUID+25,192327,571,1,128,5172.336,2862.57544,435.65802,0,0,0,0,0,120,0,1), +(@OGUID+26,192328,571,1,128,5173.12842,2820.95654,435.657623,0.0261791088,0,0,0,0,120,0,1), +(@OGUID+27,192329,571,1,128,5235.32227,2924.31079,434.8981,-1.56206989,0,0,0,0,120,0,1), +(@OGUID+28,192330,571,1,128,5237.02344,2757.35669,435.625641,1.55334139,0,0,0,0,120,0,1), +(@OGUID+29,192331,571,1,128,5289.78125,2704.62158,435.714325,0.008724241,0,0,0,0,120,0,1), +(@OGUID+30,192332,571,1,128,5350.93945,2640.43066,435.2642,1.56206989,0,0,0,0,120,0,1), +(@OGUID+31,192333,571,1,128,5392.28027,2639.84033,435.207916,1.52716041,0,0,0,0,120,0,1), +(@OGUID+32,192334,571,1,128,5322.17041,2763.20142,444.9744,-1.56206715,0,0,0,0,120,0,1), +(@OGUID+33,192335,571,1,128,5363.71631,2763.24731,445.023132,-1.54461551,0,0,0,0,120,0,1), +(@OGUID+34,192487,571,1,128,5145.11133,2934.948,433.254852,-3.10665226,0,0,0,0,120,0,1), +(@OGUID+35,192487,571,1,128,5146.04443,2747.30249,433.527039,3.124123,0,0,0,0,120,0,1), +(@OGUID+36,192487,571,1,128,5158.71,2882.90161,431.27417,3.14159274,0,0,0,0,120,0,1), +(@OGUID+37,192487,571,1,128,5160.28369,2798.59766,430.6037,-3.124123,0,0,0,0,120,0,1), +(@OGUID+38,192487,571,1,128,5162.90674,2952.59766,433.368,1.57079577,0,0,0,0,120,0,1), +(@OGUID+39,192487,571,1,128,5163.85,2729.677,433.327545,-1.60570168,0,0,0,0,120,0,1), +(@OGUID+40,192487,571,1,128,5260.82471,2631.81763,433.181061,3.124123,0,0,0,0,120,0,1), +(@OGUID+41,192487,571,1,128,5262.544,3047.93018,431.96524,3.124123,0,0,0,0,120,0,1), +(@OGUID+42,192487,571,1,128,5278.43066,2613.83276,433.294434,-1.62315571,0,0,0,0,120,0,1), +(@OGUID+43,192487,571,1,128,5280.894,3064.95386,431.9758,1.55334139,0,0,0,0,120,0,1), +-- Fortress Banners "Horde" +(@OGUID+44,192269,571,1,64,4526.46,2810.18,391.2,-2.99322,0,0,0,1,180,0,1), +(@OGUID+45,192284,571,1,64,5372.48,2862.5,409.049,3.14159,0,0,0,1,180,0,1), +(@OGUID+46,192285,571,1,64,5371.49,2820.8,409.177,3.14159,0,0,0,1,180,0,1), +(@OGUID+47,192338,571,1,64,5397.76,2873.08,455.461,3.10665,0,0,0,1,180,0,1), +(@OGUID+48,192339,571,1,64,5397.39,2809.33,455.344,3.10665,0,0,0,1,180,0,1), +(@OGUID+49,192349,571,1,64,5155.31,2820.74,444.979,-3.13286,0,0,0,1,180,0,1), +(@OGUID+50,192350,571,1,64,5270.69,2861.78,445.058,-3.11539,0,0,0,1,180,0,1), +(@OGUID+51,192351,571,1,64,5271.28,2820.16,445.201,-3.13286,0,0,0,1,180,0,1), +(@OGUID+52,192352,571,1,64,5173.02,2820.93,435.72,0.017452,0,0,0,1,180,0,1), +(@OGUID+53,192353,571,1,64,5172.11,2862.57,435.721,0.017452,0,0,0,1,180,0,1), +(@OGUID+54,192354,571,1,64,5288.41,2861.79,435.721,0.017452,0,0,0,1,180,0,1), +(@OGUID+55,192355,571,1,64,5288.92,2820.22,435.721,0.017452,0,0,0,1,180,0,1), +(@OGUID+56,192356,571,1,64,5237.07,2757.03,435.796,1.51844,0,0,0,1,180,0,1), +(@OGUID+57,192357,571,1,64,5235.34,2924.34,435.04,-1.5708,0,0,0,1,180,0,1), +(@OGUID+58,192358,571,1,64,5322.23,2899.43,435.808,-1.58825,0,0,0,1,180,0,1), +(@OGUID+59,192359,571,1,64,5364.35,2899.4,435.839,-1.5708,0,0,0,1,180,0,1), +(@OGUID+60,192360,571,1,64,5352.37,3037.09,435.252,-1.5708,0,0,0,1,180,0,1), +(@OGUID+61,192361,571,1,64,5392.65,3037.11,433.713,-1.52716,0,0,0,1,180,0,1), +(@OGUID+62,192362,571,1,64,5322.12,2763.61,444.974,-1.55334,0,0,0,1,180,0,1), +(@OGUID+63,192363,571,1,64,5363.61,2763.39,445.024,-1.54462,0,0,0,1,180,0,1), +(@OGUID+64,192364,571,1,64,5350.88,2622.72,444.686,-1.5708,0,0,0,1,180,0,1), +(@OGUID+65,192366,571,1,64,5236.27,2739.46,444.992,-1.59698,0,0,0,1,180,0,1), +(@OGUID+66,192367,571,1,64,5271.8,2704.87,445.183,-3.13286,0,0,0,1,180,0,1), +(@OGUID+67,192368,571,1,64,5289.46,2704.68,435.875,-0.017451,0,0,0,1,180,0,1), +(@OGUID+68,192369,571,1,64,5350.95,2640.36,435.408,1.5708,0,0,0,1,180,0,1), +(@OGUID+69,192370,571,1,64,5392.27,2639.74,435.331,1.50971,0,0,0,1,180,0,1), +(@OGUID+70,192371,571,1,64,5364.29,2916.94,445.331,1.57952,0,0,0,1,180,0,1), +(@OGUID+71,192372,571,1,64,5322.86,2916.95,445.154,1.56207,0,0,0,1,180,0,1), +(@OGUID+72,192373,571,1,64,5290.35,2976.56,435.221,0.017452,0,0,0,1,180,0,1), +(@OGUID+73,192374,571,1,64,5272.94,2976.55,444.492,3.12412,0,0,0,1,180,0,1), +(@OGUID+74,192375,571,1,64,5235.19,2941.9,444.278,1.58825,0,0,0,1,180,0,1), +(@OGUID+75,192376,571,1,64,5352.19775,3055.0166,444.5646,1.57952,0,0,0,0,120,0,1), +(@OGUID+76,192377,571,1,64,5414.19,3069.8,415.187,1.64061,0,0,0,1,180,0,1), +(@OGUID+77,192378,571,1,64,5322.02,2781.13,435.811,1.5708,0,0,0,1,180,0,1), +(@OGUID+78,192379,571,1,64,5363.42,2781.03,435.763,1.5708,0,0,0,1,180,0,1), +(@OGUID+79,192254,571,1,64,5154.46,2828.94,409.189,3.14159,0,0,0,1,180,0,1), +(@OGUID+80,192255,571,1,64,5154.52,2853.31,409.183,3.14159,0,0,0,1,180,0,1), +(@OGUID+81,192336,571,1,64,5154.49,2862.15,445.012,3.14159,0,0,0,1,180,0,1), +(@OGUID+82,192488,571,1,64,5160.34,2798.61,430.769,3.14159,0,0,0,1,180,0,1), +(@OGUID+83,192488,571,1,64,5158.81,2883.13,431.618,3.14159,0,0,0,1,180,0,1), +(@OGUID+84,192488,571,1,64,5278.38,2613.83,433.409,-1.58825,0,0,0,1,180,0,1), +(@OGUID+85,192488,571,1,64,5260.82,2631.8,433.324,3.05433,0,0,0,1,180,0,1), +(@OGUID+86,192488,571,1,64,5163.13,2952.59,433.503,1.53589,0,0,0,1,180,0,1), +(@OGUID+87,192488,571,1,64,5145.11,2935,433.386,3.14159,0,0,0,1,180,0,1), +(@OGUID+88,192488,571,1,64,5262.54,3047.95,432.055,3.10665,0,0,0,1,180,0,1), +(@OGUID+89,192488,571,1,64,5146.04,2747.21,433.584,3.07177,0,0,0,1,180,0,1), +(@OGUID+90,192488,571,1,64,5163.78,2729.68,433.394,-1.58825,0,0,0,1,180,0,1), +(@OGUID+91,192488,571,1,64,5280.894,3064.95386,431.9758,1.55334139,0,0,0,0,120,0,1), +-- Tower Banners "Alliance" +(@OGUID+92,192501,571,1,64,4398.82,2804.7,429.792,-1.58825,0,0,0,1,180,0,1), +(@OGUID+93,192501,571,1,64,4416,2822.67,429.851,-0.017452,0,0,0,1,180,0,1), +(@OGUID+94,192501,571,1,64,4559.11,3606.22,419.999,-1.48353,0,0,0,1,180,0,1), +(@OGUID+95,192501,571,1,64,4539.42,3622.49,420.034,-3.07177,0,0,0,1,180,0,1), +(@OGUID+96,192501,571,1,64,4555.26,3641.65,419.974,1.67551,0,0,0,1,180,0,1), +(@OGUID+97,192501,571,1,64,4574.87,3625.91,420.079,0.087266,0,0,0,1,180,0,1), +(@OGUID+98,192501,571,1,64,4466.79,1960.42,459.144,1.15192,0,0,0,1,180,0,1), +(@OGUID+99,192501,571,1,64,4475.35,1937.03,459.07,-0.436332,0,0,0,1,180,0,1), +(@OGUID+100,192501,571,1,64,4451.76,1928.1,459.076,-2.00713,0,0,0,1,180,0,1), +(@OGUID+101,192501,571,1,64,4442.99,1951.9,459.093,2.74016,0,0,0,1,180,0,1), +(@OGUID+102,192501,571,1,64,4380.36328,2822.38013,429.8818,-3.106652,0,0,0,0,120,0,1), +(@OGUID+103,192501,571,1,64,4397.6626,2840.299,429.921661,1.58824873,0,0,0,0,120,0,1), +-- Tower Banners "Horde" +(@OGUID+104,192502,571,1,128,4398.82,2804.7,429.792,-1.58825,0,0,0,1,180,0,1), +(@OGUID+105,192502,571,1,128,4416,2822.67,429.851,-0.017452,0,0,0,1,180,0,1), +(@OGUID+106,192502,571,1,128,4559.11,3606.22,419.999,-1.48353,0,0,0,1,180,0,1), +(@OGUID+107,192502,571,1,128,4539.42,3622.49,420.034,-3.07177,0,0,0,1,180,0,1), +(@OGUID+108,192502,571,1,128,4555.26,3641.65,419.974,1.67551,0,0,0,1,180,0,1), +(@OGUID+109,192502,571,1,128,4574.87,3625.91,420.079,0.087266,0,0,0,1,180,0,1), +(@OGUID+110,192502,571,1,128,4466.79,1960.42,459.144,1.15192,0,0,0,1,180,0,1), +(@OGUID+111,192502,571,1,128,4475.35,1937.03,459.07,-0.436332,0,0,0,1,180,0,1), +(@OGUID+112,192502,571,1,128,4451.76,1928.1,459.076,-2.00713,0,0,0,1,180,0,1), +(@OGUID+113,192502,571,1,128,4442.99,1951.9,459.093,2.74016,0,0,0,1,180,0,1), +(@OGUID+114,192502,571,1,128,4380.36328,2822.38013,429.8818,-3.106652,0,0,0,0,120,0,1), +(@OGUID+115,192502,571,1,128,4397.6626,2840.299,429.921661,1.58824873,0,0,0,0,120,0,1); + +SET @OGUID := 280000; +DELETE FROM `gameobject` WHERE `id` IN (192458,192459,192460,192461,192289,192290,192434,192435,192280,192283,192425,192426,192427,192428,192288,192291); +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +-- The Sunken Ring "Horde" +(@OGUID+0,192458,571,1,16,4811.4,2441.9,358.207,-2.0333,0,0,0,1,180,0,1), +(@OGUID+1,192459,571,1,16,4805.67,2407.48,358.191,1.78023,0,0,0,1,180,0,1), +(@OGUID+2,192460,571,1,16,5004.35,2486.36,358.449,2.17294,0,0,0,1,180,0,1), +(@OGUID+3,192461,571,1,16,4983.28,2503.09,358.177,-0.427603,0,0,0,1,180,0,1), +(@OGUID+4,192289,571,1,16,4778.19,2438.06,345.644,-2.94088,0,0,0,1,180,0,1), +(@OGUID+5,192290,571,1,16,5024.57,2532.75,344.023,-1.93732,0,0,0,1,180,0,1), +-- The Sunken Ring "Alliance" +(@OGUID+6,192425,571,1,32,4811.435,2441.84546,357.982483,-2.02457881,0,0,0,0,120,0,1), +(@OGUID+7,192426,571,1,32,4805.514,2407.84375,357.940765,1.7715075,0,0,0,0,120,0,1), +(@OGUID+8,192427,571,1,32,5004.35,2486.36,358.449,2.17294,0,0,0,1,180,0,1), +(@OGUID+9,192428,571,1,32,4983.221,2503.27271,357.959534,-0.43633157,0,0,0,0,120,0,1), +(@OGUID+10,192288,571,1,32,4778.065,2438.02441,345.7063,-2.932139,0,0,0,0,120,0,1), +(@OGUID+11,192291,571,1,32,5024.608,2532.72583,344.4308,-1.94604158,0,0,0,0,120,0,1), +-- The Broken Temple "Horde" +(@OGUID+12,192434,571,1,16,5041.61,3294.4,382.15,-1.63188,0,0,0,1,180,0,1), +(@OGUID+13,192435,571,1,16,4855.63,3297.62,376.739,-3.13286,0,0,0,1,180,0,1), +(@OGUID+14,192280,571,1,16,4857.97,3335.44,368.881,-2.94959,0,0,0,1,180,0,1), +(@OGUID+15,192283,571,1,16,5006.34,3280.4,371.163,2.22529,0,0,0,1,180,0,1), +-- The Broken Temple "Alliance" +(@OGUID+16,192400,571,1,32,5041.650879,3294.318604,381.919952,-1.605702,0,0,0,1,180,0,1), +(@OGUID+17,192401,571,1,32,4855.444336,3297.600830,376.495758,-3.115388,0,0,0,1,180,0,1), +(@OGUID+18,192281,571,1,32,4857.971191,3335.415771,369.291901,-2.888511,0,0,0,1,180,0,1), +(@OGUID+19,192282,571,1,32,5006.322754,3280.362061,371.242249,2.242746,0,0,0,1,180,0,1); + +-- EVERYTHING UNDER HERE IS WIP + +-- Eastspark Workshop "Horde" +(@OGUID+20,192452,571,1,16,4416.7993,2414.0383,377.4869,0.0087,0,0,0,0,120,0,1), +-- Eastspark Workshop "Alliance" +(@OGUID+21,192416,571,1,32,4408.57,2422.61,377.179,1.58825,0,0,0,1,180,0,1), +(@OGUID+22,192417,571,1,32,4416.59,2414.08,377.196,0,0,0,0,1,180,0,1), +(@OGUID+23,192418,571,1,32,4417.25,2301.14,377.214,0.026179,0,0,0,1,180,0,1), +(@OGUID+24,192273,571,1,32,4417.94,2324.81,371.577,3.08051,0,0,0,1,180,0,1), +-- Westspark Workshop "Horde" + +-- Westspark Workshop "Alliance" +(@OGUID+25,192274,571,1,32,4424.15,3286.54,371.546,3.12412,0,0,0,1,180,0,1), +(@OGUID+26,192406,571,1,32,4438.3,3361.08,371.568,-0.017451,0,0,0,1,180,0,1), +(@OGUID+27,192407,571,1,32,4448.17,3235.63,370.412,-1.56207,0,0,0,1,180,0,1), +(@OGUID+28,192433,571,1,32,4401.63,3377.46,363.365,1.55334,0,0,0,1,180,0,1), + +-- *** in progress zone horde banner in phase 128 + 32 + +-- Winters Edge tower alliance +(192429,571,1,64,4464.123535 2855.453125 406.110596,0.829032,0,0,0,0,120,0,1); +(192430,571,1,64,4434.555664,2883.448730,406.025299,0.759217,0,0,0,0,120,0,1); +(192431,571,1,64,4349.900391,2885.561768,406.104889,1.605702,0,0,0,0,120,0,1); +(192414,571,1,64,4387.621582 2719.565918 389.935120,-1.544616,0,0,0,0,120,0,1); +-- Winters Edge tower horde +(192442,571,1,128,4350.039,2885.61377,406.3287,1.58824873,0,0,0,0,120,0,1); +(192443,571,1,128,4434.32568,2883.244,406.3456,0.767943859,0,0,0,0,120,0,1); +(192444,571,1,128,4464.17432,2855.3186,406.390961,0.802850962,0,0,0,0,120,0,1); +(192450,571,1,128,4387.59033,2719.90015,390.200531,-1.51843357,0,0,0,0,120,0,1); + +(192449,571,1,129,4517.75342,2717.231,387.811981,-1.53588688,0,0,0,0,120,0,1); +(192424,571,1,417,4563.70166,2171.03125,367.607056,-1.82386875,0,0,0,0,120,0,1), +(192626,571,1,65,4938.364,2454.59863,320.391785,-2.513274,0,0,0,0,120,0,1); +(192627,571,1,65,4939.48535,3339.65259,376.874939,0.890116632,0,0,0,0,120,0,1); + +192271 4424.741211 2975.604980 367.226807 1.701696 -- banner pole shawdowsight + + +-- Misc objects in fortress phased properly +SET @OGUID := 282000; +DELETE FROM `gameobject` WHERE `guid` IN (67165,67224,67222,67190,67195,67216,67193,67182,67186,67192,67161,67164,67180,67187); +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID AND @OGUID+55; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(@OGUID+0,193096,571,1,128,5379.885,3008.093,409.181915,-3.124123,0,0,0,0,120,0,1), +(@OGUID+1,193097,571,1,128,5381.73975,3008.15454,409.181915,2.98449826,0,0,0,0,120,0,1), +(@OGUID+2,193098,571,1,128,5383.672,3008.02783,409.181915,-3.115388,0,0,0,0,120,0,1), +(@OGUID+3,193099,571,1,128,5386.25342,3007.79614,409.181915,2.932139,0,0,0,0,120,0,1), +(@OGUID+4,193100,571,1,128,5387.354,3009.64941,409.181915,-1.30899549,0,0,0,0,120,0,1), +(@OGUID+5,193101,571,1,128,5381.12744,3010.09717,409.181915,-2.72271276,0,0,0,0,120,0,1), +(@OGUID+6,193102,571,1,128,5383.12061,3007.90967,410.8231,-2.530723,0,0,0,0,120,0,1), +(@OGUID+7,193103,571,1,128,5381.105,3007.89575,410.8231,-3.09791875,0,0,0,0,120,0,1), +(@OGUID+8,193104,571,1,128,5376.777,3010.619,409.191742,-2.60926127,0,0,0,0,120,0,1), +(@OGUID+9,193105,571,1,128,5381.47559,3010.24731,410.8231,-2.80997539,0,0,0,0,120,0,1), +(@OGUID+10,193106,571,1,128,5381.059,3009.85864,410.8231,2.66161919,0,0,0,0,120,0,1), +(@OGUID+11,193107,571,1,128,5381.038,3010.44263,410.8157,-2.0507617,0,0,0,0,120,0,1), +(@OGUID+12,193108,571,1,128,5379.83154,3007.82373,410.8161,-2.02457881,0,0,0,0,120,0,1), +(@OGUID+13,193109,571,1,128,5379.99463,3008.40356,410.815918,-3.03687477,0,0,0,0,120,0,1), +(@OGUID+14,193124,571,1,128,5293.65869,2924.44019,409.29306,1.20427489,0,0,0,0,120,0,1), +(@OGUID+15,193125,571,1,1,5293.28,2932.32813,409.065247,-2.49581814,0,0,0,0,120,0,1), +(@OGUID+16,193126,571,1,1,5292.30469,2930.5105,409.157135,-3.06302428,0,0,0,0,120,0,1), +(@OGUID+17,193127,571,1,64,5293.349,2923.712,409.844757,-1.8762306,0,0,0,0,120,0,1), +(@OGUID+18,193128,571,1,128,5293.12256,2895.22754,409.208771,-0.9861096,0,0,0,0,120,0,1), +(@OGUID+19,193129,571,1,128,5292.913,2895.54346,410.419617,-0.122171074,0,0,0,0,120,0,1), +(@OGUID+20,193130,571,1,128,5294.09473,2894.191,409.164063,-0.7330382,0,0,0,0,120,0,1), +(@OGUID+21,193131,571,1,128,5295.1875,2895.382,409.143219,-0.349065244,0,0,0,0,120,0,1), +(@OGUID+22,193132,571,1,128,5294.527,2895.57471,410.6591,-1.92858779,0,0,0,0,120,0,1), +(@OGUID+23,193133,571,1,128,5295.3916,2895.05737,410.6686,0.6894028,0,0,0,0,120,0,1), +(@OGUID+24,193134,571,1,128,5295.13525,2895.68481,410.618866,-2.22529364,0,0,0,0,120,0,1), +(@OGUID+25,193135,571,1,128,5294.97559,2895.33521,410.657684,-2.73143482,0,0,0,0,120,0,1), +(@OGUID+26,193136,571,1,128,5293.22559,2895.46436,410.413483,-0.802850962,0,0,0,0,120,0,1), +(@OGUID+27,193137,571,1,128,5295.56,2895.24146,410.628052,-2.11184788,0,0,0,0,120,0,1), +(@OGUID+28,193138,571,1,128,5293.741,2894.48169,409.183167,-2.72271276,0,0,0,0,120,0,1), +(@OGUID+29,193139,571,1,64,5294.599,2786.85254,409.8877,-2.356195,0,0,0,0,120,0,1), +(@OGUID+30,193140,571,1,64,5294.37939,2785.03833,409.175018,-2.33873963,0,0,0,0,120,0,1), +(@OGUID+31,193141,571,1,64,5293.205,2787.03052,409.218872,3.03687477,0,0,0,0,120,0,1), +(@OGUID+32,193142,571,1,64,5294.241,2786.42456,409.174347,0.0174524616,0,0,0,0,120,0,1), +(@OGUID+33,193143,571,1,64,5291.705,2785.86646,409.282135,-2.03330517,0,0,0,0,120,0,1), +(@OGUID+34,193144,571,1,64,5293.03369,2785.632,409.22522,-1.2915417,0,0,0,0,120,0,1), +(@OGUID+35,193145,571,1,64,5295.866,2787.7666,409.1923,2.155478,0,0,0,0,120,0,1), +(@OGUID+36,193146,571,1,64,5293.56445,2787.31079,410.55954,0.261798173,0,0,0,0,120,0,1), +(@OGUID+37,193147,571,1,128,5233.12061,2920.362,409.163544,-0.7243115,0,0,0,0,120,0,1), +(@OGUID+38,193148,571,1,128,5238.27539,2920.67358,409.256439,-0.418878615,0,0,0,0,120,0,1), +(@OGUID+39,193149,571,1,128,5235.902,2920.751,409.224457,-0.951203167,0,0,0,0,120,0,1), +(@OGUID+40,193150,571,1,128,5237.36963,2919.89771,409.556641,0.8202983,0,0,0,0,120,0,1), +(@OGUID+41,193151,571,1,128,5234.19775,2918.99731,409.322754,-2.33873963,0,0,0,0,120,0,1), +(@OGUID+42,193152,571,1,128,5234.52344,2921.76221,409.175781,-2.2165668,0,0,0,0,120,0,1), +(@OGUID+43,193153,571,1,128,5234.119,2918.93921,409.1339,-3.098036,0,0,0,0,120,0,1), +(@OGUID+44,193154,571,1,128,5234.26758,2919.40015,409.502869,-2.18166113,0,0,0,0,120,0,1), +(@OGUID+45,193155,571,1,128,5293.37939,2746.05566,409.22052,-0.06981169,0,0,0,0,120,0,1), +(@OGUID+46,193156,571,1,128,5293.65039,2755.67529,409.1913,-0.43633157,0,0,0,0,120,0,1), +(@OGUID+47,193157,571,1,128,5292.23535,2753.59473,409.0867,-0.357789934,0,0,0,0,120,0,1), +(@OGUID+48,193158,571,1,128,5292.42969,2748.62427,409.131042,0.253072351,0,0,0,0,120,0,1), +(@OGUID+49,193159,571,1,128,5293.384,2750.90283,409.234924,-0.0610866137,0,0,0,0,120,0,1), +(@OGUID+50,193160,571,1,64,5371.89746,2805.47583,409.3072,0.0610866137,0,0,0,0,120,0,1), +(@OGUID+51,193161,571,1,64,5376.616,2875.105,409.254822,1.59697616,0,0,0,0,120,0,1), +(@OGUID+52,193162,571,1,128,5377.54932,2870.92456,409.239166,-0.549776852,0,0,0,0,120,0,1), +(@OGUID+53,193163,571,1,128,5378.068,2813.61719,409.239166,1.55334139,0,0,0,0,120,0,1), +(@OGUID+54,193164,571,1,128,5378.921,2805.43677,409.239166,1.53588688,0,0,0,0,120,0,1), +(@OGUID+55,193165,571,1,128,5378.452,2876.67456,409.239166,1.54461825,0,0,0,0,120,0,1); + diff --git a/sql/updates/world_WinterGrasp.sql b/sql/updates/world_WinterGrasp.sql new file mode 100644 index 00000000000..0433c4b8b17 --- /dev/null +++ b/sql/updates/world_WinterGrasp.sql @@ -0,0 +1,341 @@ +-- Unused yet: +-- Wintergrasp is under attack! +-- Wintergrasp Fortress is under attack! +-- Winter's Edge Tower is under attack! +-- Eastern Bridge is under attack! +-- Western Bridge is under attack! +-- Westspark Bridge is under attack! +-- Flamewatch Tower is under attack! + +-- 'You have reached Rank 1: Corporal' Sent to player by raid leader +-- 'You have reached Rank 2: First Lieutenant' Sent to player by raid leader + +-- Wintergrasp coreside texts +DELETE FROM trinity_string WHERE entry BETWEEN 12050 AND 12072; +INSERT INTO `trinity_string` (`entry`,`content_default`,`content_loc1`,`content_loc2`,`content_loc3`,`content_loc4`,`content_loc5`,`content_loc6`,`content_loc7`,`content_loc8`)VALUES +(12050, '%s has been captured by %s ', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +(12051, '%s is under attack by %s', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12052, 'The Broken Temple siege workshop', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12053, 'Eastspark siege workshop', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12054, 'Westspark siege workshop', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12055, 'The Sunken Ring siege workshop', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12057, 'Alliance', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12056, 'Horde', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12058, 'The battle for Wintergrasp is about to begin!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12059, 'You have reached Rank 1: Corporal', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12060, 'You have reached Rank 2: First Lieutenant', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12061, 'The south-eastern keep tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12062, 'The north-eastern keep tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12063, 'The south-western keep tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12064, 'The north-western keep tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12065, '%s has been damaged !', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12066, '%s has been destroyed!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12067, 'The battle for Wintergrasp begin!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12068, '%s has successfully defended the Wintergrasp fortress!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12069, 'The southern tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12070, 'The eastern tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12071, 'The western tower', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +(12072, 'The Wintergrasp fortress has been captured by %s !', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + +-- Wintergrasp script texts +DELETE FROM `script_texts` WHERE entry BETWEEN -1850500 AND -1850507; +INSERT INTO `script_texts` (`npc_entry`,`entry`,`content_default`,`content_loc1`,`content_loc2`,`content_loc3`,`content_loc4`,`content_loc5`,`content_loc6`,`content_loc7`,`content_loc8`,`sound`,`type`,`language`,`emote`,`comment`)VALUES +(0, -1850500, 'Guide me to the Fortress Graveyard.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850501, 'Guide me to the Sunken Ring Graveyard.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850502, 'Guide me to the Broken Temple Graveyard.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850503, 'Guide me to the Westspark Graveyard.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850504, 'Guide me to the Eastspark Graveyard.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850505, 'Guide me back to the Horde landing camp.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850506, 'Guide me back to the Alliance landing camp.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''), +(0, -1850507, 'Se mettre dans la file pour le Joug-d''hiver.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, ''); -- (Needs proper english text) + +-- Wintergrasp queue template NPCs +UPDATE `creature_template` SET `ScriptName`= 'npc_wg_dalaran_queue' WHERE `entry` IN (32169,32170,35599,35596,35600,35601,35598,35603,35602,35597,35612,35611); + +-- 54640 Teleport (Teleports defenders behind the walls on the Isle of Ulduran, Strand of the Ancients) - FIX THIS? +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=54640; +INSERT INTO `spell_linked_spell` (`spell_trigger`,`spell_effect`,`type`,`comment`) VALUES (54640,54643,0, 'WG teleporter'); + +-- ??? +DELETE FROM `gameobject` WHERE `id` IN (194162,192951,192273,192274,192277,192280,192283,192289,192290,192338,192339,192406,192407,192414,192417,192418,192429,192433,192434,192435,192458,192459,192460,192461,192819,190475,190487,194959,194962,192829,190219,190220,191795,191796,191799,191800,191801,191802,191803,191804,191806,191807,191808,191809,190369,190370,190371,190372,190374,190376,190221,190373,190377,190378,191797,191798,191805,190356,190357,190358,190375,191810, 192488,192501,192374,192416,192375,192336,192255,192269,192254,192349,192366,192367,192364,192370,192369,192368,192362,192363,192379,192378,192355,192354,192358,192359,192284,192285,192371,192372,192373,192360,192361,192356,192352,192353,192357,192350,192351,190763,192501,192488,192269,192278) AND `map`=571; +DELETE FROM `creature` WHERE `id` IN (30739,30740,31102,31841,31151,31153,32296,31051,31106,31108,31109,31053,30489,39172,31107,32294,31101,30499,31842,31036,31091,39173,31052,30400,31054) AND `map`=571; + +-- ??? +UPDATE `creature_template` SET `InhabitType`=7 WHERE `entry`=27852; + +-- Wintergrasp spiritguide NPC script +UPDATE `creature_template` SET `ScriptName`= 'npc_wg_spiritguide' WHERE `entry` IN (31841,31842); + +-- Wintergrasp demolisher engineer NPC script +UPDATE `creature_template` SET `ScriptName`= 'npc_demolisher_engineerer' WHERE `entry` IN (30400,30499); + +-- 58730 Restricted Flight Area (Wintergrasp Eject) +DELETE FROM `spell_area` WHERE `spell`=58730; +INSERT INTO `spell_area` (`spell`,`area`,`quest_start`,`quest_start_active`,`quest_end`,`aura_spell`,`racemask`,`gender`,`autocast`)VALUES +(58730,4581,0,0,0,0,0,2,1), +(58730,4539,0,0,0,0,0,2,1), +(58730,4197,0,0,0,0,0,2,1), +(58730,4585,0,0,0,0,0,2,1), +(58730,4612,0,0,0,0,0,2,1), +(58730,4582,0,0,0,0,0,2,1), +(58730,4583,0,0,0,0,0,2,1), +(58730,4589,0,0,0,0,0,2,1), +(58730,4575,0,0,0,0,0,2,1), +(58730,4538,0,0,0,0,0,2,1), +(58730,4577,0,0,0,0,0,2,1); + +-- 57940 Essence of Wintergrasp +DELETE FROM `spell_area` WHERE `spell`=57940; +INSERT INTO `spell_area` (`spell`,`area`,`quest_start`,`quest_start_active`,`quest_end`,`aura_spell`,`racemask`,`gender`,`autocast`)VALUES +(57940,65,0,0,0,0,0,2,1), +(57940,66,0,0,0,0,0,2,1), +(57940,67,0,0,0,0,0,2,1), +(57940,206,0,0,0,0,0,2,1), +(57940,210,0,0,0,0,0,2,1), +(57940,394,0,0,0,0,0,2,1), +(57940,395,0,0,0,0,0,2,1), +(57940,1196,0,0,0,0,0,2,1), +(57940,2817,0,0,0,0,0,2,1), +(57940,3456,0,0,0,0,0,2,1), +(57940,3477,0,0,0,0,0,2,1), +(57940,3537,0,0,0,0,0,2,1), +(57940,3711,0,0,0,0,0,2,1), +(57940,4100,0,0,0,0,0,2,1), +(57940,4196,0,0,0,0,0,2,1), +(57940,4228,0,0,0,0,0,2,1), +(57940,4264,0,0,0,0,0,2,1), +(57940,4265,0,0,0,0,0,2,1), +(57940,4272,0,0,0,0,0,2,1), +(57940,4273,0,0,0,0,0,2,1), +(57940,4395,0,0,0,0,0,2,1), +(57940,4415,0,0,0,0,0,2,1), +(57940,4416,0,0,0,0,0,2,1), +(57940,4493,0,0,0,0,0,2,1), +(57940,4494,0,0,0,0,0,2,1), +(57940,4603,0,0,0,0,0,2,1); + +-- Wintergrasp Cannons (Spell 51421 : Fire Cannon) +UPDATE `creature_template` SET `faction_A`=1732,`faction_H`=1735,`spell1`=51421 WHERE `entry`=28366; -- *** WRONG **** +UPDATE `creature_template` SET `faction_A`=1732,`faction_H`=1732 WHERE `entry` IN (30499,30740, 28319); -- Alliance +UPDATE `creature_template` SET `faction_A`=1735,`faction_H`=1735 WHERE `entry` IN (30400,30739, 32629); -- Horde + +-- Added by Malcrom +UPDATE `creature_template` SET `faction_A`=1732,`faction_H`=1732 WHERE `entry` IN (28312); -- Alliance +UPDATE `creature_template` SET `faction_A`=1735,`faction_H`=1735 WHERE `entry` IN (32627); -- Horde + +-- New support-commands for battlefield class +DELETE FROM `command` WHERE name IN ('bf start', 'bf stop', 'bf enable', 'bf switch', 'bf timer'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES ('bf start',3,'Syntaxe: .bf start #battleid'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES ('bf stop',3,'Syntaxe: .bf stop #battleid'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES ('bf enable',3,'Syntaxe: .bf enable #battleid'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES ('bf switch',3,'Syntaxe: .bf switch #battleid'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES ('bf timer',3,'Syntaxe: .bf timer #battleid #timer'); + +-- 49899 Activate Robotic Arms +DELETE FROM `spell_scripts` WHERE `id`=49899; +INSERT INTO `spell_scripts` (`id`,`delay`,`command`,`datalong`,`datalong2`,`dataint`,`x`,`y`,`z`,`o`) VALUES +(49899,0,1,406,0,0,0,0,0,0); + +-- Wintergrasp creature addon cleanups +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131258 AND 131322; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131326 AND 131328; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131350 AND 131353; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131376 AND 131380; +DELETE FROM `creature_addon` WHERE `guid`=131392; +DELETE FROM `creature_addon` WHERE `guid`=131437; +DELETE FROM `creature_addon` WHERE `guid`=131458; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131631 AND 131634; +DELETE FROM `creature_addon` WHERE `guid`=131706; +DELETE FROM `creature_addon` WHERE `guid` BETWEEN 131727 AND 131731; + +-- Wintergrasp vehicle teleport +UPDATE `gameobject_template` SET `ScriptName`= 'go_wintergrasp_teleporter' WHERE `entry`=192951; + +-- Wintergrasp Quests - Horde +UPDATE `quest_template` SET `ExclusiveGroup`=13180 WHERE `entry` IN (13180, 13178); +UPDATE `quest_template` SET `ExclusiveGroup`=13185 WHERE `entry` IN (13185, 13223); +UPDATE `quest_template` SET `ExclusiveGroup`=13192 WHERE `entry` IN (13192, 13202); +UPDATE `quest_template` SET `ExclusiveGroup`=13199 WHERE `entry` IN (13193, 13199); +UPDATE `quest_template` SET `ExclusiveGroup`=13200 WHERE `entry` IN (13200, 13191); +UPDATE `quest_template` SET `ExclusiveGroup`=13201 WHERE `entry` IN (13201, 13194); + +-- Wintergrasp Quests - Alliance +UPDATE `quest_template` SET `ExclusiveGroup`=13179 WHERE `entry` IN (13179, 13177); +UPDATE `quest_template` SET `ExclusiveGroup`=13186 WHERE `entry` IN (13186, 13222); +UPDATE `quest_template` SET `ExclusiveGroup`=13195 WHERE `entry` IN (13195, 13156); +UPDATE `quest_template` SET `ExclusiveGroup`=13196 WHERE `entry` IN (13196, 13154); +UPDATE `quest_template` SET `ExclusiveGroup`=13198 WHERE `entry` IN (13198, 13153); + +-- Wintergrasp Questgiver NPCs - requires binding to Wintergrasp questgiver script +UPDATE `creature_template` SET `ScriptName`= 'npc_wintergrasp_quest_giver' WHERE `entry` IN (31054, 31052, 31091, 31036, 31101, 31107, 31053, 31051, 31153, 31151, 31102, 31106); + +-- Wintergrasp Catapult speed adjustments +UPDATE `creature_template` SET `speed_walk`=2.8,`speed_run`=1.6 WHERE `entry`=27881; + +-- Add Missing Horde Spirt Healer options Wintergrasp +DELETE FROM `gossip_menu_option` WHERE `menu_id`=10129 AND `id` IN (2,4); +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`action_script_id`,`box_coded`,`box_money`,`box_text`) VALUES +(10129,2,0, 'Guide me to the Broken Temple Graveyard.',1,1,0,0,0,0,0, ''), +(10129,4,0, 'Guide me to the Eastspark Graveyard.',1,1,0,0,0,0,0, ''); + +-- Add Spell Target position for Wintergrasp Graveyard spells +DELETE FROM `spell_target_position` WHERE `id` IN (59760,59762,59763,59765,59766,59767,59769); +INSERT INTO `spell_target_position` (`id`,`target_map`,`target_position_x`,`target_position_y`,`target_position_z`,`target_orientation`) VALUES +(59760,571,5537.986,2897.493,517.057,4.819249), -- Teleport: Fortress Graveyard +(59762,571,5104.750,2300.940,368.579,0.733038), -- Teleport: Sunken Ring "area 4538" +(59763,571,5099.120,3466.036,368.484,5.317802), -- Teleport: Broken Temple "area 4539 & 4589" +(59765,571,5032.454,3711.382,372.468,3.971623), -- Teleport: Horde Landing Zone +(59766,571,4331.716,3235.695,390.251,0.008500), -- Teleport: Westspark Factory Graveyard "area 4611" +(59767,571,4314.648,2408.522,392.642,6.268125), -- Teleport: Eastspark Factory Graveyard "area 4612" +(59769,571,5140.790,2179.120,390.950,1.972220); -- Teleport: Alliance Landing Zone + +-- Add scripts to Wintergrasp spirit guide gossip +UPDATE `gossip_menu_option` SET `action_script_id`=1012800 WHERE `menu_id` IN (10128,10129) AND `id`=0; +UPDATE `gossip_menu_option` SET `action_script_id`=1012801 WHERE `menu_id` IN (10128,10129) AND `id`=1; +UPDATE `gossip_menu_option` SET `action_script_id`=1012802 WHERE `menu_id` IN (10128,10129) AND `id`=2; +UPDATE `gossip_menu_option` SET `action_script_id`=1012803 WHERE `menu_id` IN (10128,10129) AND `id`=3; +UPDATE `gossip_menu_option` SET `action_script_id`=1012804 WHERE `menu_id` IN (10128,10129) AND `id`=4; +UPDATE `gossip_menu_option` SET `action_script_id`=1012805 WHERE `menu_id`=10128 AND `id`=5; +UPDATE `gossip_menu_option` SET `action_script_id`=1012806 WHERE `menu_id`=10129 AND `id`=5; + +-- Add Teleport graveyard Spells to gossip scripts +DELETE FROM `gossip_scripts` WHERE `id` IN (1012800,1012801,1012802,1012803,1012804,1012805,1012806); +INSERT INTO `gossip_scripts` (`id`,`delay`,`command`,`datalong`,`datalong2`) VALUES +(1012800,0,33,0,0),(1012800,0,15,59760,1), +(1012801,0,33,0,0),(1012801,0,15,59762,1), +(1012802,0,33,0,0),(1012802,0,15,59763,1), +(1012803,0,33,0,0),(1012803,0,15,59766,1), +(1012804,0,33,0,0),(1012804,0,15,59767,1), +(1012805,0,33,0,0),(1012805,0,15,59769,1), +(1012806,0,33,0,0),(1012806,0,15,59765,1); + +-- Taunka Spirit Guide SAI +SET @ENTRY := 31841; +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=@ENTRY; +DELETE FROM `creature_addon` WHERE `guid` IN (SELECT `guid` FROM `creature` WHERE `id`=@ENTRY); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=@ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,11,0,100,0,0,0,0,0,11,58729,0,0,0,0,0,1,0,0,0,0,0,0,0, 'on spawn aura self'), +(@ENTRY,0,1,0,1,0,100,0,0,0,30000,30000,11,22011,0,0,0,0,0,1,0,0,0,0,0,0,0, 'cast Spirit Heal Channel every 30 sec'); +-- Dwarven Spirit Guide SAI +SET @ENTRY := 31842; +UPDATE `creature_template` SET `AIName`= 'SmartAI' WHERE `entry`=@ENTRY; +DELETE FROM `creature_addon` WHERE `guid` IN (SELECT `guid` FROM `creature` WHERE `id`=@ENTRY); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=@ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@ENTRY,0,0,0,11,0,100,0,0,0,0,0,11,58729,0,0,0,0,0,1,0,0,0,0,0,0,0, 'on spawn aura self'), +(@ENTRY,0,1,0,1,0,100,0,0,0,30000,30000,11,22011,0,0,0,0,0,1,0,0,0,0,0,0,0, 'cast Spirit Heal Channel every 30 sec'); + +-- Gossip Menu insert from sniff +DELETE FROM `gossip_menu` WHERE `entry`=9904 AND `text_id`=13759; +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (9904,13759); +DELETE FROM `gossip_menu` WHERE `entry`=9904 AND `text_id`=13761; +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (9904,13761); +DELETE FROM `gossip_menu` WHERE `entry`=9923 AND `text_id`=14172; +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (9923,14172); +DELETE FROM `gossip_menu` WHERE `entry`=10229 AND `text_id`=14221; +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (10229,14221); + +-- Creature Gossip_menu_id Update from sniff +UPDATE `creature_template` SET `gossip_menu_id`=9904 WHERE `entry`=30400; +UPDATE `creature_template` SET `gossip_menu_id`=10229 WHERE `entry`=31091; +-- Creature Gossip_menu_option Update from sniff +DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (9904); +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`action_script_id`,`box_coded`,`box_money`,`box_text`) VALUES +(9904,0,0, 'I would like to build a catapult.',1,1,0,0,0,0,0, ''), +(9904,1,0, 'I would like to build a demolisher.',1,1,0,0,0,0,0, ''), +(9904,2,0, 'I would like to build a siege engine.',1,1,0,0,0,0,0, ''); +-- Add gossip_menu condition for 9904 Horde +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=9904; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`) VALUES +(14,9904,13759,0,1,33280), -- Must have Rank 1: Corporal +(14,9904,13759,1,1,55629), -- Or must have Rank 2: First Lieutenant +(14,9904,13761,0,11,33280), -- Must not have Rank 1: Corporal +(14,9904,13761,0,11,55629); -- Must not have Rank 2: First Lieutenant +-- Add gossip_menu condition for 9923 Alliance +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=9923; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`) VALUES +(14,9923,13798,0,1,33280), -- Must have Rank 1: Corporal +(14,9923,13798,1,1,55629), -- Or must have Rank 2: First Lieutenant +(14,9923,14172,0,11,33280), -- Must not have Rank 1: Corporal +(14,9923,14172,0,11,55629); -- Must not have Rank 2: First Lieutenant +-- Add conditions to gossip options horde +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9904; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`) VALUES +(15,9904,0,0,1,33280,0), -- Must have reached Rank 1: Corporal +(15,9904,0,1,1,55629,0), -- Or must have reached Rank 2: First Lieutenant +(15,9904,1,0,1,55629,0), -- Must have reached Rank 2: First Lieutenant +(15,9904,2,0,1,55629,0); -- Must have reached Rank 2: First Lieutenant +-- Add conditions to gossip options alliance +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9923; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`) VALUES +(15,9923,0,0,1,33280,0), -- Must have reached Rank 1: Corporal +(15,9923,0,1,1,55629,0), -- Or must have reached Rank 2: First Lieutenant +(15,9923,1,0,1,55629,0), -- Must have reached Rank 2: First Lieutenant +(15,9923,2,0,1,55629,0); -- Must have reached Rank 2: First Lieutenant + +-- Add scripts to Wintergrasp engineers +UPDATE `gossip_menu_option` SET `action_script_id`=990400 WHERE `menu_id` IN (9904,9923) AND `id`=0; +UPDATE `gossip_menu_option` SET `action_script_id`=990401 WHERE `menu_id` IN (9904,9923) AND `id`=1; +UPDATE `gossip_menu_option` SET `action_script_id`=990402 WHERE `menu_id` IN (9904) AND `id`=2; +UPDATE `gossip_menu_option` SET `action_script_id`=990403 WHERE `menu_id` IN (9923) AND `id`=2; +-- Add create vehicle Spells to gossip scripts +DELETE FROM `gossip_scripts` WHERE `id` IN (990400,990401,990402); +INSERT INTO `gossip_scripts` (`id`,`delay`,`command`,`datalong`,`datalong2`) VALUES +(990400,0,33,0,0),(990400,0,15,56663,1), +(990401,0,33,0,0),(990401,0,15,56575,1), +(990402,0,33,0,0),(990402,0,15,61408,1), +(990403,0,33,0,0),(990403,0,15,56661,1); + +-- NPC talk text insert from sniff +DELETE FROM `creature_text` WHERE `entry`=15214 AND `groupid` BETWEEN 0 AND 30; +DELETE FROM `creature_text` WHERE `entry` IN (31036,31091) AND `groupid` BETWEEN 0 AND 3; +DELETE FROM `creature_text` WHERE `entry` IN (31108,31109,34924) AND `groupid`=0; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(15214,0,0, 'Let the battle begin!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,1,0, 'The southern tower has been damaged!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,2,0, 'The southern tower has been destroyed!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,3,0, 'The eastern tower has been damaged!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,4,0, 'The eastern tower has been destroyed!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,5,0, 'The western tower has been damaged!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,6,0, 'The western tower has been destroyed!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,7,0, 'The north-western keep tower has been damaged!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,8,0, 'The north-western keep tower has been destroyed!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,9,0, 'The south-eastern keep tower has been damaged!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,10,0, 'The south-eastern keep tower has been destroyed!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,11,0, 'The Broken Temple siege workshop has been attacked by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,12,0, 'The Broken Temple siege workshop has been captured by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,13,0, 'The Broken Temple siege workshop has been attacked by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,14,0, 'The Broken Temple siege workshop has been captured by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,15,0, 'The Eastspark siege workshop has been attacked by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,16,0, 'The Eastspark siege workshop has been captured by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,17,0, 'The Eastspark siege workshop has been attacked by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,18,0, 'The Eastspark siege workshop has been captured by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,19,0, 'The Sunken Ring siege workshop has been attacked by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,20,0, 'The Sunken Ring siege workshop has been captured by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,21,0, 'The Sunken Ring siege workshop has been attacked by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,22,0, 'The Sunken Ring siege workshop has been captured by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,23,0, 'The Westspark siege workshop has been attacked by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,24,0, 'The Westspark siege workshop has been captured by the Alliance!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,25,0, 'The Westspark siege workshop has been attacked by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,26,0, 'The Westspark siege workshop has been captured by the Horde!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,27,0, 'The Alliance has defended Wintergrasp Fortress!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,28,0, 'The Alliance has captured Wintergrasp Fortress!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,29,0, 'The Horde has defended Wintergrasp Fortress!',3,0,100,0,0,0, 'Invisible Stalker'), +(15214,30,0, 'The Horde has captured Wintergrasp Fortress!',3,0,100,0,0,0, 'Invisible Stalker'), +-- Not sure if all Alliance text is here, need horde text +(31036,0,0, 'The first of the Horde towers has fallen! Destroy all three and we will hasten their retreat!',1,7,100,0,0,0, 'Commander Zanneth'), +(31036,1,0, 'The second tower has fallen! Destroy the final tower and we will hasten their retreat!',1,7,100,0,0,0, 'Commander Zanneth'), +(31036,2,0, 'The Horde towers have fallen! We have forced their hand. Finish off the remaining forces!',1,7,100,0,0,0, 'Commander Zanneth'), +(31036,3,0, 'Show those animals no mercy, $n!',0,7,100,0,0,0, 'Commander Zanneth'), +(31091,0,0, 'The first of the Alliance towers has fallen! Destroy all three and we will hasten their retreat!',1,7,100,0,0,0, 'Commander Dardosh'), +(31091,1,0, 'Lok''tar! The second tower falls! Destroy the final tower and we will hasten their retreat!',1,7,100,0,0,0, 'Commander Dardosh'), +(31091,2,0, 'The Alliance towers have fallen! We have forced their hand. Finish off the remaining forces!',1,7,100,0,0,0, 'Commander Dardosh'), +(31091,3,0, 'Show those animals no mercy, $n!',0,7,100,0,0,0, 'Commander Dardosh'), -- ??? +(31108,0,0, 'Stop the Horde from retrieving the embers, $n. We cannot risk them having the advantage when the battle resumes!',0,7,100,0,0,0, 'Siege Master Stouthandle'), +(31109,0,0, 'Destroy their foul machines of war, $n!',0,7,100,0,0,0, 'Senior Demolitionist Legoso'), +(34924,0,0, 'The gates have been breached! Defend the keep!',1,0,100,0,0,0, 'High Commander Halford Wyrmbane'); + + + + diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index ed3a5b47e76..5c1c34d56b6 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -39,6 +39,12 @@ class GameObjectAI virtual void Reset() {}; + // Pass parameters between AI + virtual void DoAction(const int32 /*param = 0 */) {} + virtual uint32 GetData(uint32 /*id = 0*/) { return 0; } + virtual void SetGUID(const uint64 &/*guid*/, int32 /*id = 0 */) {} + virtual uint64 GetGUID(int32 /*id = 0 */) { return 0; } + static int Permissible(const GameObject* go); virtual bool GossipHello(Player* /*player*/) {return false;} diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index 46cbd1abf5d..981a7fd3888 100755 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -134,6 +134,11 @@ namespace FactorySelector GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance()); ai_factory = ai_registry.GetRegistryItem(go->GetAIName()); + + //scriptname in db + if (!ai_factory) + if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) + return scriptedAI; //future goAI types go here diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp new file mode 100644 index 00000000000..7a745e52d6a --- /dev/null +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -0,0 +1,1155 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Battlefield.h" +#include "BattlefieldMgr.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "Map.h" +#include "MapManager.h" +#include "Group.h" +#include "WorldPacket.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "CreatureTextMgr.h" + +#include "GroupMgr.h" + +Battlefield::Battlefield() +{ + m_Timer = 0; + m_enable = true; + m_WarTime = false; + m_DefenderTeam = TEAM_NEUTRAL; + + m_TypeId = 0; + m_BattleId = 0; + m_ZoneId = 0; + m_MapId = 0; + m_MaxPlayer = 0; + m_MinPlayer = 0; + m_BattleTime = 0; + m_NoWarBattleTime = 0; + m_TimeForAcceptInvite = 20; + m_uiKickDontAcceptTimer = 1000; + + m_uiKickAfkTimer = 1000; + + m_LastResurectTimer = 30000; + m_StartGroupingTimer = 0; + m_StartGrouping = false; + StalkerGuid = 0; +} + +Battlefield::~Battlefield() +{ +} + +void Battlefield::HandlePlayerEnterZone(Player *plr, uint32 /*zone */ ) +{ + //If battle is start, + // if it not fully > invite player to join the war + // if it fully > announce to player that BF is full and kick after few second if he dont leave + if (IsWarTime()) + { + if (m_PlayersInWar[plr->GetTeamId()].size() + m_InvitedPlayers[plr->GetTeamId()].size() < m_MaxPlayer) //Not fully + { + InvitePlayerToWar(plr); + } + else //Full + { + //TODO:Send packet for announce it to player + m_PlayersWillBeKick[plr->GetTeamId()][plr->GetGUID()] = time(NULL) + 10; + InvitePlayerToQueue(plr); + } + } + else + { + //If time left is <15 minutes invite player to join queue + if (m_Timer <= m_StartGroupingTimer) + InvitePlayerToQueue(plr); + } + + //Add player in list of player in zone + m_players[plr->GetTeamId()].insert(plr->GetGUID()); + OnPlayerEnterZone(plr); //for scripting +} + +//Called when a player leave the zone +void Battlefield::HandlePlayerLeaveZone(Player *plr, uint32 /*zone */ ) +{ + if (IsWarTime()) + { + //if player is in war list + if (m_PlayersInWar[plr->GetTeamId()].find(plr->GetGUID()) != m_PlayersInWar[plr->GetTeamId()].end()) + { + m_PlayersInWar[plr->GetTeamId()].erase(plr->GetGUID()); + plr->GetSession()->SendBfLeaveMessage(m_BattleId); + if (Group* group = GetGroupPlayer(plr->GetGUID(), plr->GetTeamId())) // remove from raid group if player is member + { + // I think that now is not a hack + if (!group->RemoveMember(plr->GetGUID())) // group was disbanded + { + m_Groups[plr->GetTeamId()].erase(group->GetGUID()); + group->SetBattlefieldGroup(NULL); + sGroupMgr->RemoveGroup(group); + delete group; + } + } + OnPlayerLeaveWar(plr); //For scripting + } + } + + for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + itr->second->HandlePlayerLeave(plr); + + m_InvitedPlayers[plr->GetTeamId()].erase(plr->GetGUID()); + m_PlayersWillBeKick[plr->GetTeamId()].erase(plr->GetGUID()); + m_players[plr->GetTeamId()].erase(plr->GetGUID()); + SendRemoveWorldStates(plr); + RemovePlayerFromResurrectQueue(plr->GetGUID()); + OnPlayerLeaveZone(plr); //For scripting +} + +bool Battlefield::Update(uint32 diff) +{ + //When global timer is end + if (m_Timer <= diff) + { + //Here end of battle by timer + if (IsWarTime()) + EndBattle(true); + //Start of battle + else + StartBattle(); + } + else + m_Timer -= diff; + + //Some times before battle start invite player to queue + if (!m_StartGrouping && m_Timer <= m_StartGroupingTimer) + { + m_StartGrouping = true; + InvitePlayerInZoneToQueue(); + OnStartGrouping(); // for scripting + } + + bool objective_changed = false; + if (IsWarTime()) + { + if (m_uiKickAfkTimer <= diff) + { + m_uiKickAfkTimer = 1000; + KickAfk(); + } + else + m_uiKickAfkTimer -= diff; + + //Here kick player witch dont have accept invitation to join the war when time is end (time of windows) + if (m_uiKickDontAcceptTimer <= diff) + { + for (int team = 0; team < 2; team++) + for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); itr++) + if ((*itr).second <= time(NULL)) + KickPlayerFromBf((*itr).first); + InvitePlayerInZoneToWar(); + for (int team = 0; team < 2; team++) + for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); itr++) + if ((*itr).second <= time(NULL)) + KickPlayerFromBf((*itr).first); + + m_uiKickDontAcceptTimer = 1000; + } + else + m_uiKickDontAcceptTimer -= diff; + + for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) + if (itr->second->Update(diff)) + objective_changed = true; + } + + + if (m_LastResurectTimer <= diff) + { + for (uint8 i = 0; i < m_GraveYardList.size(); i++) + if (GetGraveYardById(i)) + m_GraveYardList[i]->Resurrect(); + m_LastResurectTimer = RESURRECTION_INTERVAL; + } + else + m_LastResurectTimer -= diff; + + return objective_changed; +} + +void Battlefield::InvitePlayerInZoneToQueue() +{ + for (uint8 team = 0; team < 2; ++team) + for (GuidSet::const_iterator p_itr = m_players[team].begin(); p_itr != m_players[team].end(); ++p_itr) + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + InvitePlayerToQueue(plr); +} + +void Battlefield::InvitePlayerToQueue(Player *plr) +{ + if (m_PlayersInQueue[plr->GetTeamId()].count(plr->GetGUID())) + return; + + if (m_PlayersInQueue[plr->GetTeam()].size() <= m_MinPlayer || m_PlayersInQueue[plr->GetTeam() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE].size() >= m_MinPlayer) + plr->GetSession()->SendBfInvitePlayerToQueue(m_BattleId); +} + +void Battlefield::InvitePlayerInQueueToWar() +{ + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) + { + for (GuidSet::const_iterator p_itr = m_PlayersInQueue[team].begin(); p_itr != m_PlayersInQueue[team].end(); ++p_itr) + { + if (Player* plr = sObjectAccessor->FindPlayer(*p_itr)) + { + if (m_PlayersInWar[plr->GetTeamId()].size() + m_InvitedPlayers[plr->GetTeamId()].size() < m_MaxPlayer) + InvitePlayerToWar(plr); + else + { + //Full + } + } + } + m_PlayersInQueue[team].clear(); + } +} + +void Battlefield::InvitePlayerInZoneToWar() +{ + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) + for (GuidSet::const_iterator p_itr = m_players[team].begin(); p_itr != m_players[team].end(); ++p_itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + { + if (m_PlayersInWar[plr->GetTeamId()].count(plr->GetGUID()) || m_InvitedPlayers[plr->GetTeamId()].count(plr->GetGUID())) + continue; + if (m_PlayersInWar[plr->GetTeamId()].size() + m_InvitedPlayers[plr->GetTeamId()].size() < m_MaxPlayer) + InvitePlayerToWar(plr); + else + { + //full + m_PlayersWillBeKick[plr->GetTeamId()][plr->GetGUID()] = time(NULL) + 10; + } + } + } +} + +void Battlefield::InvitePlayerToWar(Player *plr) +{ + if (!plr) + return; + + //TODO : needed ? + if (plr->isInFlight()) + return; + + if (plr->InArena() || plr->GetBattleground()) + { + m_PlayersInQueue[plr->GetTeamId()].erase(plr->GetGUID()); + return; + } + + if (plr->getLevel() < m_MinLevel) + { + if (m_PlayersWillBeKick[plr->GetTeamId()].count(plr->GetGUID()) == 0) + m_PlayersWillBeKick[plr->GetTeamId()][plr->GetGUID()] = time(NULL) + 10; + return; + } + //Check if player is not already in war + if (m_PlayersInWar[plr->GetTeamId()].count(plr->GetGUID()) || m_InvitedPlayers[plr->GetTeamId()].count(plr->GetGUID())) + return; + + m_PlayersWillBeKick[plr->GetTeamId()].erase(plr->GetGUID()); + m_InvitedPlayers[plr->GetTeamId()][plr->GetGUID()] = time(NULL) + m_TimeForAcceptInvite; + plr->GetSession()->SendBfInvitePlayerToWar(m_BattleId, m_ZoneId, m_TimeForAcceptInvite); +} + +void Battlefield::InitStalker(uint32 entry, float x, float y, float z, float o) +{ + if (Creature * creature = SpawnCreature(entry, x, y, z, o, TEAM_NEUTRAL)) + StalkerGuid = creature->GetGUID(); + else + sLog->outError("Battlefield::InitStalker: could not spawn Stalker (Creature entry %u), zone messeges will be un-available", entry); +} + +void Battlefield::KickAfk() +{ + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) + for (GuidSet::const_iterator p_itr = m_PlayersInWar[team].begin(); p_itr != m_PlayersInWar[team].end(); ++p_itr) + if (Player* plr = sObjectAccessor->FindPlayer((*p_itr))) + if (plr->isAFK()) + KickPlayerFromBf((*p_itr)); +} + +void Battlefield::KickPlayerFromBf(uint64 guid) +{ + if (Player* plr = sObjectAccessor->FindPlayer(guid)) + if (plr->GetZoneId() == GetZoneId()) + plr->TeleportTo(KickPosition); +} + +void Battlefield::StartBattle() +{ + if (m_WarTime) + return; + + for (int team = 0; team < BG_TEAMS_COUNT; team++) + { + m_PlayersInWar[team].clear(); + m_Groups[team].clear(); + } + + m_Timer = m_BattleTime; + m_WarTime = true; + + InvitePlayerInZoneToWar(); + InvitePlayerInQueueToWar(); + + PlaySoundToAll(BF_START); + + OnBattleStart(); +} + +void Battlefield::EndBattle(bool endbytimer) +{ + m_WarTime = false; + + m_StartGrouping = false; + + if (!endbytimer) + SetDefenderTeam(GetAttackerTeam()); + + if (GetDefenderTeam() == TEAM_ALLIANCE) + PlaySoundToAll(BF_ALLIANCE_WINS); // alliance wins sound + else + PlaySoundToAll(BF_HORDE_WINS); // horde wins sound + + + OnBattleEnd(endbytimer); + + //reset bf timer + m_Timer = m_NoWarBattleTime; + SendInitWorldStatesToAll(); +} + +void Battlefield::PlaySoundToAll(uint32 SoundID) +{ + WorldPacket data; + data.Initialize(SMSG_PLAY_SOUND, 4); + data << uint32(SoundID); + + for (int team = 0; team < BG_TEAMS_COUNT; team++) + for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + { + Player *plr = sObjectMgr->GetPlayer((*itr)); + if (plr) + plr->GetSession()->SendPacket(&data); + } +} + +bool Battlefield::HasPlayer(Player *plr) const +{ + return m_players[plr->GetTeamId()].find(plr->GetGUID()) != m_players[plr->GetTeamId()].end(); +} + +// Called in WorldSession::HandleBfQueueInviteResponse +void Battlefield::PlayerAcceptInviteToQueue(Player *plr) +{ + // Add player in queueVenez + m_PlayersInQueue[plr->GetTeamId()].insert(plr->GetGUID()); + // Send notification + plr->GetSession()->SendBfQueueInviteResponce(m_BattleId, m_ZoneId); +} +// Called in WorldSession::HandleBfExitRequest +void Battlefield::AskToLeaveQueue(Player *plr) +{ + // Remove player from queue + m_PlayersInQueue[plr->GetTeamId()].erase(plr->GetGUID()); +} + +// Called in WorldSession::HandleBfEntryInviteResponse +void Battlefield::PlayerAcceptInviteToWar(Player *plr) +{ + if (!IsWarTime()) + return; + + if (AddOrSetPlayerToCorrectBfGroup(plr)) + { + plr->GetSession()->SendBfEntered(m_BattleId); + m_PlayersInWar[plr->GetTeamId()].insert(plr->GetGUID()); + m_InvitedPlayers[plr->GetTeamId()].erase(plr->GetGUID()); + //Remove player AFK + if (plr->isAFK()) + plr->ToggleAFK(); + + OnPlayerJoinWar(plr); //for scripting + } +} + +void Battlefield::TeamCastSpell(TeamId team, int32 spellId) +{ + if (spellId > 0) + for (GuidSet::const_iterator p_itr = m_PlayersInWar[team].begin(); p_itr != m_PlayersInWar[team].end(); ++p_itr) + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + plr->CastSpell(plr, (uint32) spellId, true); + else + for (GuidSet::const_iterator p_itr = m_PlayersInWar[team].begin(); p_itr != m_PlayersInWar[team].end(); ++p_itr) + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + plr->RemoveAuraFromStack((uint32) - spellId); +} + +void Battlefield::BroadcastPacketZone(WorldPacket & data) const +{ + 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* plr = sObjectMgr->GetPlayer((*itr))) + plr->GetSession()->SendPacket(&data); +} + +void Battlefield::BroadcastPacketQueue(WorldPacket & data) const +{ + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) + for (GuidSet::const_iterator itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->GetSession()->SendPacket(&data); +} + +void Battlefield::BroadcastPacketWar(WorldPacket & data) const +{ + for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team) + for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->GetSession()->SendPacket(&data); +} + +WorldPacket Battlefield::BuildWarningAnnPacket(std::string msg) +{ + WorldPacket data(SMSG_MESSAGECHAT, 200); + + data << uint8(CHAT_MSG_RAID_BOSS_EMOTE); + data << uint32(LANG_UNIVERSAL); + data << uint64(0); + data << uint32(0); // 2.1.0 + data << uint32(1); + data << uint8(0); + data << uint64(0); + data << uint32(strlen(msg.c_str()) + 1); + data << msg.c_str(); + data << uint8(0); + + return data; +} + +void Battlefield::SendWarningToAllInZone(uint32 entry) +{ + if (Unit* unit = sObjectAccessor->FindUnit(StalkerGuid)) + if (Creature* stalker = unit->ToCreature()) + // FIXME: replaced CHAT_TYPE_END with CHAT_MSG_BG_SYSTEM_NEUTRAL to fix compile, it's a guessed change :/ + sCreatureTextMgr->SendChat(stalker, (uint8) entry, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_ADDON, TEXT_RANGE_ZONE); +} + +/*void Battlefield::SendWarningToAllInWar(int32 entry,...) +{ + const char *format = sObjectMgr->GetTrinityStringForDBCLocale(entry); + va_list ap; + char str [1024]; + va_start(ap, entry); + vsnprintf(str,1024,format, ap); + va_end(ap); + std::string msg = (std::string)str; + + WorldPacket data = BuildWarningAnnPacket(msg); + BroadcastPacketWar(data); +}*/ +void Battlefield::SendWarningToPlayer(Player *plr, uint32 entry) +{ + if (!plr) + return; + + if (Unit* unit = sObjectAccessor->FindUnit(StalkerGuid)) + if (Creature* stalker = unit->ToCreature()) + sCreatureTextMgr->SendChat(stalker, (uint8)entry, plr->GetGUID()); +} + +void Battlefield::SendUpdateWorldState(uint32 field, uint32 value) +{ + for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i) + for (GuidSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) + if (Player *plr = sObjectMgr->GetPlayer((*itr))) + plr->SendUpdateWorldState(field, value); +} + +void Battlefield::RegisterZone(uint32 zoneId) +{ + sBattlefieldMgr.AddZone(zoneId, this); +} + +void Battlefield::HideNpc(Creature * p_Creature) +{ + p_Creature->CombatStop(); + p_Creature->SetReactState(REACT_PASSIVE); + p_Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + p_Creature->SetPhaseMask(2, true); + p_Creature->DisappearAndDie(); + p_Creature->SetVisible(false); +} + +void Battlefield::ShowNpc(Creature * p_Creature, bool p_Aggressive) +{ + p_Creature->SetPhaseMask(1, true); + p_Creature->SetVisible(true); + p_Creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + if (!p_Creature->isAlive()) + p_Creature->Respawn(true); + if (p_Aggressive) + p_Creature->SetReactState(REACT_AGGRESSIVE); + else + { + p_Creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + p_Creature->SetReactState(REACT_PASSIVE); + } +} + +//***************************************************** +//*******************Group System********************** +//***************************************************** +Group *Battlefield::GetFreeBfRaid(TeamId TeamId) +{ + //if found free group we return it + for (GuidSet::const_iterator itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr) + if (Group* group = sGroupMgr->GetGroupByGUID(*itr)) + if (!group->IsFull()) + return group; + + return NULL; +} + +Group *Battlefield::GetGroupPlayer(uint64 guid, TeamId TeamId) +{ + for (GuidSet::const_iterator itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr) + if (Group* group = sGroupMgr->GetGroupByGUID(*itr)) + if (group->IsMember(guid)) + return group; + + return NULL; +} + +bool Battlefield::AddOrSetPlayerToCorrectBfGroup(Player *plr) +{ + if (!plr->IsInWorld()) + return false; + + if (Group* group = plr->GetGroup()) + group->RemoveMember(plr->GetGUID()); + + Group* group = GetFreeBfRaid(plr->GetTeamId()); + if (!group) + { + group = new Group; + group->SetBattlefieldGroup(this); + group->Create(plr); + sGroupMgr->AddGroup(group); + m_Groups[plr->GetTeamId()].insert(group->GetGUID()); + } + else if (group->IsMember(plr->GetGUID())) + { + uint8 subgroup = group->GetMemberGroup(plr->GetGUID()); + plr->SetBattlegroundOrBattlefieldRaid(group, subgroup); + } + else + group->AddMember(plr); + + return true; +} + +//***************End of Group System******************* + +//***************************************************** +//***************Spirit Guide System******************* +//***************************************************** +//-------------------- +//-Battlefield Method- +//-------------------- +BfGraveYard *Battlefield::GetGraveYardById(uint32 id) +{ + if (id < m_GraveYardList.size()) + { + if (m_GraveYardList[id]) + return m_GraveYardList[id]; + else + sLog->outError("Battlefield::GetGraveYardById Id:%u not existed", id); + } + else + sLog->outError("Battlefield::GetGraveYardById Id:%u cant be found", id); + + return NULL; +} + +WorldSafeLocsEntry const *Battlefield::GetClosestGraveYard(Player *plr) +{ + BfGraveYard* closestGY = NULL; + float maxdist = -1; + for (uint8 i = 0; i < m_GraveYardList.size(); i++) + { + if (m_GraveYardList[i]) + { + if (m_GraveYardList[i]->GetControlTeamId() != plr->GetTeamId()) + continue; + + float dist = m_GraveYardList[i]->GetDistance(plr); + if (dist < maxdist || maxdist < 0) + { + closestGY = m_GraveYardList[i]; + maxdist = dist; + } + } + } + + if (closestGY) + return sWorldSafeLocsStore.LookupEntry(closestGY->GetGraveYardId()); + + return NULL; +} + +void Battlefield::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid) +{ + for (uint8 i = 0; i < m_GraveYardList.size(); i++) + { + if (!m_GraveYardList[i]) + continue; + + if (m_GraveYardList[i]->HasNpc(npc_guid)) + { + m_GraveYardList[i]->AddPlayer(player_guid); + break; + } + } +} + +void Battlefield::RemovePlayerFromResurrectQueue(uint64 player_guid) +{ + for (uint8 i = 0; i < m_GraveYardList.size(); i++) + { + if (!m_GraveYardList[i]) + continue; + + if (m_GraveYardList[i]->HasPlayer(player_guid)) + { + m_GraveYardList[i]->RemovePlayer(player_guid); + break; + } + } +} + +void Battlefield::SendAreaSpiritHealerQueryOpcode(Player *pl, const uint64 &guid) +{ + sLog->outError("SendAreaSpiritHealerQueryOpcode"); + WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); + uint32 time = m_LastResurectTimer; // resurrect every 30 seconds + + data << guid << time; + ASSERT(pl && pl->GetSession()); + pl->GetSession()->SendPacket(&data); +} + +bool Battlefield::IncrementQuest(Player *player, uint32 quest, bool complete) +{ + if (!player) + return false; + + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); + if (!pQuest || player->GetQuestStatus(quest) == QUEST_STATUS_NONE) + return false; + + if (complete) + { + player->CompleteQuest(quest); + return true; + } + else + { + for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + { + int32 creature = pQuest->ReqCreatureOrGOId[i]; + if (uint32 spell_id = pQuest->ReqSpell[i]) + { + player->CastedCreatureOrGO(creature, 0, spell_id); + return true; + } + else if (creature > 0) + { + player->KilledMonsterCredit(creature, 0); + return true; + } + else if (creature < 0) + { + player->CastedCreatureOrGO(creature, 0, 0); + return true; + } + } + } + return false; +} + +//-------------------- +//-BfGraveYard Method- +//-------------------- +BfGraveYard::BfGraveYard(Battlefield *Bf) +{ + m_Bf = Bf; + m_GraveyardId = 0; + m_ControlTeam = TEAM_NEUTRAL; + m_SpiritGuide[0] = NULL; + m_SpiritGuide[1] = NULL; + m_ResurrectQueue.clear(); +} + +void BfGraveYard::Init(uint32 horde_entry, uint32 alliance_entry, float x, float y, float z, float o, TeamId startcontrol, uint32 gy) +{ + m_ControlTeam = startcontrol; + if (Creature * cre = m_Bf->SpawnCreature(horde_entry, x, y, z, o, TEAM_HORDE)) + { + m_SpiritGuide[TEAM_HORDE] = cre; + m_SpiritGuide[TEAM_HORDE]->SetReactState(REACT_PASSIVE); + if (m_ControlTeam == TEAM_ALLIANCE) + m_SpiritGuide[TEAM_HORDE]->SetVisible(false); + } + else + sLog->outError("BfGraveYard::Init can't spawn horde spiritguide %u", horde_entry); + + if (Creature * cre = m_Bf->SpawnCreature(alliance_entry, x, y, z, o, TEAM_ALLIANCE)) + { + m_SpiritGuide[TEAM_ALLIANCE] = cre; + m_SpiritGuide[TEAM_ALLIANCE]->SetReactState(REACT_PASSIVE); + if (m_ControlTeam == TEAM_HORDE) + m_SpiritGuide[TEAM_ALLIANCE]->SetVisible(false); + } + else + sLog->outError("BfGraveYard::Init can't spawn alliance spiritguide %u", alliance_entry); + + m_GraveyardId = gy; +} + +float BfGraveYard::GetDistance(Player *plr) +{ + const WorldSafeLocsEntry* ws = sWorldSafeLocsStore.LookupEntry(m_GraveyardId); + return plr->GetDistance2d(ws->x, ws->y); +} + +void BfGraveYard::AddPlayer(uint64 player_guid) +{ + if (!m_ResurrectQueue.count(player_guid)) + { + m_ResurrectQueue.insert(player_guid); + + Player* plr = sObjectMgr->GetPlayer(player_guid); + if (plr) + plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true); + } +} + +void BfGraveYard::RemovePlayer(uint64 player_guid) +{ + m_ResurrectQueue.erase(m_ResurrectQueue.find(player_guid)); + Player* plr = sObjectMgr->GetPlayer(player_guid); + + if (plr) + plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT); +} + +void BfGraveYard::Resurrect() +{ + if (m_ResurrectQueue.empty()) + return; + + for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) + { + //Get player object from his guid + Player* plr = sObjectMgr->GetPlayer(*itr); + if (!plr) + continue; + + //Cherck player isinworld and player is on good graveyard + if (plr->IsInWorld()) + if (m_SpiritGuide[m_ControlTeam]) + m_SpiritGuide[m_ControlTeam]->CastSpell(m_SpiritGuide[m_ControlTeam], SPELL_SPIRIT_HEAL, true); + + //Resurect player + plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true); + plr->ResurrectPlayer(1.0f); + plr->CastSpell(plr, 6962, true); + plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true); + + sObjectAccessor->ConvertCorpseForPlayer(plr->GetGUID()); + } + + m_ResurrectQueue.clear(); +} + +//For changing graveyard control +void BfGraveYard::ChangeControl(TeamId team) +{ + //Guide switching + if (m_SpiritGuide[1 - team]) + m_SpiritGuide[1 - team]->SetVisible(false); + if (m_SpiritGuide[team]) + m_SpiritGuide[team]->SetVisible(true); + + m_ControlTeam = team; + //Teleport to other graveyard, player witch were on this graveyard + RelocateDeadPlayers(); +} + +void BfGraveYard::RelocateDeadPlayers() +{ + WorldSafeLocsEntry const* ClosestGrave = NULL; + for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr) + { + Player* plr = sObjectMgr->GetPlayer(*itr); + if (!plr) + continue; + + if (ClosestGrave) + plr->TeleportTo(plr->GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); + else + { + ClosestGrave = m_Bf->GetClosestGraveYard(plr); + if (ClosestGrave) + plr->TeleportTo(plr->GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); + } + } +} + +//***************End Spirit Guide system*************** + +//***************************************************** +//**********************Misc*************************** +//***************************************************** +//Method for spawn creature on map +Creature *Battlefield::SpawnCreature(uint32 entry, Position pos, TeamId team) +{ + return SpawnCreature(entry, pos.m_positionX, pos.m_positionY, pos.m_positionZ, pos.m_orientation, team); +} + +Creature *Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId team) +{ + //Get map object + Map* map = const_cast < Map * >(sMapMgr->CreateBaseMap(m_MapId)); + if (!map) + { + sLog->outError("Can't create creature entry: %u map not found", entry); + return 0; + } + + //Create creature + Creature* pCreature = new Creature; + if (!pCreature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, 0, team, x, y, z, o)) + { + sLog->outError("Can't create creature entry: %u", entry); + delete pCreature; + return NULL; + } + + pCreature->SetHomePosition(x, y, z, o); + + CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); + if (!cinfo) + { + sLog->outErrorDb("Battleground::AddCreature: entry %u does not exist.", entry); + return NULL; + } + //force using DB speeds + pCreature->SetSpeed(MOVE_WALK, cinfo->speed_walk); + pCreature->SetSpeed(MOVE_RUN, cinfo->speed_run); + + //Set creature in world + map->Add(pCreature); + pCreature->setActive(true); + + return pCreature; +} + +//Method for spawning gameobject on map +GameObject *Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z, float o) +{ + //Get map object + Map *map = const_cast < Map * >(sMapMgr->CreateBaseMap(571)); + if (!map) + return 0; + + //Create gameobject + GameObject *go = new GameObject; + if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, PHASEMASK_NORMAL, x, y, z, o, 0, 0, 0, 0, 100, GO_STATE_READY)) + { + sLog->outErrorDb("Gameobject template %u not found in database! Battleground not created!", entry); + sLog->outError("Cannot create gameobject template %u! Battleground not created!", entry); + delete go; + return NULL; + } + + //Add in the world + map->Add(go); + go->setActive(true); + return go; +} + +//***************************************************** +//*******************CapturePoint********************** +//***************************************************** + +BfCapturePoint::BfCapturePoint(Battlefield *Bf):m_Bf(Bf), m_capturePoint(NULL) +{ + m_team = TEAM_NEUTRAL; + m_value = 0; + m_maxValue = 0; + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL; + m_OldState = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL; + m_capturePointEntry = 0; + m_neutralValuePct = 0; + m_maxSpeed = 0; +} + +bool BfCapturePoint::HandlePlayerEnter(Player *plr) +{ + if (m_capturePoint) + { + plr->SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldState1, 1); + plr->SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); + plr->SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct); + } + return m_activePlayers[plr->GetTeamId()].insert(plr->GetGUID()).second; +} + +void BfCapturePoint::HandlePlayerLeave(Player *plr) +{ + if (m_capturePoint) + plr->SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldState1, 0); + m_activePlayers[plr->GetTeamId()].erase(plr->GetGUID()); +} + +void BfCapturePoint::SendChangePhase() +{ + if (!m_capturePoint) + return; + + // send this too, sometimes the slider disappears, dunno why :( + SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldState1, 1); + // send these updates to only the ones in this objective + SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); + // send this too, sometimes it resets :S + SendUpdateWorldState(m_capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct); +} + +bool BfCapturePoint::SetCapturePointData(uint32 entry, uint32 /*map */ , float x, float y, float z, float o) +{ + sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Creating capture point %u", entry); + + // check info existence + GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry); + if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT) + { + sLog->outError("OutdoorPvP: GO %u is not capture point!", entry); + return false; + } + m_capturePoint = m_Bf->SpawnGameObject(entry, x, y, z, o); + if (m_capturePoint) + { + // get the needed values from goinfo + m_maxValue = goinfo->capturePoint.maxTime; + m_maxSpeed = m_maxValue / (goinfo->capturePoint.minTime ? goinfo->capturePoint.minTime : 60); + m_neutralValuePct = goinfo->capturePoint.neutralPercent; + m_minValue = m_maxValue * goinfo->capturePoint.neutralPercent / 100; + m_capturePointEntry = entry; + if (m_team == TEAM_ALLIANCE) + { + m_value = m_maxValue; + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE; + } + else + { + m_value = -m_maxValue; + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE; + } + return true; + } + + return false; +} + +bool BfCapturePoint::DelCapturePoint() +{ + if (m_capturePoint) + { + m_capturePoint->SetRespawnTime(0); // not save respawn time + m_capturePoint->Delete(); + m_capturePoint = NULL; + } + + return true; +} + +bool BfCapturePoint::Update(uint32 diff) +{ + if (!m_capturePoint) + return false; + + float radius = m_capturePoint->GetGOInfo()->capturePoint.radius; + + for (uint8 team = 0; team < 2; ++team) + for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + if (!m_capturePoint->IsWithinDistInMap(plr, radius) || !plr->IsOutdoorPvPActive()) + HandlePlayerLeave(plr); + + std::list < Player * >players; + Trinity::AnyPlayerInObjectRangeCheck checker(m_capturePoint, radius); + Trinity::PlayerListSearcher < Trinity::AnyPlayerInObjectRangeCheck > searcher(m_capturePoint, players, checker); + m_capturePoint->VisitNearbyWorldObject(radius, searcher); + + for (std::list < Player * >::iterator itr = players.begin(); itr != players.end(); ++itr) + if ((*itr)->IsOutdoorPvPActive()) + if (m_activePlayers[(*itr)->GetTeamId()].insert((*itr)->GetGUID()).second) + HandlePlayerEnter(*itr); + + // get the difference of numbers + float fact_diff = ((float) m_activePlayers[0].size() - (float) m_activePlayers[1].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL; + if (!fact_diff) + return false; + + uint32 Challenger = 0; + float maxDiff = m_maxSpeed * diff; + + if (fact_diff < 0) + { + // horde is in majority, but it's already horde-controlled -> no change + if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE && m_value <= -m_maxValue) + return false; + + if (fact_diff < -maxDiff) + fact_diff = -maxDiff; + + Challenger = HORDE; + } + else + { + // ally is in majority, but it's already ally-controlled -> no change + if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE && m_value >= m_maxValue) + return false; + + if (fact_diff > maxDiff) + fact_diff = maxDiff; + + Challenger = ALLIANCE; + } + + float oldValue = m_value; + TeamId oldTeam = m_team; + + m_OldState = m_State; + + m_value += fact_diff; + + if (m_value < -m_minValue) // red + { + if (m_value < -m_maxValue) + m_value = -m_maxValue; + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE; + m_team = TEAM_HORDE; + } + else if (m_value > m_minValue) // blue + { + if (m_value > m_maxValue) + m_value = m_maxValue; + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE; + m_team = TEAM_ALLIANCE; + } + else if (oldValue * m_value <= 0) // grey, go through mid point + { + // if challenger is ally, then n->a challenge + if (Challenger == ALLIANCE) + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE; + // if challenger is horde, then n->h challenge + else if (Challenger == HORDE) + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE; + m_team = TEAM_NEUTRAL; + } + else // grey, did not go through mid point + { + // old phase and current are on the same side, so one team challenges the other + if (Challenger == ALLIANCE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE)) + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE; + else if (Challenger == HORDE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE)) + m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE; + m_team = TEAM_NEUTRAL; + } + + if (m_value != oldValue) + SendChangePhase(); + + if (m_OldState != m_State) + { + //sLog->outError("%u->%u", m_OldState, m_State); + if (oldTeam != m_team) + ChangeTeam(oldTeam); + return true; + } + + return false; +} + +void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) +{ + for (uint8 team = 0; team < 2; ++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* plr = sObjectMgr->GetPlayer((*itr))) + plr->SendUpdateWorldState(field, value); +} + +void BfCapturePoint::SendObjectiveComplete(uint32 id, uint64 guid) +{ + uint8 team; + switch (m_State) + { + case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: + team = 0; + break; + case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: + team = 1; + break; + default: + return; + } + + // send to all players present in the area + for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->KilledMonsterCredit(id, guid); +} + +bool BfCapturePoint::IsInsideObjective(Player *plr) const +{ + return m_activePlayers[plr->GetTeamId()].find(plr->GetGUID()) != m_activePlayers[plr->GetTeamId()].end(); +} diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h new file mode 100644 index 00000000000..c083fbfb232 --- /dev/null +++ b/src/server/game/Battlefield/Battlefield.h @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BATTLEFIELD_H_ +#define BATTLEFIELD_H_ + +#include "Utilities/Util.h" +#include "SharedDefines.h" +#include "ZoneScript.h" +#include "WorldPacket.h" +#include "GameObject.h" + +enum BattlefieldTypes +{ + BATTLEFIELD_WG, // Wintergrasp + BATTLEFIELD_TB, // Tol Barad (cataclysm) +}; + +enum BattlefieldIDs +{ + BATTLEFIELD_BATTLEID_WG = 1, // Wintergrasp battle +}; + +enum BattlefieldObjectiveStates +{ + BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL = 0, + BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE, + BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE, + BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE, + BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE, + BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE, + BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE, +}; + +enum BattlefieldSounds +{ + BF_HORDE_WINS = 8454, + BF_ALLIANCE_WINS = 8455, + BF_START = 3439 +}; + +enum BattlefieldTimers +{ + BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL = 1000 +}; + +// some class predefs +class Player; +class GameObject; +class WorldPacket; +class Creature; +class Unit; + +class Battlefield; +class BfGraveYard; + +typedef std::set < uint64 > GuidSet; +typedef std::vector < BfGraveYard * >GraveYardVect; +typedef std::map < uint64, uint32 > PlayerTimerMap; + +class BfCapturePoint +{ +public: + BfCapturePoint(Battlefield * bf); + + virtual void FillInitialWorldStates(WorldPacket & /*data */ ) {} + + // send world state update to all players present + void SendUpdateWorldState(uint32 field, uint32 value); + + // send kill notify to players in the controlling faction + void SendObjectiveComplete(uint32 id, uint64 guid); + + // used when player is activated/inactivated in the area + virtual bool HandlePlayerEnter(Player * plr); + virtual void HandlePlayerLeave(Player * plr); + //virtual void HandlePlayerActivityChanged(Player * plr); + + // checks if player is in range of a capture credit marker + bool IsInsideObjective(Player * plr) const; + + // returns true if the state of the objective has changed, in this case, the OutdoorPvP must send a world state ui update. + virtual bool Update(uint32 diff); + virtual void ChangeTeam(TeamId /*oldTeam */ ) {} + virtual void SendChangePhase(); + + bool SetCapturePointData(uint32 entry, uint32 map, float x, float y, float z, float o); + GameObject *GetCapturePointGo() { return m_capturePoint; } + + TeamId GetTeamId() {return m_team;} +protected: + bool DelCapturePoint(); + + // active players in the area of the objective, 0 - alliance, 1 - horde + GuidSet m_activePlayers[2]; + + // total shift needed to capture the objective + float m_maxValue; + float m_minValue; + + // maximum speed of capture + float m_maxSpeed; + + // the status of the objective + float m_value; + TeamId m_team; + + // objective states + BattlefieldObjectiveStates m_OldState; + BattlefieldObjectiveStates m_State; + + // neutral value on capture bar + uint32 m_neutralValuePct; + + // pointer to the Battlefield this objective belongs to + Battlefield *m_Bf; + uint32 m_capturePointEntry; + GameObject *m_capturePoint; +}; + +class BfGraveYard +{ +public: + BfGraveYard(Battlefield *Bf); + + // method for change who control the graveyard + void ChangeControl(TeamId team); + TeamId GetControlTeamId() { return m_ControlTeam; } + + // use for found the nearest graveyard + float GetDistance(Player * plr); + void Init(uint32 horde_entry, uint32 alliance_entry, float x, float y, float z, float o, TeamId startcontrol, uint32 gy); + void AddPlayer(uint64 player_guid); + void RemovePlayer(uint64 player_guid); + + void Resurrect(); + void RelocateDeadPlayers(); + + bool HasNpc(uint64 guid) { return (m_SpiritGuide[0]->GetGUID() == guid || m_SpiritGuide[1]->GetGUID() == guid); } + bool HasPlayer(uint64 guid) { return m_ResurrectQueue.find(guid) != m_ResurrectQueue.end(); } + uint32 GetGraveYardId() { return m_GraveyardId; } + +protected: + + TeamId m_ControlTeam; + uint32 m_GraveyardId; + Creature *m_SpiritGuide[2]; + GuidSet m_ResurrectQueue; + Battlefield *m_Bf; +}; + +class Battlefield:public ZoneScript +{ + friend class BattlefieldMgr; + + public: + /// Constructor + Battlefield(); + /// Destructor + virtual ~Battlefield(); + + /// typedef of map witch store capturepoint and the associate gameobject entry + typedef std::map < uint32 /*lowguid */ , BfCapturePoint * >BfCapturePointMap; + + /// Call this to init the Battlefield + virtual bool SetupBattlefield() { return true; } + + /// Generate packet which contain all worldstatedata of area + virtual void FillInitialWorldStates(WorldPacket & /*data */ ) {} + + /// Call when a GameObject/Creature is created OR destroyed (view bool add) + void OnGameObjectCreate(GameObject * /*go */ , bool /*add */ ) {} + void OnCreatureCreate(Creature * /*cre */ , bool /*add */ ) {} + + /// Update data of a worldstate to all players present in zone + void SendUpdateWorldState(uint32 field, uint32 value); + + /** + * \brief Called every time for update bf data and time + * -Update timer for start/end battle + * -Invite player in zone to queue x minutes before start (x = m_StartGroupingTimer) + * -Kick Afk players + * \param diff : time ellapsed since last call (in ms) + */ + virtual bool Update(uint32 diff); + + /// Invite all player in zone, to join the queue, called x minutes before battle start in Update() + void InvitePlayerInZoneToQueue(); + /// Invite all player in queue to join battle on battle start + void InvitePlayerInQueueToWar(); + /// Invite all player in zone to join battle on battle start + void InvitePlayerInZoneToWar(); + + /// Called when a Unit is kill in battlefield zone + virtual void HandleKill(Player * /*killer */ , Unit * /*killed */ ) {}; + + uint32 GetTypeId() { return m_TypeId; } + uint32 GetZoneId() { return m_ZoneId; } + + void TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2 = 0); + + /// Return true if battle is start, false if battle is not started + bool IsWarTime() { return m_WarTime; } + + /// Enable or Disable battlefield + void SetEnable(bool enable) { m_enable = enable; } + /// Return if battlefield is enable + bool GetEnable() { return m_enable; } + + /** + * \brief Kick player from battlefield and teleport him to kick-point location + * \param guid : guid of player who must be kick + */ + void KickPlayerFromBf(uint64 guid); + + /// Called when player (plr) enter in zone + void HandlePlayerEnterZone(Player * plr, uint32 zone); + /// Called when player (plr) leave the zone + void HandlePlayerLeaveZone(Player * plr, uint32 zone); + + // All-purpose data storage 64 bit + virtual uint64 GetData64(uint32 DataId) { return m_Data64[DataId]; } + virtual void SetData64(uint32 DataId, uint64 Value) { m_Data64[DataId] = Value; } + + // All-purpose data storage 32 bit + virtual uint32 GetData(uint32 DataId) { return m_Data32[DataId]; } + virtual void SetData(uint32 DataId, uint32 Value) { m_Data32[DataId] = Value; } + + // Battlefield - generic methods + TeamId GetDefenderTeam() { return m_DefenderTeam; } + TeamId GetAttackerTeam() { return TeamId(1 - m_DefenderTeam); } + void SetDefenderTeam(TeamId team) { m_DefenderTeam = team; } + + // Group methods + /** + * \brief Find a not full battlefield group, if there is no, create one + * \param TeamId : Id of player team for who we search a group (plr->GetTeamId()) + */ + Group *GetFreeBfRaid(TeamId TeamId); + /// Return battlefield group where player is. + Group *GetGroupPlayer(uint64 guid, TeamId TeamId); + /// Force player to join a battlefield group + bool AddOrSetPlayerToCorrectBfGroup(Player * plr); + + // Graveyard methods + // Find which graveyard the player must be teleported to to be resurrected by spiritguide + WorldSafeLocsEntry const *GetClosestGraveYard(Player * plr); + + virtual void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid); + void RemovePlayerFromResurrectQueue(uint64 player_guid); + void SetGraveyardNumber(uint32 number) { m_GraveYardList.resize(number); } + BfGraveYard *GetGraveYardById(uint32 id); + + // Misc methods + Creature *SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId team); + Creature *SpawnCreature(uint32 entry, Position pos, TeamId team); + GameObject *SpawnGameObject(uint32 entry, float x, float y, float z, float o); + + // Script-methods + + /// Called on start + virtual void OnBattleStart() {}; + /// Called at the end of battle + virtual void OnBattleEnd(bool /*endbytimer */ ) {}; + /// Called x minutes before battle start when player in zone are invite to join queue + virtual void OnStartGrouping() {}; + /// Called when a player accept to join the battle + virtual void OnPlayerJoinWar(Player * /*plr */ ) {}; + /// Called when a player leave the battle + virtual void OnPlayerLeaveWar(Player * /*plr */ ) {}; + /// Called when a player leave battlefield zone + virtual void OnPlayerLeaveZone(Player * /*plr */ ) {}; + /// Called when a player enter in battlefield zone + virtual void OnPlayerEnterZone(Player * /*plr */ ) {}; + + WorldPacket BuildWarningAnnPacket(std::string msg); + void SendWarningToAllInZone(uint32 entry); + //void SendWarningToAllInWar(int32 entry, ...); -- UNUSED + void SendWarningToPlayer(Player * plr, uint32 entry); + + void PlayerAcceptInviteToQueue(Player * plr); + void PlayerAcceptInviteToWar(Player * plr); + uint32 GetBattleId() { return m_BattleId; } + void AskToLeaveQueue(Player * plr); + + virtual void DoCompleteOrIncrementAchievement(uint32 /*achievement */ , Player * /*player */ , uint8 /*incrementNumber = 1 */ ) {}; + + /// Send all worldstate data to all player in zone. + virtual void SendInitWorldStatesToAll() {}; + + /// Return if we can use mount in battlefield + bool CanFlyIn() { return !m_WarTime; } // Used for check if we can use flying mount or not + bool IncrementQuest(Player * player, uint32 quest, bool complete = false); + void SendAreaSpiritHealerQueryOpcode(Player * pl, const uint64 & guid); + + void StartBattle(); + void EndBattle(bool endbytimer); + + void HideNpc(Creature * p_Creature); + void ShowNpc(Creature * p_Creature, bool p_Aggressive); + + GraveYardVect GetGraveYardVect() { return m_GraveYardList; } + + uint32 GetTimer() { return m_Timer; } + void SetTimer(uint32 timer) { m_Timer = timer; } + + void PlaySoundToAll(uint32 SoundID); + + void InvitePlayerToQueue(Player * plr); + void InvitePlayerToWar(Player * plr); + + void InitStalker(uint32 entry, float x, float y, float z, float o); + +protected: + uint64 StalkerGuid; + uint32 m_Timer; // Global timer for event + bool m_enable; + bool m_WarTime; + TeamId m_DefenderTeam; + + // the map of the objectives belonging to this outdoorpvp + BfCapturePointMap m_capturePoints; + + // the set of player + GuidSet m_players[BG_TEAMS_COUNT]; // Players in zone + GuidSet m_PlayersInQueue[BG_TEAMS_COUNT]; // Players in the queue + GuidSet m_PlayersInWar[BG_TEAMS_COUNT]; // Players in WG combat + PlayerTimerMap m_InvitedPlayers[BG_TEAMS_COUNT]; + PlayerTimerMap m_PlayersWillBeKick[BG_TEAMS_COUNT]; + + //Variables that must exist for each battlefield + uint32 m_TypeId; // See enum BattlefieldTypes + uint32 m_BattleId; // BattleID (for packet) + uint32 m_ZoneId; // ZoneID of Wintergrasp = 4197 + uint32 m_MapId; // MapId where is Battlefield + uint32 m_MaxPlayer; // Maximum number of player that participated to Battlefield + uint32 m_MinPlayer; // Minimum number of player for Battlefield start + uint32 m_MinLevel; // Required level to participate at Battlefield + uint32 m_BattleTime; // Length of a battle + uint32 m_NoWarBattleTime; // Time between two battles + uint32 m_RestartAfterCrash; // Delay to restart Wintergrasp if the server crashed during a running battle. + uint32 m_TimeForAcceptInvite; + uint32 m_uiKickDontAcceptTimer; + WorldLocation KickPosition; // Position where player is teleport if they switch to afk during battle or if they dont accept invitation + + uint32 m_uiKickAfkTimer; // Timer for check Afk in war + + //Graveyard variables + GraveYardVect m_GraveYardList; // Vector witch contain the different GY of the battle + uint32 m_LastResurectTimer; // Timer for resurect player every 30 sec + + uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle + bool m_StartGrouping; // bool for know if all players in area has been invited + + GuidSet m_Groups[BG_TEAMS_COUNT]; // Contain different raid group + + std::vector < uint64 > m_Data64; + std::vector < uint32 > m_Data32; + + void KickAfk(); + // use for switch off all worldstate for client + virtual void SendRemoveWorldStates(Player * /*plr */ ) {} + + // use for send a packet for all player list + void BroadcastPacketZone(WorldPacket & data) const; + void BroadcastPacketQueue(WorldPacket & data) const; + void BroadcastPacketWar(WorldPacket & data) const; + + //CapturePoint system + void AddCapturePoint(BfCapturePoint * cp) { m_capturePoints[cp->GetCapturePointGo()->GetEntry()] = cp; } + + BfCapturePoint *GetCapturePoint(uint32 lowguid) const + { + Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(lowguid); + if (itr != m_capturePoints.end()) + return itr->second; + return NULL; + } + + void RegisterZone(uint32 zoneid); + bool HasPlayer(Player * plr) const; + void TeamCastSpell(TeamId team, int32 spellId); + +}; + +#endif diff --git a/src/server/game/Battlefield/BattlefieldHandler.cpp b/src/server/game/Battlefield/BattlefieldHandler.cpp new file mode 100644 index 00000000000..b0d0a239d45 --- /dev/null +++ b/src/server/game/Battlefield/BattlefieldHandler.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "Battlefield.h" +#include "BattlefieldMgr.h" +#include "Opcodes.h" + +//This send to player windows for invite player to join the war +//Param1:(BattleId) the BattleId of Bf +//Param2:(ZoneId) the zone where the battle is (4197 for wg) +//Param3:(time) Time in second that the player have for accept +void WorldSession::SendBfInvitePlayerToWar(uint32 BattleId, uint32 ZoneId, uint32 p_time) +{ + //Send packet + WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, 12); + data << uint32(BattleId); + data << uint32(ZoneId); + data << uint32((time(NULL) + p_time)); + + //Sending the packet to player + SendPacket(&data); +} + +//This send invitation to player to join the queue +//Param1:(BattleId) the BattleId of Bf +void WorldSession::SendBfInvitePlayerToQueue(uint32 BattleId) +{ + WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, 5); + + data << uint32(BattleId); + data << uint8(1); //warmup ? used ? + + //Sending packet to player + SendPacket(&data); +} + +//This send packet for inform player that he join queue +//Param1:(BattleId) the BattleId of Bf +//Param2:(ZoneId) the zone where the battle is (4197 for wg) +void WorldSession::SendBfQueueInviteResponce(uint32 BattleId, uint32 ZoneId) +{ + WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, 11); + data << uint32(BattleId); + data << uint32(ZoneId); + data << uint8(1); //Accepted + data << uint8(0); //Logging In + data << uint8(1); //Warmup + + SendPacket(&data); +} + +//This is call when player accept to join war +//Param1:(BattleId) the BattleId of Bf +void WorldSession::SendBfEntered(uint32 BattleId) +{ +// m_PlayerInWar[plr->GetTeamId()].insert(plr->GetGUID()); + WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTERED, 7); + data << uint32(BattleId); + data << uint8(1); //unk + data << uint8(1); //unk + data << uint8(_player->isAFK() ? 1 : 0); //Clear AFK + + SendPacket(&data); +} + +//Send when player is kick from Battlefield +void WorldSession::SendBfLeaveMessage(uint32 BattleId) +{ + WorldPacket data(SMSG_BATTLEFIELD_MGR_EJECTED, 7); + data << uint32(BattleId); + data << uint8(8); //byte Reason + data << uint8(2); //byte BattleStatus + data << uint8(0); //bool Relocated + + SendPacket(&data); +} + +//Send by client when he click on accept for queue +void WorldSession::HandleBfQueueInviteResponse(WorldPacket & recv_data) +{ + uint32 BattleId; + uint8 Accepted; + + recv_data >> BattleId >> Accepted; + sLog->outError("HandleQueueInviteResponse: BattleID:%u Accepted:%u", BattleId, Accepted); + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldByBattleId(BattleId); + if (!Bf) + return; + + if (Accepted) + { + Bf->PlayerAcceptInviteToQueue(_player); + } +} + +//Send by client on clicking in accept or refuse of invitation windows for join game +void WorldSession::HandleBfEntryInviteResponse(WorldPacket & recv_data) +{ + uint32 BattleId; + uint8 Accepted; + + recv_data >> BattleId >> Accepted; + sLog->outError("HandleBattlefieldInviteResponse: BattleID:%u Accepted:%u", BattleId, Accepted); + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldByBattleId(BattleId); + if (!Bf) + return; + + //If player accept invitation + if (Accepted) + { + Bf->PlayerAcceptInviteToWar(_player); + } + else + { + if (_player->GetZoneId() == Bf->GetZoneId()) + Bf->KickPlayerFromBf(_player->GetGUID()); + } +} + +void WorldSession::HandleBfExitRequest(WorldPacket & recv_data) +{ + uint32 BattleId; + + recv_data >> BattleId; + sLog->outError("HandleBfExitRequest: BattleID:%u ", BattleId); + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldByBattleId(BattleId); + if (!Bf) + return; + + Bf->AskToLeaveQueue(_player); +} diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp new file mode 100644 index 00000000000..29640414f2b --- /dev/null +++ b/src/server/game/Battlefield/BattlefieldMgr.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlefieldMgr.h" +#include "Zones/BattlefieldWG.h" +#include "ObjectMgr.h" +#include "Player.h" + +BattlefieldMgr::BattlefieldMgr() +{ + m_UpdateTimer = 0; + //sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Instantiating BattlefieldMgr"); +} + +BattlefieldMgr::~BattlefieldMgr() +{ + //sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Deleting BattlefieldMgr"); + for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr) + delete *itr; +} + +void BattlefieldMgr::InitBattlefield() +{ + Battlefield* pBf = new BattlefieldWG; + // respawn, init variables + if (!pBf->SetupBattlefield()) + { + sLog->outString(); + sLog->outString("Battlefield : Wintergrasp init failed."); + delete pBf; + } + else + { + m_BattlefieldSet.push_back(pBf); + sLog->outString(); + sLog->outString("Battlefield : Wintergrasp successfully initiated."); + } + + /* For Cataclysm: Tol Barad + pBf = new BattlefieldTB; + // respawn, init variables + if(!pBf->SetupBattlefield()) + { + sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Battlefield : Tol Barad init failed."); + delete pBf; + } + else + { + m_BattlefieldSet.push_back(pBf); + sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Battlefield : Tol Barad successfully initiated."); + } */ +} + +void BattlefieldMgr::AddZone(uint32 zoneid, Battlefield *handle) +{ + m_BattlefieldMap[zoneid] = handle; +} + +void BattlefieldMgr::HandlePlayerEnterZone(Player * plr, uint32 zoneid) +{ + BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid); + if (itr == m_BattlefieldMap.end()) + return; + + if (itr->second->HasPlayer(plr)) + return; + if (itr->second->GetEnable() == false) + return; + itr->second->HandlePlayerEnterZone(plr, zoneid); + sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Player %u entered outdoorpvp id %u", plr->GetGUIDLow(), itr->second->GetTypeId()); +} + +void BattlefieldMgr::HandlePlayerLeaveZone(Player * plr, uint32 zoneid) +{ + BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid); + if (itr == m_BattlefieldMap.end()) + return; + + // teleport: remove once in removefromworld, once in updatezone + if (!itr->second->HasPlayer(plr)) + return; + itr->second->HandlePlayerLeaveZone(plr, zoneid); + sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Player %u left outdoorpvp id %u", plr->GetGUIDLow(), itr->second->GetTypeId()); +} + +Battlefield *BattlefieldMgr::GetBattlefieldToZoneId(uint32 zoneid) +{ + BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid); + if (itr == m_BattlefieldMap.end()) + { + // no handle for this zone, return + return NULL; + } + if (itr->second->GetEnable() == false) + return NULL; + return itr->second; +} + +Battlefield *BattlefieldMgr::GetBattlefieldByBattleId(uint32 battleid) +{ + for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr) + { + if ((*itr)->GetBattleId() == battleid) + return (*itr); + } + return NULL; +} + +void BattlefieldMgr::Update(uint32 diff) +{ + m_UpdateTimer += diff; + if (m_UpdateTimer > BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL) + { + for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr) + if ((*itr)->GetEnable()) + (*itr)->Update(m_UpdateTimer); + m_UpdateTimer = 0; + } +} + +ZoneScript *BattlefieldMgr::GetZoneScript(uint32 zoneId) +{ + BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneId); + if (itr != m_BattlefieldMap.end()) + return itr->second; + else + return NULL; +} diff --git a/src/server/game/Battlefield/BattlefieldMgr.h b/src/server/game/Battlefield/BattlefieldMgr.h new file mode 100644 index 00000000000..eec66483974 --- /dev/null +++ b/src/server/game/Battlefield/BattlefieldMgr.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BATTLEFIELD_MGR_H_ +#define BATTLEFIELD_MGR_H_ + +#include "Battlefield.h" +#include "ace/Singleton.h" + +class Player; +class GameObject; +class Creature; +class ZoneScript; +struct GossipMenuItems; + +// class to handle player enter / leave / areatrigger / GO use events +class BattlefieldMgr +{ + public: + // ctor + BattlefieldMgr(); + // dtor + ~BattlefieldMgr(); + + // create battlefield events + void InitBattlefield(); + // called when a player enters an battlefield area + void HandlePlayerEnterZone(Player * plr, uint32 areaflag); + // called when player leaves an battlefield area + void HandlePlayerLeaveZone(Player * plr, uint32 areaflag); + // called when player resurrects + void HandlePlayerResurrects(Player * plr, uint32 areaflag); + // return assigned battlefield + Battlefield *GetBattlefieldToZoneId(uint32 zoneid); + Battlefield *GetBattlefieldByBattleId(uint32 battleid); + + ZoneScript *GetZoneScript(uint32 zoneId); + + void AddZone(uint32 zoneid, Battlefield * handle); + + void Update(uint32 diff); + + void HandleGossipOption(Player * player, uint64 guid, uint32 gossipid); + + bool CanTalkTo(Player * player, Creature * creature, GossipMenuItems gso); + + void HandleDropFlag(Player * plr, uint32 spellId); + + typedef std::vector < Battlefield * >BattlefieldSet; + typedef std::map < uint32 /* zoneid */ , Battlefield * >BattlefieldMap; + private: + // contains all initiated battlefield events + // used when initing / cleaning up + BattlefieldSet m_BattlefieldSet; + // maps the zone ids to an battlefield event + // used in player event handling + BattlefieldMap m_BattlefieldMap; + // update interval + uint32 m_UpdateTimer; +}; + +#define sBattlefieldMgr (*ACE_Singleton<BattlefieldMgr, ACE_Null_Mutex>::instance()) + +#endif diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp new file mode 100644 index 00000000000..bf6a0a04add --- /dev/null +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -0,0 +1,1141 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +// TODO: Implement proper support for vehicle+player teleportation +// TODO: Use spell victory/defeat in wg instead of RewardMarkOfHonor() && RewardHonor +// TODO: Add proper implement of achievement + +#include "BattlefieldWG.h" +#include "SpellAuras.h" + +enum eWGBfData +{ + BATTLEFIELD_WG_ZONEID = 4197, // Wintergrasp + BATTLEFIELD_WG_MAPID = 571, // Northrend +}; + +bool BattlefieldWG::SetupBattlefield() +{ + InitStalker(BATTLEFIELD_WG_NPC_STALKER, WintergraspStalkerPos[0], WintergraspStalkerPos[1], WintergraspStalkerPos[2], WintergraspStalkerPos[3]); + + m_TypeId = BATTLEFIELD_WG; // See enum BattlefieldTypes + m_BattleId = BATTLEFIELD_BATTLEID_WG; + m_ZoneId = BATTLEFIELD_WG_ZONEID; + m_MapId = BATTLEFIELD_WG_MAPID; + + m_MaxPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MAX); + m_enable = sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE); + m_MinPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN); + m_MinLevel = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN_LVL); + m_BattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_BATTLETIME) * MINUTE; + m_NoWarBattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_NOBATTLETIME) * MINUTE; + m_RestartAfterCrash = sWorld->getIntConfig(CONFIG_WINTERGRASP_RESTART_AFTER_CRASH) * MINUTE; + + m_TimeForAcceptInvite = 20; + m_StartGroupingTimer = 15 * MINUTE; + m_StartGrouping = false; + + m_tenacityStack = 0; + + KickPosition.Relocate(5728.117f, 2714.346f, 697.733f, 0); + KickPosition.m_mapId = m_MapId; + + RegisterZone(m_ZoneId); + + m_Data32.resize(BATTLEFIELD_WG_DATA_MAX); + + m_saveTimer = 60000; + + // Init GraveYards + SetGraveyardNumber(BATTLEFIELD_WG_GY_MAX); + + // Load from db + if ((sWorld->getWorldState(3801) == 0) && (sWorld->getWorldState(3802) == 0) && (sWorld->getWorldState(ClockWorldState[0]) == 0)) + { + sWorld->setWorldState(3801, false); + sWorld->setWorldState(3802, urand(0, 1)); + sWorld->setWorldState(ClockWorldState[0], m_NoWarBattleTime); + } + + m_WarTime = sWorld->getWorldState(3801); + m_DefenderTeam = TeamId(sWorld->getWorldState(3802)); + + m_Timer = sWorld->getWorldState(ClockWorldState[0]); + if (m_WarTime) + { + m_WarTime = false; + m_Timer = m_RestartAfterCrash; + } + + for (uint8 i = 0; i < BATTLEFIELD_WG_GY_MAX; i++) + { + BfGraveYardWG *gy = new BfGraveYardWG(this); + if (WGGraveYard[i].startcontrol == TEAM_NEUTRAL) // When between games, the graveyard is controlled by the defending team + gy->Init(31841, 31842, WGGraveYard[i].x, WGGraveYard[i].y, WGGraveYard[i].z, WGGraveYard[i].o, m_DefenderTeam, WGGraveYard[i].gyid); + else + gy->Init(31841, 31842, WGGraveYard[i].x, WGGraveYard[i].y, WGGraveYard[i].z, WGGraveYard[i].o, WGGraveYard[i].startcontrol, WGGraveYard[i].gyid); + gy->SetTextId(WGGraveYard[i].textid); + m_GraveYardList[i] = gy; + } + + // Spawn workshop creatures and gameobjects + for (uint8 i = 0; i < WG_MAX_WORKSHOP; i++) + { + BfWGWorkShopData *ws = new BfWGWorkShopData(this); // Create new object + // Init:setup variable + ws->Init(WGWorkShopDataBase[i].worldstate, WGWorkShopDataBase[i].type, WGWorkShopDataBase[i].nameid); + // Spawn associate npc on this point (Guard/Engineer) + for (uint8 c = 0; c < WGWorkShopDataBase[i].nbcreature; c++) + ws->AddCreature(WGWorkShopDataBase[i].CreatureData[c]); + + // Spawn associate gameobject on this point (Horde/Alliance flags) + for (uint8 g = 0; g < WGWorkShopDataBase[i].nbgob; g++) + ws->AddGameObject(WGWorkShopDataBase[i].GameObjectData[g]); + + // Create PvPCapturePoint + if (WGWorkShopDataBase[i].type < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST) + { + ws->ChangeControl(GetAttackerTeam(), true); // Update control of this point + // Create Object + BfCapturePointWG *workshop = new BfCapturePointWG(this, GetAttackerTeam()); + // Spawn gameobject associate (see in OnGameObjectCreate, of OutdoorPvP for see association) + workshop->SetCapturePointData(WGWorkShopDataBase[i].CapturePoint.entryh, 571, + WGWorkShopDataBase[i].CapturePoint.x, WGWorkShopDataBase[i].CapturePoint.y, WGWorkShopDataBase[i].CapturePoint.z, 0); + workshop->LinkToWorkShop(ws); // Link our point to the capture point (for faction changement) + AddCapturePoint(workshop); // Add this capture point to list for update this (view in Update() of OutdoorPvP) + } + else + ws->ChangeControl(GetDefenderTeam(), true); // Update control of this point (Keep workshop= to deffender team) + + WorkShopList.insert(ws); + } + // Spawning npc in keep + for (uint8 i = 0; i < WG_MAX_KEEP_NPC; i++) + { + // Horde npc + if (Creature * creature = SpawnCreature(WGKeepNPC[i].entryh, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_HORDE)) + KeepCreature[TEAM_HORDE].insert(creature->GetGUID()); + // Alliance npc + if (Creature * creature = SpawnCreature(WGKeepNPC[i].entrya, WGKeepNPC[i].x, WGKeepNPC[i].y, WGKeepNPC[i].z, WGKeepNPC[i].o, TEAM_ALLIANCE)) + KeepCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); + } + // Hide keep npc + for (GuidSet::const_iterator itr = KeepCreature[GetAttackerTeam()].begin(); itr != KeepCreature[GetAttackerTeam()].end(); ++itr) + if (Unit * unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + HideNpc(creature); + // Spawn out of keep npc + // Horde npc + for (uint8 i = 0; i < WG_OUTSIDE_ALLIANCE_NPC; i++) + if (Creature * creature = SpawnCreature(WGOutsideNPC[i].entryh, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_HORDE)) + OutsideCreature[TEAM_HORDE].insert(creature->GetGUID()); + // Alliance npc + for (uint8 i = WG_OUTSIDE_ALLIANCE_NPC; i < WG_MAX_OUTSIDE_NPC; i++) + if (Creature * creature = SpawnCreature(WGOutsideNPC[i].entrya, WGOutsideNPC[i].x, WGOutsideNPC[i].y, WGOutsideNPC[i].z, WGOutsideNPC[i].o, TEAM_ALLIANCE)) + OutsideCreature[TEAM_ALLIANCE].insert(creature->GetGUID()); + // Hide outside npc + for (GuidSet::const_iterator itr = OutsideCreature[GetDefenderTeam()].begin(); itr != OutsideCreature[GetDefenderTeam()].end(); ++itr) + if (Unit * unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + HideNpc(creature); + for (uint8 i = 0; i < WG_MAX_TURRET; i++) + { + if (Creature * creature = SpawnCreature(28366, WGTurret[i].x, WGTurret[i].y, WGTurret[i].z, WGTurret[i].o, TeamId(0))) + { + CanonList.insert(creature->GetGUID()); + HideNpc(creature); + } + } + // Spawning Buiding + for (uint8 i = 0; i < WG_MAX_OBJ; i++) + { + GameObject *go = + SpawnGameObject(WGGameObjectBuillding[i].entry, WGGameObjectBuillding[i].x, WGGameObjectBuillding[i].y, WGGameObjectBuillding[i].z, WGGameObjectBuillding[i].o); + BfWGGameObjectBuilding *b = new BfWGGameObjectBuilding(this); + b->Init(go, WGGameObjectBuillding[i].type, WGGameObjectBuillding[i].WorldState, WGGameObjectBuillding[i].nameid); + BuildingsInZone.insert(b); + } + // Spawning portal defender + for (uint8 i = 0; i < WG_MAX_TELEPORTER; i++) + { + GameObject *go = SpawnGameObject(WGPortalDefenderData[i].entry, WGPortalDefenderData[i].x, WGPortalDefenderData[i].y, WGPortalDefenderData[i].z, WGPortalDefenderData[i].o); + DefenderPortalList.insert(go); + go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[GetDefenderTeam()]); + } + + // Spawn banner in keep + for (uint8 i = 0; i < WG_KEEPGAMEOBJECT_MAX; i++) + { + if (GameObject * go = SpawnGameObject(WGKeepGameObject[i].entryh, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) + { + go->SetRespawnTime(GetDefenderTeam()? RESPAWN_ONE_DAY : RESPAWN_IMMEDIATELY); + m_KeepGameObject[1].insert(go); + } + if (GameObject * go = SpawnGameObject(WGKeepGameObject[i].entrya, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) + { + go->SetRespawnTime(GetDefenderTeam()? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); + m_KeepGameObject[0].insert(go); + } + } + + // Show defender banner in keep + for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetDefenderTeam()].begin(); itr != m_KeepGameObject[GetDefenderTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); + + // Hide attackant banner in keep + for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetAttackerTeam()].begin(); itr != m_KeepGameObject[GetAttackerTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); + + UpdateCounterVehicle(true); + return true; +} + +bool BattlefieldWG::Update(uint32 diff) +{ + bool m_return = Battlefield::Update(diff); + if (m_saveTimer <= diff) + { + sWorld->setWorldState(3801, m_WarTime); + sWorld->setWorldState(3802, m_DefenderTeam); + sWorld->setWorldState(ClockWorldState[0], m_Timer); + m_saveTimer = 60 * IN_MILLISECONDS; + } + else + m_saveTimer -= diff; + + for (GuidSet::const_iterator itr = m_PlayersIsSpellImu.begin(); itr != m_PlayersIsSpellImu.end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + if (plr->HasAura(SPELL_SPIRITUAL_IMMUNITY)) + { + const WorldSafeLocsEntry *graveyard = GetClosestGraveYard(plr); + if (graveyard) + { + if (plr->GetDistance2d(graveyard->x, graveyard->y) > 10.0f) + { + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + m_PlayersIsSpellImu.erase(plr->GetGUID()); + } + } + } + } + + if (m_WarTime) + { + for (uint8 team = 0; team < 2; ++team) + for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + { + if (unit->IsInWater() && !unit->HasAura(SPELL_WINTERGRASP_WATER)) + unit->AddAura(SPELL_WINTERGRASP_WATER, unit); + if (!unit->IsInWater() && unit->HasAura(SPELL_WINTERGRASP_WATER)) + unit->RemoveAurasDueToSpell(SPELL_WINTERGRASP_WATER); + } + + } + + for (uint8 team = 0; team < 2; ++team) + for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + for (BfCapturePointMap::iterator cp_itr = m_capturePoints.begin(); cp_itr != m_capturePoints.end(); ++cp_itr) + { + if ((*cp_itr).second->GetCapturePointGo()->GetExactDist2dSq(plr) < 22500.0f) // 150*150 + { + plr->AddAura((*cp_itr).second->GetTeamId() == TEAM_HORDE ? SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT : SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT, plr); + plr->RemoveAurasDueToSpell((*cp_itr).second->GetTeamId() == TEAM_ALLIANCE ? SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT : SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT); + break; + } + } + + return m_return; +} + +void BattlefieldWG::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid) +{ + Battlefield::AddPlayerToResurrectQueue(npc_guid, player_guid); + if (IsWarTime()) + { + if (Player* plr = sObjectMgr->GetPlayer(player_guid)) + { + if (!plr->HasAura(SPELL_SPIRITUAL_IMMUNITY)) + { + plr->CastSpell(plr, SPELL_SPIRITUAL_IMMUNITY, true); + m_PlayersIsSpellImu.insert(plr->GetGUID()); + } + } + } +} + +void BattlefieldWG::OnBattleStart() +{ + // Spawn titan relic + m_relic = SpawnGameObject(BATTLEFIELD_WG_GAMEOBJECT_TITAN_RELIC, 5440.0f, 2840.8f, 430.43f, 0); + if (m_relic) + { + // Update faction of relic, only attacker can click on + m_relic->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[GetAttackerTeam()]); + // Set in use (not allow to click on before last door is broken) + m_relic->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } + else + sLog->outError("WG: Failed to spawn titan relic."); + + + // Update tower visibility and update faction + for (GuidSet::const_iterator itr = CanonList.begin(); itr != CanonList.end(); ++itr) + { + if (Unit * unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature * creature = unit->ToCreature()) + { + ShowNpc(creature, true); + creature->setFaction(WintergraspFaction[GetDefenderTeam()]); + } + } + } + + // Rebuild all wall + for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr) + { + if ((*itr)) + { + (*itr)->Rebuild(); + (*itr)->UpdateTurretAttack(false); + } + } + + m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] = 0; + m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF] = 0; + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT] = 0; + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF] = 0; + + // Update graveyard (in no war time all graveyard is to deffender, in war time, depend of base) + for (WorkShop::const_iterator itr = WorkShopList.begin(); itr != WorkShopList.end(); ++itr) + { + if ((*itr)) + (*itr)->UpdateGraveYardAndWorkshop(); + } + + for (uint8 team = 0; team < 2; ++team) + for (GuidSet::const_iterator p_itr = m_players[team].begin(); p_itr != m_players[team].end(); ++p_itr) + { + // Kick player in orb room, TODO: offline player ? + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + { + float x, y, z; + plr->GetPosition(x, y, z); + if (5500 > x && x > 5392 && y < 2880 && y > 2800 && z < 480) + plr->TeleportTo(571, 5349.8686f, 2838.481f, 409.240f, 0.046328f); + SendInitWorldStatesTo(plr); + } + } + // Initialize vehicle counter + UpdateCounterVehicle(true); + // Send start warning to all players + SendWarningToAllInZone(BATTLEFIELD_WG_TEXT_START); +} + +void BattlefieldWG::UpdateCounterVehicle(bool init) +{ + if (init) + { + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_H] = 0; + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_A] = 0; + } + m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_H] = 0; + m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_A] = 0; + + for (WorkShop::const_iterator itr = WorkShopList.begin(); itr != WorkShopList.end(); ++itr) + { + if (BfWGWorkShopData * workshop = (*itr)) + { + if (workshop->m_TeamControl == TEAM_ALLIANCE) + m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_A] = m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_A] + 4; + else if (workshop->m_TeamControl == TEAM_HORDE) + m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_H] = m_Data32[BATTLEFIELD_WG_DATA_MAX_VEHICLE_H] + 4; + } + } + + UpdateVehicleCountWG(); +} + +void BattlefieldWG::OnBattleEnd(bool endbytimer) +{ + // Remove relic + if (m_relic) + m_relic->RemoveFromWorld(); + m_relic = NULL; + + // Remove turret + for (GuidSet::const_iterator itr = CanonList.begin(); itr != CanonList.end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature* creature = unit->ToCreature()) + { + if (!endbytimer) + creature->setFaction(WintergraspFaction[GetDefenderTeam()]); + HideNpc(creature); + } + } + } + + // If endbytimer is false, battle is end by clicking on relic + if (!endbytimer) + { + // Change all npc in keep + for (GuidSet::const_iterator itr = KeepCreature[GetAttackerTeam()].begin(); itr != KeepCreature[GetAttackerTeam()].end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + HideNpc(creature); + } + for (GuidSet::const_iterator itr = KeepCreature[GetDefenderTeam()].begin(); itr != KeepCreature[GetDefenderTeam()].end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + ShowNpc(creature, true); + } + // Change all npc out of keep + for (GuidSet::const_iterator itr = OutsideCreature[GetDefenderTeam()].begin(); itr != OutsideCreature[GetDefenderTeam()].end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + HideNpc(creature); + } + for (GuidSet::const_iterator itr = OutsideCreature[GetAttackerTeam()].begin(); itr != OutsideCreature[GetAttackerTeam()].end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature* creature = unit->ToCreature()) + ShowNpc(creature, true); + } + } + + // Update all graveyard, control is to defender when no wartime + for (uint8 i = 0; i < BATTLEFIELD_WG_GY_HORDE; i++) + { + if (GetGraveYardById(i)) + { + GetGraveYardById(i)->ChangeControl(GetDefenderTeam()); + } + } + + for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetDefenderTeam()].begin(); itr != m_KeepGameObject[GetDefenderTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); + + for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetAttackerTeam()].begin(); itr != m_KeepGameObject[GetAttackerTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); + + // Update portal defender faction + for (GameObjectSet::const_iterator itr = DefenderPortalList.begin(); itr != DefenderPortalList.end(); ++itr) + (*itr)->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[GetDefenderTeam()]); + + // Saving data + for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr) + (*itr)->Save(); + for (WorkShop::const_iterator itr = WorkShopList.begin(); itr != WorkShopList.end(); ++itr) + (*itr)->Save(); + + uint32 WinerHonor = 0; + uint32 LooserHonor = 0; + + if (!endbytimer) + { + WinerHonor = 3000 + 400 * m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF] + 100 * m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF]; + LooserHonor = 1000 + 400 * m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] + 100 * m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT]; + } + else + { + WinerHonor = 3000 + 400 * m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] + 100 * m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT]; + LooserHonor = 1000 + 400 * m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF] + 100 * m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF]; + } + + for (GuidSet::const_iterator itr = m_PlayersInWar[GetDefenderTeam()].begin(); itr != m_PlayersInWar[GetDefenderTeam()].end(); ++itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + plr->AddAura(58045, plr); + if (plr->HasAura(SPELL_LIEUTENANT)) + { + plr->RewardHonor(NULL, 1, WinerHonor); + RewardMarkOfHonor(plr, 3); + } + else if (plr->HasAura(SPELL_CORPORAL)) + { + plr->RewardHonor(NULL, 1, WinerHonor); + RewardMarkOfHonor(plr, 2); + } + if (plr->GetTeamId() == TEAM_HORDE) + IncrementQuest(plr, 13183, true); + else + IncrementQuest(plr, 13181, true); + // Send Wintergrasp victory achievement + DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WIN_WG, plr); + // Award achievement for succeeding in Wintergrasp in 10 minutes or less + if (!endbytimer && GetTimer() <= 10000) + DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WIN_WG_TIMER_10, plr); + } + } + for (GuidSet::const_iterator itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + if (plr->HasAura(SPELL_LIEUTENANT)) + { + plr->RewardHonor(NULL, 1, LooserHonor); + RewardMarkOfHonor(plr, 1); + } + else if (plr->HasAura(SPELL_CORPORAL)) + { + plr->RewardHonor(NULL, 1, LooserHonor); + RewardMarkOfHonor(plr, 1); + } + } + } + + for (uint8 team = 0; team < 2; ++team) + { + for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + plr->RemoveAura(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + } + } + m_PlayersInWar[team].clear(); + + for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + { + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature* creature = unit->ToCreature()) + if (creature->IsVehicle()) + creature->GetVehicleKit()->Dismiss(); + } + m_vehicles[team].clear(); + } + + if (!endbytimer) + { + for (uint8 team = 0; team < 2; ++team) + { + for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + plr->RemoveAurasDueToSpell(m_DefenderTeam == TEAM_ALLIANCE ? SPELL_HORDE_CONTROL_PHASE_SHIFT : SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, plr->GetGUID()); + plr->AddAura(m_DefenderTeam == TEAM_HORDE ? SPELL_HORDE_CONTROL_PHASE_SHIFT : SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, plr); + } + } + } + } + + if (!endbytimer) + { // win alli/horde + SendWarningToAllInZone((GetDefenderTeam() == TEAM_ALLIANCE) ? BATTLEFIELD_WG_TEXT_WIN_KEEP : BATTLEFIELD_WG_TEXT_WIN_KEEP + 1); + } + else + { // defend alli/horde + SendWarningToAllInZone((GetDefenderTeam() == TEAM_ALLIANCE) ? BATTLEFIELD_WG_TEXT_DEFEND_KEEP : BATTLEFIELD_WG_TEXT_DEFEND_KEEP + 1); + } +} + +// ***************************************************** +// *******************Reward System********************* +// ***************************************************** +void BattlefieldWG::DoCompleteOrIncrementAchievement(uint32 achievement, Player *player, uint8 /*incrementNumber */ ) +{ + AchievementEntry const* AE = GetAchievementStore()->LookupEntry(achievement); + + switch (achievement) + { + case ACHIEVEMENTS_WIN_WG_100: + { + // player->GetAchievementMgr().UpdateAchievementCriteria(); + } + default: + { + if (player) + player->CompletedAchievement(AE); + } + break; + } + +} + +void BattlefieldWG::RewardMarkOfHonor(Player *plr, uint32 count) +{ + // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens + if (count == 0) + return; + + ItemPosCountVec dest; + uint32 no_space_count = 0; + uint8 msg = plr->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, WG_MARK_OF_HONOR, count, &no_space_count); + + if (msg == EQUIP_ERR_ITEM_NOT_FOUND) + { + return; + } + + if (msg != EQUIP_ERR_OK) // convert to possible store amount + count -= no_space_count; + + if (count != 0 && !dest.empty()) // can add some + if (Item * item = plr->StoreNewItem(dest, WG_MARK_OF_HONOR, true, 0)) + plr->SendNewItem(item, count, true, false); +} + +void BattlefieldWG::OnStartGrouping() +{ + // Warn + SendWarningToAllInZone(BATTLEFIELD_WG_TEXT_WILL_START); +} + +void BattlefieldWG::OnCreatureCreate(Creature * creature, bool add) +{ + if (IsWarTime()) + { + switch (creature->GetEntry()) + { + case 28312: + case 32627: + case 27881: + case 28094: + { + uint8 team; + if (creature->getFaction() == WintergraspFaction[TEAM_ALLIANCE]) + team = TEAM_ALLIANCE; + else if (creature->getFaction() == WintergraspFaction[TEAM_HORDE]) + team = TEAM_HORDE; + else + return; + + if (add) + { + if (team == TEAM_HORDE) + { + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_H]++; + if (GetData(BATTLEFIELD_WG_DATA_VEHICLE_H) <= GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H)) + { + creature->AddAura(SPELL_HORDE_FLAG, creature); + m_vehicles[team].insert(creature->GetGUID()); + UpdateVehicleCountWG(); + } + else + { + creature->setDeathState(DEAD); + creature->SetRespawnTime(RESPAWN_ONE_DAY); + return; + } + } + else + { + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_A]++; + if (GetData(BATTLEFIELD_WG_DATA_VEHICLE_A) <= GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A)) + { + creature->AddAura(SPELL_ALLIANCE_FLAG, creature); + m_vehicles[team].insert(creature->GetGUID()); + UpdateVehicleCountWG(); + } + else + { + creature->setDeathState(DEAD); + creature->SetRespawnTime(RESPAWN_ONE_DAY); + return; + } + } + } + else + { + m_vehicles[team].erase(creature->GetGUID()); + if (team == TEAM_HORDE) + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_H]--; + else + m_Data32[BATTLEFIELD_WG_DATA_VEHICLE_A]--; + UpdateVehicleCountWG(); + } + break; + } + } + } +} + +// Called when player kill a unit in wg zone +void BattlefieldWG::HandleKill(Player *killer, Unit *victim) +{ + if (killer == victim) + return; + + bool again = false; + if (victim->GetTypeId() == TYPEID_PLAYER) + { + IncrementQuest(killer, WGQuest[killer->GetTeamId()][4]); + IncrementQuest(killer, WGQuest[killer->GetTeamId()][5]); + for (GuidSet::const_iterator p_itr = m_PlayersInWar[killer->GetTeamId()].begin(); p_itr != m_PlayersInWar[killer->GetTeamId()].end(); ++p_itr) + { + if (Player* plr = sObjectAccessor->FindPlayer(*p_itr)) + if (plr->GetDistance2d(killer) < 40) + PromotePlayer(plr); + } + return; + } + for (GuidSet::const_iterator itr = m_vehicles[killer->GetTeamId()? TEAM_ALLIANCE : TEAM_HORDE].begin(); + itr != m_vehicles[killer->GetTeamId()? TEAM_ALLIANCE : TEAM_HORDE].end(); ++itr) + { + if (Unit * unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature * creature = unit->ToCreature()) + { + if (victim->GetEntry() == creature->GetEntry() && !again) + { + again = true; + for (GuidSet::const_iterator p_itr = m_PlayersInWar[killer->GetTeamId()].begin(); p_itr != m_PlayersInWar[killer->GetTeamId()].end(); ++p_itr) + { + if (Player* plr = sObjectAccessor->FindPlayer(*p_itr)) + if (plr->GetDistance2d(killer) < 40) + IncrementQuest(plr, IncrementQuest(killer, WGQuest[killer->GetTeamId()][0])); + } + } + } + } + } + for (GuidSet::const_iterator itr = KeepCreature[killer->GetTeamId()? TEAM_ALLIANCE : TEAM_HORDE].begin(); + itr != KeepCreature[killer->GetTeamId()? TEAM_ALLIANCE : TEAM_HORDE].end(); ++itr) + { + if (Unit * unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature * creature = unit->ToCreature()) + { + if (victim->GetEntry() == creature->GetEntry() && !again) + { + again = true; + IncrementQuest(killer, WGQuest[killer->GetTeamId()][4]); + IncrementQuest(killer, WGQuest[killer->GetTeamId()][5]); + for (GuidSet::const_iterator p_itr = m_PlayersInWar[killer->GetTeamId()].begin(); p_itr != m_PlayersInWar[killer->GetTeamId()].end(); ++p_itr) + { + if (Player* plr = sObjectAccessor->FindPlayer(*p_itr)) + if (plr->GetDistance2d(killer) < 40) + PromotePlayer(plr); + } + } + } + } + } + // TODO:Recent PvP activity worldstate +} + +// Update rank for player +void BattlefieldWG::PromotePlayer(Player *killer) +{ + if (!m_WarTime) + return; + // Updating rank of player + if (Aura * aur = killer->GetAura(SPELL_RECRUIT)) + { + if (aur->GetStackAmount() >= 5) // 7 or more TODO: + { + killer->RemoveAura(SPELL_RECRUIT); + killer->CastSpell(killer, SPELL_CORPORAL, true); + SendWarningToPlayer(killer, BATTLEFIELD_WG_TEXT_FIRSTRANK); + } + else + killer->CastSpell(killer, SPELL_RECRUIT, true); + } + else if (Aura * aur = killer->GetAura(SPELL_CORPORAL)) + { + if (aur->GetStackAmount() >= 5) // 7 or more TODO: + { + killer->RemoveAura(SPELL_CORPORAL); + killer->CastSpell(killer, SPELL_LIEUTENANT, true); + SendWarningToPlayer(killer, BATTLEFIELD_WG_TEXT_SECONDRANK); + } + else + killer->CastSpell(killer, SPELL_CORPORAL, true); + } +} + +void BattlefieldWG::OnPlayerJoinWar(Player *plr) +{ + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + plr->RemoveAurasDueToSpell(58045); + + plr->CastSpell(plr, SPELL_RECRUIT, true); + + if (plr->GetZoneId() != m_ZoneId) + { + if (plr->GetTeamId() == GetDefenderTeam()) + { + plr->TeleportTo(571, 5345, 2842, 410, 3.14f); + } + else + { + if (plr->GetTeamId() == TEAM_HORDE) + plr->TeleportTo(571, 5025.857422f, 3674.628906f, 362.737122f, 4.135169f); + else + plr->TeleportTo(571, 5101.284f, 2186.564f, 373.549f, 3.812f); + } + } + + UpdateTenacity(); + + if (plr->GetTeamId() == GetAttackerTeam()) + { + if (3 - m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] > 0) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, 3 - m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT]); + } + else + { + if (m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] > 0) + plr->SetAuraStack(SPELL_TOWER_CONTROL, plr, m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT]); + } + SendInitWorldStatesTo(plr); +} + +void BattlefieldWG::OnPlayerLeaveWar(Player *plr) +{ + // Remove all aura from WG // TODO: false we can go out of this zone on retail and keep Rank buff, remove on end of WG + if (!plr->GetSession()->PlayerLogout()) + { + if (plr->GetVehicle()) // Remove vehicle of player if he go out. + plr->GetVehicle()->Dismiss(); + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + plr->RemoveAurasDueToSpell(58730); + plr->RemoveAurasDueToSpell(58045); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + } + plr->RemoveAurasDueToSpell(SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_HORDE_CONTROL_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROL_PHASE_SHIFT); +} + +void BattlefieldWG::OnPlayerLeaveZone(Player *plr) +{ + plr->RemoveAurasDueToSpell(58045); + if (!m_WarTime) + { + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + plr->RemoveAurasDueToSpell(58730); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + } + plr->RemoveAurasDueToSpell(SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_HORDE_CONTROL_PHASE_SHIFT); + plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROL_PHASE_SHIFT); +} + +void BattlefieldWG::OnPlayerEnterZone(Player *plr) +{ + plr->RemoveAurasDueToSpell(58045); + if (!m_WarTime) + { + plr->RemoveAurasDueToSpell(SPELL_RECRUIT); + plr->RemoveAurasDueToSpell(SPELL_CORPORAL); + plr->RemoveAurasDueToSpell(SPELL_LIEUTENANT); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + plr->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY); + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + plr->RemoveAurasDueToSpell(58730); + plr->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL); + if (plr->GetTeamId() == GetDefenderTeam()) + plr->AddAura(58045, plr); + } + + plr->AddAura(m_DefenderTeam == TEAM_HORDE ? + SPELL_HORDE_CONTROL_PHASE_SHIFT: + SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, + plr); + // Send worldstate to player + SendInitWorldStatesTo(plr); +} + +// Method sending worldsate to player +WorldPacket BattlefieldWG::BuildInitWorldStates() +{ + WorldPacket data(SMSG_INIT_WORLD_STATES, (4 + 4 + 4 + 2 + (BuildingsInZone.size() * 8) + (WorkShopList.size() * 8))); + + data << uint32(m_MapId); + data << uint32(m_ZoneId); + data << uint32(0); + data << uint16(4 + 2 + 4 + BuildingsInZone.size() + WorkShopList.size()); + + data << uint32(3803) << uint32(GetAttackerTeam()); + data << uint32(3802) << uint32(GetDefenderTeam()); + data << uint32(3801) << uint32(IsWarTime()? 0 : 1); + data << uint32(3710) << uint32(IsWarTime()? 1 : 0); + + for (uint32 i = 0; i < 2; ++i) + data << ClockWorldState[i] << uint32(time(NULL) + (m_Timer / 1000)); + + data << uint32(3490) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_H)); + data << uint32(3491) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H); + data << uint32(3680) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_A)); + data << uint32(3681) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A); + + for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr) + { + data << (*itr)->m_WorldState << (*itr)->m_State; + } + for (WorkShop::const_iterator itr = WorkShopList.begin(); itr != WorkShopList.end(); ++itr) + { + data << (*itr)->m_WorldState << (*itr)->m_State; + } + return data; +} + +void BattlefieldWG::SendInitWorldStatesTo(Player *player) +{ + WorldPacket data = BuildInitWorldStates(); + player->GetSession()->SendPacket(&data); +} + +void BattlefieldWG::SendInitWorldStatesToAll() +{ + WorldPacket data = BuildInitWorldStates(); + for (uint8 team = 0; team < 2; team++) + for (GuidSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->GetSession()->SendPacket(&data); +} + +void BattlefieldWG::BrokenWallOrTower(TeamId team) +{ + if (team == GetDefenderTeam()) + { + for (GuidSet::const_iterator p_itr = m_PlayersInWar[GetAttackerTeam()].begin(); p_itr != m_PlayersInWar[GetAttackerTeam()].end(); ++p_itr) + { + if (Player* plr = sObjectMgr->GetPlayer((*p_itr))) + { + if (plr->GetTeamId() == TEAM_ALLIANCE) + IncrementQuest(plr, 13222); + else + IncrementQuest(plr, 13223); + } + } + } +} +// Called when a tower is broke +void BattlefieldWG::AddBrokenTower(TeamId team) +{ + // Destroy an attack tower + if (team == GetAttackerTeam()) + { + // Update counter + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT]--; + m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT]++; + + // Remove buff stack + for (GuidSet::const_iterator itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->RemoveAuraFromStack(SPELL_TOWER_CONTROL); + + // Add buff stack + for (GuidSet::const_iterator itr = m_PlayersInWar[GetDefenderTeam()].begin(); itr != m_PlayersInWar[GetDefenderTeam()].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + { + plr->CastSpell(plr, SPELL_TOWER_CONTROL, true); + if (plr->GetTeamId() == TEAM_HORDE) + IncrementQuest(plr, 13539, true); + else + IncrementQuest(plr, 13538, true); + DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WG_TOWER_DESTROY, plr); + } + // If the threw south tower is destroy + if (m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT] == 3) + { + // Remove 10 minutes to battle time + if (int32(m_Timer - 600000) < 0) + { + m_Timer = 0; + } + else + { + m_Timer -= 600000; + } + SendInitWorldStatesToAll(); + } + } + else + { + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF]--; + m_Data32[BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF]++; + } +} + +void BattlefieldWG::ProcessEvent(GameObject * obj, uint32 eventId) +{ + if (!obj || !IsWarTime()) + return; + + // On click on titan relic + if (obj->GetEntry() == BATTLEFIELD_WG_GAMEOBJECT_TITAN_RELIC) + { + // Check that the door is break + if (m_bCanClickOnOrb) + EndBattle(false); + else // if door is not break, respawn relic. + m_relic->SetRespawnTime(RESPAWN_IMMEDIATELY); + } + + // if destroy or damage event, search the wall/tower and update worldstate/send warning message + for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr) + { + if (obj->GetEntry() == (*itr)->m_Build->GetEntry()) + { + if ((*itr)->m_Build->GetGOInfo()->building.damagedEvent == eventId) + (*itr)->Damaged(); + + if ((*itr)->m_Build->GetGOInfo()->building.destroyedEvent == eventId) + (*itr)->Destroyed(); + + break; + } + } +} + +// Called when a tower is damaged, used for honor reward calcul +void BattlefieldWG::AddDamagedTower(TeamId team) +{ + if (team == GetAttackerTeam()) + { + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT]++; + } + else + { + m_Data32[BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF]++; + } +} + +// Update vehicle count WorldState to player +void BattlefieldWG::UpdateVehicleCountWG() +{ + SendUpdateWorldState(3490, GetData(BATTLEFIELD_WG_DATA_VEHICLE_H)); + SendUpdateWorldState(3491, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H)); + SendUpdateWorldState(3680, GetData(BATTLEFIELD_WG_DATA_VEHICLE_A)); + SendUpdateWorldState(3681, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A)); +} + +void BattlefieldWG::UpdateTenacity() +{ + TeamId team = TEAM_NEUTRAL; + uint32 allianceNum = m_PlayersInWar[TEAM_ALLIANCE].size(); + uint32 hordeNum = m_PlayersInWar[TEAM_HORDE].size(); + int32 newStack = 0; + + if (allianceNum && hordeNum) + { + if (allianceNum < hordeNum) + newStack = int32((float (hordeNum) / float (allianceNum) - 1) *4); // positive, should cast on alliance + else if (allianceNum > hordeNum) + newStack = int32((1 - float (allianceNum) / float (hordeNum)) *4); // negative, should cast on horde + } + + if (newStack == int32(m_tenacityStack)) + return; + + if (m_tenacityStack > 0 && newStack <= 0) // old buff was on alliance + team = TEAM_ALLIANCE; + else if (newStack >= 0) // old buff was on horde + team = TEAM_HORDE; + + m_tenacityStack = newStack; + // Remove old buff + if (team != TEAM_NEUTRAL) + { + for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + if (plr->getLevel() > 76) + plr->RemoveAurasDueToSpell(SPELL_TENACITY); + + for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature* creature = unit->ToCreature()) + creature->RemoveAurasDueToSpell(SPELL_TENACITY_VEHICLE); + } + + // Apply new buff + if (newStack) + { + team = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE; + + if (newStack < 0) + newStack = -newStack; + if (newStack > 20) + newStack = 20; + + uint32 buff_honnor = SPELL_GREATEST_HONOR; + buff_honnor = (newStack < 15) ? (uint32) SPELL_GREATER_HONOR : buff_honnor; + buff_honnor = (newStack < 10) ? (uint32) SPELL_GREAT_HONOR : buff_honnor; + buff_honnor = (newStack < 5) ? 0 : buff_honnor; + + for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->SetAuraStack(SPELL_TENACITY, plr, newStack); + for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature * creature = unit->ToCreature()) + creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, newStack); + + if (buff_honnor != 0) + { + for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr) + if (Player* plr = sObjectMgr->GetPlayer((*itr))) + plr->AddAura(buff_honnor, plr); + for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) + if (Unit* unit = sObjectAccessor->FindUnit((*itr))) + if (Creature* creature = unit->ToCreature()) + creature->AddAura(buff_honnor, creature); + } + } +} + +void BfCapturePointWG::ChangeTeam(TeamId /*oldTeam */ ) +{ + m_WorkShop->ChangeControl(m_team, false); +} + +BfCapturePointWG::BfCapturePointWG(BattlefieldWG * bf, TeamId control):BfCapturePoint(bf) +{ + m_Bf = bf; + m_team = control; +} + +BfGraveYardWG::BfGraveYardWG(BattlefieldWG * bf):BfGraveYard(bf) +{ + m_Bf = bf; +} diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h new file mode 100644 index 00000000000..6a768c1e164 --- /dev/null +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -0,0 +1,1906 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BATTLEFIELD_WG_ +#define BATTLEFIELD_WG_ + +#include "Battlefield.h" +#include "Group.h" +#include "WorldPacket.h" +#include "World.h" + +const uint32 VehNumWorldState[2] = { 3680, 3490 }; +const uint32 MaxVehNumWorldState[2] = { 3681, 3491 }; +const uint32 ClockWorldState[2] = { 3781, 4354 }; +const uint32 WintergraspFaction[3] = { 1732, 1735, 35 }; + +const float WintergraspStalkerPos[4] = { 0, 0, 0, 0 }; + +class BattlefieldWG; +class BfCapturePointWG; + +struct BfWGGameObjectBuilding; +struct BfWGWorkShopData; + +typedef std::set<GameObject *>GameObjectSet; +typedef std::set<BfWGGameObjectBuilding *> GameObjectBuilding; +typedef std::set<BfWGWorkShopData *> WorkShop; +//typedef std::set<BfCapturePointWG *> CapturePointSet; unused ? +typedef std::set<Group *> GroupSet; + +enum eWGItem +{ +// *INDENT-OFF* + WG_MARK_OF_HONOR = 43589, +// *INDENT-ON* +}; + +enum eWGSpell +{ +// *INDENT-OFF* + // Wartime auras + SPELL_RECRUIT = 37795, + SPELL_CORPORAL = 33280, + SPELL_LIEUTENANT = 55629, + SPELL_TENACITY = 58549, + SPELL_TENACITY_VEHICLE = 59911, + SPELL_TOWER_CONTROL = 62064, + SPELL_SPIRITUAL_IMMUNITY = 58729, + SPELL_GREAT_HONOR = 58555, + SPELL_GREATER_HONOR = 58556, + SPELL_GREATEST_HONOR = 58557, + SPELL_ALLIANCE_FLAG = 14268, + SPELL_HORDE_FLAG = 14267, + + // Reward spells + SPELL_VICTORY_REWARD = 56902, + SPELL_DEFEAT_REWARD = 58494, + SPELL_DAMAGED_TOWER = 59135, + SPELL_DESTROYED_TOWER = 59136, + SPELL_DAMAGED_BUILDING = 59201, + SPELL_INTACT_BUILDING = 59203, + + SPELL_TELEPORT_BRIDGE = 59096, + SPELL_TELEPORT_FORTRESS = 60035, + + SPELL_TELEPORT_DALARAN = 53360, + SPELL_VICTORY_AURA = 60044, + + // Other spells + SPELL_WINTERGRASP_WATER = 36444, + + // Phasing spells + SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT = 56617,// ADDS PHASE 32 + SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT = 56618,// ADDS PHASE 16 + + SPELL_HORDE_CONTROL_PHASE_SHIFT = 55773,// ADDS PHASE 64 + SPELL_ALLIANCE_CONTROL_PHASE_SHIFT = 55774,// ADDS PHASE 128 + +// *INDENT-ON* +}; + +enum eWGData32 +{ + BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF, + BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF, + BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT, + BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT, + BATTLEFIELD_WG_DATA_MAX_VEHICLE_A, + BATTLEFIELD_WG_DATA_MAX_VEHICLE_H, + BATTLEFIELD_WG_DATA_VEHICLE_A, + BATTLEFIELD_WG_DATA_VEHICLE_H, + BATTLEFIELD_WG_DATA_MAX, +}; + +enum WB_ACHIEVEMENTS +{ +// *INDENT-OFF* + ACHIEVEMENTS_WIN_WG = 1717, + ACHIEVEMENTS_WIN_WG_100 = 1718, // todo + ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, // todo + ACHIEVEMENTS_WG_TOWER_DESTROY = 1727, + ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, // todo + ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, // todo + ACHIEVEMENTS_WG_MASTER_A = 1752, // todo + ACHIEVEMENTS_WIN_WG_TIMER_10 = 1755, + ACHIEVEMENTS_STONE_KEEPER_50 = 2085, // todo + ACHIEVEMENTS_STONE_KEEPER_100 = 2086, // todo + ACHIEVEMENTS_STONE_KEEPER_250 = 2087, // todo + ACHIEVEMENTS_STONE_KEEPER_500 = 2088, // todo + ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, // todo + ACHIEVEMENTS_WG_RANGER = 2199, // todo + ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, // todo + ACHIEVEMENTS_WG_MASTER_H = 2776, // todo +// *INDENT-ON* +}; + +/*######################### +*####### Graveyards ######* +#########################*/ + +class BfGraveYardWG : public BfGraveYard +{ + public: + BfGraveYardWG(BattlefieldWG *Bf); + + void SetTextId(uint32 textid) { m_GossipTextId = textid; } + uint32 GetTextId() { return m_GossipTextId; } + protected: + uint32 m_GossipTextId; +}; + +enum eWGGraveyardId +{ + BATTLEFIELD_WG_GY_WORKSHOP_NE, + BATTLEFIELD_WG_GY_WORKSHOP_NW, + BATTLEFIELD_WG_GY_WORKSHOP_SE, + BATTLEFIELD_WG_GY_WORKSHOP_SW, + BATTLEFIELD_WG_GY_KEEP, + BATTLEFIELD_WG_GY_HORDE, + BATTLEFIELD_WG_GY_ALLIANCE, + BATTLEFIELD_WG_GY_MAX, +}; + +enum eWGGossipText +{ +// *INDENT-OFF* + BATTLEFIELD_WG_GOSSIPTEXT_GY_NE = -1850501, + BATTLEFIELD_WG_GOSSIPTEXT_GY_NW = -1850502, + BATTLEFIELD_WG_GOSSIPTEXT_GY_SE = -1850504, + BATTLEFIELD_WG_GOSSIPTEXT_GY_SW = -1850503, + BATTLEFIELD_WG_GOSSIPTEXT_GY_KEEP = -1850500, + BATTLEFIELD_WG_GOSSIPTEXT_GY_HORDE = -1850505, + BATTLEFIELD_WG_GOSSIPTEXT_GY_ALLIANCE = -1850506, +// *INDENT-ON* +}; + +enum eWGNpc +{ +// *INDENT-OFF* + BATTLEFIELD_WG_NPC_GUARD_H = 30739, + BATTLEFIELD_WG_NPC_GUARD_A = 30740, + BATTLEFIELD_WG_NPC_STALKER = 00000, + + BATTLEFIELD_WG_NPC_VIERON_BLAZEFEATHER = 31102, + BATTLEFIELD_WG_NPC_STONE_GUARD_MUKAR = 32296,// <WINTERGRASP QUARTERMASTER> + BATTLEFIELD_WG_NPC_HOODOO_MASTER_FU_JIN = 31101,// <MASTER HEXXER> + BATTLEFIELD_WG_NPC_CHAMPION_ROS_SLAI = 39173,// <WINTERGRASP QUARTERMASTER> + BATTLEFIELD_WG_NPC_COMMANDER_DARDOSH = 31091, + BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_KILRATH = 31151, + BATTLEFIELD_WG_NPC_SIEGESMITH_STRONGHOOF = 31106, + BATTLEFIELD_WG_NPC_PRIMALIST_MULFORT = 31053, + BATTLEFIELD_WG_NPC_LIEUTENANT_MURP = 31107, + + BATTLEFIELD_WG_NPC_BOWYER_RANDOLPH = 31052, + BATTLEFIELD_WG_NPC_KNIGHT_DAMERON = 32294,// <WINTERGRASP QUARTERMASTER> + BATTLEFIELD_WG_NPC_SORCERESS_KAYLANA = 31051,// <ENCHANTRESS> + BATTLEFIELD_WG_NPC_MARSHAL_MAGRUDER = 39172,// <WINTERGRASP QUARTERMASTER> + BATTLEFIELD_WG_NPC_COMMANDER_ZANNETH = 31036, + BATTLEFIELD_WG_NPC_TACTICAL_OFFICER_AHBRAMIS = 31153, + BATTLEFIELD_WG_NPC_SIEGE_MASTER_STOUTHANDLE = 31108, + BATTLEFIELD_WG_NPC_ANCHORITE_TESSA = 31054, + BATTLEFIELD_WG_NPC_SENIOR_DEMOLITIONIST_LEGOSO = 31109, +// *INDENT-ON* +}; + +struct BfWGCoordGY +{ + float x; + float y; + float z; + float o; + uint32 gyid; + uint8 type; + uint32 textid; // for gossip menu + TeamId startcontrol; +}; + +const uint32 WGQuest[2][6] = { + { 13186, 13181, 13222, 13538, 13177, 13179 }, + { 13185, 13183, 13223, 13539, 13178, 13180 }, +}; +// 7 in sql, 7 in header +const BfWGCoordGY WGGraveYard[BATTLEFIELD_WG_GY_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 }, +}; + +/*######################### +* BfCapturePointWG * +#########################*/ + +class BfCapturePointWG : public BfCapturePoint +{ + public: + BfCapturePointWG(BattlefieldWG *bf, TeamId control); + + void LinkToWorkShop(BfWGWorkShopData *ws) + { + m_WorkShop = ws; + } + + void ChangeTeam(TeamId oldteam); + TeamId GetTeam() const + { + return m_team; + } + + protected: + BfWGWorkShopData *m_WorkShop; +}; + +/*######################### +* WinterGrasp Battlefield * +#########################*/ + +class BattlefieldWG : public Battlefield +{ + public: + /** + * \brief Called when the battle start + * -Spawn relic and turret + * -Rebuild tower and wall + * -Invite player to war + */ + void OnBattleStart(); + + /** + * \brief Called when battle end + * -Remove relic and turret + * -Change banner/npc in keep if it needed + * -Saving battlestate + * -Reward honor/mark to player + * -Remove vehicle + * \param endbytimer : true if battle end when timer is at 00:00, false if battle end by clicking on relic + */ + void OnBattleEnd(bool endbytimer); + + /** + * \brief Called when grouping start (15 minutes before battlestart) + * -Invite all player in zone to join queue + */ + void OnStartGrouping(); + + /** + * \brief Called when player accept invite to join battle + * -Update aura + * -Teleport if it needed + * -Update worldstate + * -Update tenacity + * \param plr: Player who accept invite + */ + void OnPlayerJoinWar(Player *plr); + + /** + * \brief Called when player leave battle + * -Update player aura + * \param plr : Player who leave battle + */ + void OnPlayerLeaveWar(Player *plr); + + /** + * \brief Called when player leave WG zone + * \param plr : Player who leave zone + */ + void OnPlayerLeaveZone(Player *plr); + + /** + * \brief Called when player enter in WG zone + * -Update aura + * -Update worldstate + * \param plr : Player who leave zone + */ + void OnPlayerEnterZone(Player *plr); + + /** + * \brief Called for update battlefield data + * -Save battle timer in database every minutes + * -Update imunity aura from graveyard + * -Update water aura, if player is in water (HACK) + * \param diff : time ellapsed since the last call (in ms) + */ + bool Update(uint32 diff); + + /** + * \brief Called when a creature is spawn or remove from WG + * -Update vehicle count + * \param add : true > creature is spawn false > creature is remove + */ + void OnCreatureCreate(Creature *creature, bool add); + + /** + * \brief Called when a wall/tower is broken + * -Update quest + */ + void BrokenWallOrTower(TeamId team); + + /** + * \brief Called when a tower is damaged + * -Update tower count (for reward calcul) + */ + void AddDamagedTower(TeamId team); + + /** + * \brief Called when tower is broken + * -Update tower buff + * -check if three south tower is down for remove 10 minutes to wg + */ + void AddBrokenTower(TeamId team); + + void DoCompleteOrIncrementAchievement(uint32 achievement, Player *player, uint8 incrementNumber = 1); + + /** + * \brief called when a player is die, for add him to resurrect queue + */ + void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid); + + /** + * \brief Called when battlefield is setup, at server start + */ + bool SetupBattlefield(); + + /// Return pointer to relic object + GameObject *GetRelic() + { + return m_relic; + } + + /// Define relic object + void SetRelic(GameObject * relic) + { + m_relic = relic; + } + + /// Say if player can click or not on orb (last door broken) + bool CanClickOnOrb() + { + return m_bCanClickOnOrb; + } + + /// Define if player can click or not on orb (if last door broken) + void AllowToClickOnOrb(bool allow) + { + m_bCanClickOnOrb = allow; + } + + void RewardMarkOfHonor(Player *plr, uint32 count); + + void UpdateVehicleCountWG(); + void UpdateCounterVehicle(bool init); + + WorldPacket BuildInitWorldStates(); + void SendInitWorldStatesTo(Player * plr); + void SendInitWorldStatesToAll(); + + void HandleKill(Player *killer, Unit *victim); + void PromotePlayer(Player *killer); + + void UpdateTenacity(); + void ProcessEvent(GameObject *obj, uint32 eventId); + + protected: + bool m_bCanClickOnOrb; + GameObject *m_relic; + GameObjectBuilding BuildingsInZone; + GuidSet KeepCreature[2]; + GuidSet OutsideCreature[2]; + WorkShop WorkShopList; + GuidSet CanonList; + GameObjectSet DefenderPortalList; + GameObjectSet m_KeepGameObject[2]; + GuidSet m_vehicles[2]; + GuidSet m_PlayersIsSpellImu; // Player is dead + uint32 m_tenacityStack; + uint32 m_saveTimer; +}; + +#define NORTHREND_WINTERGRASP 4197 + +enum eWGGameObjectBuildingType +{ + BATTLEFIELD_WG_OBJECTTYPE_DOOR, + BATTLEFIELD_WG_OBJECTTYPE_TITANRELIC, + BATTLEFIELD_WG_OBJECTTYPE_WALL, + BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST, + BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER, + BATTLEFIELD_WG_OBJECTTYPE_TOWER, +}; + +enum eWGGameObjectState +{ + BATTLEFIELD_WG_OBJECTSTATE_NONE, + BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_INTACT, + BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DAMAGE, + BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DESTROY, + BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT, + BATTLEFIELD_WG_OBJECTSTATE_HORDE_DAMAGE, + BATTLEFIELD_WG_OBJECTSTATE_HORDE_DESTROY, + BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT, + BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE, + BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY, +}; + +enum eWGWorkShopType +{ + BATTLEFIELD_WG_WORKSHOP_NE, + BATTLEFIELD_WG_WORKSHOP_NW, + BATTLEFIELD_WG_WORKSHOP_SE, + BATTLEFIELD_WG_WORKSHOP_SW, + BATTLEFIELD_WG_WORKSHOP_KEEP_WEST, + BATTLEFIELD_WG_WORKSHOP_KEEP_EAST, +}; + +enum eWGTeamControl +{ + BATTLEFIELD_WG_TEAM_ALLIANCE, + BATTLEFIELD_WG_TEAM_HORDE, + BATTLEFIELD_WG_TEAM_NEUTRAL, +}; + +// TODO: Handle this with creature_text ? +enum eWGText +{ +// *INDENT-OFF* + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NE = 12055, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NW = 12052, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_SE = 12053, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_SW = 12054, + BATTLEFIELD_WG_TEXT_WORKSHOP_ATTACK = 12051, + BATTLEFIELD_WG_TEXT_WORKSHOP_TAKEN = 12050, + BATTLEFIELD_WG_TEXT_ALLIANCE = 12057, + BATTLEFIELD_WG_TEXT_HORDE = 12056, + BATTLEFIELD_WG_TEXT_WILL_START = 12058, + BATTLEFIELD_WG_TEXT_START = 12067, + BATTLEFIELD_WG_TEXT_FIRSTRANK = 12059, + BATTLEFIELD_WG_TEXT_SECONDRANK = 12060, + BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_NE = 12062, + BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_NW = 12064, + BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_SE = 12061, + BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_SW = 12063, + BATTLEFIELD_WG_TEXT_TOWER_DAMAGE = 12065, + BATTLEFIELD_WG_TEXT_TOWER_DESTROY = 12066, + BATTLEFIELD_WG_TEXT_TOWER_NAME_S = 12069, + BATTLEFIELD_WG_TEXT_TOWER_NAME_E = 12070, + BATTLEFIELD_WG_TEXT_TOWER_NAME_W = 12071, + BATTLEFIELD_WG_TEXT_DEFEND_KEEP = 12068, + BATTLEFIELD_WG_TEXT_WIN_KEEP = 12072, +// *INDENT-ON* +}; + +enum eWGObject +{ +// *INDENT-OFF* + BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NE = 190475, + BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NW = 190487, + BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SE = 194959, + BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SW = 194962, + BATTLEFIELD_WG_GAMEOBJECT_TITAN_RELIC = 192829, +// *INDENT-ON* +}; +struct BfWGObjectPosition +{ + float x; + float y; + float z; + float o; + uint32 entryh; + uint32 entrya; +}; + +// ********************************************************* +// ************Destructible (Wall,Tower..)****************** +// ********************************************************* + +struct BfWGBuildingSpawnData +{ + uint32 entry; + uint32 WorldState; + float x; + float y; + float z; + float o; + uint32 type; + uint32 nameid; +}; + +#define WG_MAX_OBJ 32 +const BfWGBuildingSpawnData WGGameObjectBuillding[WG_MAX_OBJ] = { + // Wall (Not spawned in db) + // Entry WS X Y Z O type NameID + { 190219, 3749, 5371.46f, 3047.47f, 407.571f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190220, 3750, 5331.26f, 3047.1f, 407.923f, 0.052359f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191795, 3764, 5385.84f, 2909.49f, 409.713f, 0.00872f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191796, 3772, 5384.45f, 2771.84f, 410.27f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191799, 3762, 5371.44f, 2630.61f, 408.816f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191800, 3766, 5301.84f, 2909.09f, 409.866f, 0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191801, 3770, 5301.06f, 2771.41f, 409.901f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191802, 3751, 5280.2f, 2995.58f, 408.825f, 1.61443f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191803, 3752, 5279.14f, 2956.02f, 408.604f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191804, 3767, 5278.69f, 2882.51f, 409.539f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191806, 3769, 5279.5f, 2798.94f, 409.998f, 1.5708f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191807, 3759, 5279.94f, 2724.77f, 409.945f, 1.56207f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191808, 3760, 5279.6f, 2683.79f, 409.849f, 1.55334f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191809, 3761, 5330.96f, 2630.78f, 409.283f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190369, 3753, 5256.08f, 2933.96f, 409.357f, 3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190370, 3758, 5257.46f, 2747.33f, 409.743f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190371, 3754, 5214.96f, 2934.09f, 409.19f, -0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190372, 3757, 5215.82f, 2747.57f, 409.188f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190374, 3755, 5162.27f, 2883.04f, 410.256f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 190376, 3756, 5163.72f, 2799.84f, 409.227f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + + // Tower of keep (Not spawned in db) + { 190221, 3711, 5281.15f, 3044.59f, 407.843f, 3.11539f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER, BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_NW }, + { 190373, 3713, 5163.76f, 2932.23f, 409.19f, 3.12412f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER, BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_SW }, + { 190377, 3714, 5166.4f, 2748.37f, 409.188f, -1.5708f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER, BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_SE }, + { 190378, 3712, 5281.19f, 2632.48f, 409.099f, -1.58825f, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER, BATTLEFIELD_WG_TEXT_KEEPTOWER_NAME_NE }, + + // Wall (with passage) (Not spawned in db) + { 191797, 3765, 5343.29f, 2908.86f, 409.576f, 0.008724f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191798, 3771, 5342.72f, 2771.39f, 409.625f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + { 191805, 3768, 5279.13f, 2840.8f, 409.783f, 1.57952f, BATTLEFIELD_WG_OBJECTTYPE_WALL, 0 }, + + // South tower (Not spawned in db) + { 190356, 3704, 4557.17f, 3623.94f, 395.883f, 1.67552f, BATTLEFIELD_WG_OBJECTTYPE_TOWER, BATTLEFIELD_WG_TEXT_TOWER_NAME_W }, + { 190357, 3705, 4398.17f, 2822.5f, 405.627f, -3.12412f, BATTLEFIELD_WG_OBJECTTYPE_TOWER, BATTLEFIELD_WG_TEXT_TOWER_NAME_S }, + { 190358, 3706, 4459.1f, 1944.33f, 434.991f, -2.00276f, BATTLEFIELD_WG_OBJECTTYPE_TOWER, BATTLEFIELD_WG_TEXT_TOWER_NAME_E }, + + // Door of forteress (Not spawned in db) + { 190375, 3763, 5162.99f, 2841.23f, 410.162f, -3.13286f, BATTLEFIELD_WG_OBJECTTYPE_DOOR, 0 }, + + // Last door (Not spawned in db) + { 191810, 3773, 5397.11f, 2841.54f, 425.899f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST, 0 }, +}; + + +// ********************************************************* +// **********Keep Element(GameObject,Creature)************** +// ********************************************************* + +// Keep gameobject +// 192488 : 10 in sql, 19 in header +// 192501 : 12 in sql, 17 in header +// 192416 : 1 in sql, 33 in header +// 192374 : 1 in sql, 1 in header +// 192375 : 1 in sql, 1 in header +// 192336 : 1 in sql, 1 in header +// 192255 : 1 in sql, 1 in header +// 192269 : 1 in sql, 7 in header +// 192254 : 1 in sql, 1 in header +// 192349 : 1 in sql, 1 in header +// 192366 : 1 in sql, 3 in header +// 192367 : 1 in sql, 1 in header +// 192364 : 1 in sql, 1 in header +// 192370 : 1 in sql, 1 in header +// 192369 : 1 in sql, 1 in header +// 192368 : 1 in sql, 1 in header +// 192362 : 1 in sql, 1 in header +// 192363 : 1 in sql, 1 in header +// 192379 : 1 in sql, 1 in header +// 192378 : 1 in sql, 1 in header +// 192355 : 1 in sql, 1 in header +// 192354 : 1 in sql, 1 in header +// 192358 : 1 in sql, 1 in header +// 192359 : 1 in sql, 1 in header +// 192338 : 1 in sql, 1 in header +// 192339 : 1 in sql, 1 in header +// 192284 : 1 in sql, 1 in header +// 192285 : 1 in sql, 1 in header +// 192371 : 1 in sql, 1 in header +// 192372 : 1 in sql, 1 in header +// 192373 : 1 in sql, 1 in header +// 192360 : 1 in sql, 1 in header +// 192361 : 1 in sql, 1 in header +// 192356 : 1 in sql, 1 in header +// 192352 : 1 in sql, 1 in header +// 192353 : 1 in sql, 1 in header +// 192357 : 1 in sql, 1 in header +// 192350 : 1 in sql, 1 in header +// 192351 : 1 in sql, 1 in header +#define WG_KEEPGAMEOBJECT_MAX 44 +const BfWGObjectPosition WGKeepGameObject[WG_KEEPGAMEOBJECT_MAX] = { + { 5262.540039f, 3047.949951f, 432.054993f, 3.106650f, 192488, 192501 }, // Flag on tower + { 5272.939941f, 2976.550049f, 444.492004f, 3.124120f, 192374, 192416 }, // Flag on Wall Intersect + { 5235.189941f, 2941.899902f, 444.278015f, 1.588250f, 192375, 192416 }, // Flag on Wall Intersect + { 5163.129883f, 2952.590088f, 433.502991f, 1.535890f, 192488, 192501 }, // Flag on tower + { 5145.109863f, 2935.000000f, 433.385986f, 3.141590f, 192488, 192501 }, // Flag on tower + { 5158.810059f, 2883.129883f, 431.618011f, 3.141590f, 192488, 192416 }, // Flag on wall + { 5154.490234f, 2862.149902f, 445.011993f, 3.141590f, 192336, 192416 }, // Flag on Wall Intersect + { 5154.520020f, 2853.310059f, 409.183014f, 3.141590f, 192255, 192269 }, // Flag on the floor + { 5154.459961f, 2828.939941f, 409.188995f, 3.141590f, 192254, 192269 }, // Flag on the floor + { 5155.310059f, 2820.739990f, 444.979004f, -3.13286f, 192349, 192416 }, // Flag on wall intersect + { 5160.339844f, 2798.610107f, 430.769012f, 3.141590f, 192488, 192416 }, // Flag on wall + { 5146.040039f, 2747.209961f, 433.584015f, 3.071770f, 192488, 192501 }, // Flag on tower + { 5163.779785f, 2729.679932f, 433.394012f, -1.58825f, 192488, 192501 }, // Flag on tower + { 5236.270020f, 2739.459961f, 444.992004f, -1.59698f, 192366, 192416 }, // Flag on wall intersect + { 5271.799805f, 2704.870117f, 445.183014f, -3.13286f, 192367, 192416 }, // Flag on wall intersect + { 5260.819824f, 2631.800049f, 433.324005f, 3.054330f, 192488, 192501 }, // Flag on tower + { 5278.379883f, 2613.830078f, 433.408997f, -1.58825f, 192488, 192501 }, // Flag on tower + { 5350.879883f, 2622.719971f, 444.686005f, -1.57080f, 192364, 192416 }, // Flag on wall intersect + { 5392.270020f, 2639.739990f, 435.330994f, 1.509710f, 192370, 192416 }, // Flag on wall intersect + { 5350.950195f, 2640.360107f, 435.407990f, 1.570800f, 192369, 192416 }, // Flag on wall intersect + { 5289.459961f, 2704.679932f, 435.875000f, -0.01745f, 192368, 192416 }, // Flag on wall intersect + { 5322.120117f, 2763.610107f, 444.973999f, -1.55334f, 192362, 192416 }, // Flag on wall intersect + { 5363.609863f, 2763.389893f, 445.023987f, -1.54462f, 192363, 192416 }, // Flag on wall intersect + { 5363.419922f, 2781.030029f, 435.763000f, 1.570800f, 192379, 192416 }, // Flag on wall intersect + { 5322.020020f, 2781.129883f, 435.811005f, 1.570800f, 192378, 192416 }, // Flag on wall intersect + { 5288.919922f, 2820.219971f, 435.721008f, 0.017452f, 192355, 192416 }, // Flag on wall intersect + { 5288.410156f, 2861.790039f, 435.721008f, 0.017452f, 192354, 192416 }, // Flag on wall intersect + { 5322.229980f, 2899.429932f, 435.808014f, -1.58825f, 192358, 192416 }, // Flag on wall intersect + { 5364.350098f, 2899.399902f, 435.838989f, -1.57080f, 192359, 192416 }, // Flag on wall intersect + { 5397.759766f, 2873.080078f, 455.460999f, 3.106650f, 192338, 192416 }, // Flag on keep + { 5397.390137f, 2809.330078f, 455.343994f, 3.106650f, 192339, 192416 }, // Flag on keep + { 5372.479980f, 2862.500000f, 409.049011f, 3.141590f, 192284, 192269 }, // Flag on floor + { 5371.490234f, 2820.800049f, 409.177002f, 3.141590f, 192285, 192269 }, // Flag on floor + { 5364.290039f, 2916.939941f, 445.330994f, 1.579520f, 192371, 192416 }, // Flag on wall intersect + { 5322.859863f, 2916.949951f, 445.153992f, 1.562070f, 192372, 192416 }, // Flag on wall intersect + { 5290.350098f, 2976.560059f, 435.221008f, 0.017452f, 192373, 192416 }, // Flag on wall intersect + { 5352.370117f, 3037.090088f, 435.252014f, -1.57080f, 192360, 192416 }, // Flag on wall intersect + { 5392.649902f, 3037.110107f, 433.713013f, -1.52716f, 192361, 192416 }, // Flag on wall intersect + { 5237.069824f, 2757.030029f, 435.795990f, 1.518440f, 192356, 192416 }, // Flag on wall intersect + { 5173.020020f, 2820.929932f, 435.720001f, 0.017452f, 192352, 192416 }, // Flag on wall intersect + { 5172.109863f, 2862.570068f, 435.721008f, 0.017452f, 192353, 192416 }, // Flag on wall intersect + { 5235.339844f, 2924.340088f, 435.040009f, -1.57080f, 192357, 192416 }, // Flag on wall intersect + { 5270.689941f, 2861.780029f, 445.058014f, -3.11539f, 192350, 192416 }, // Flag on wall intersect + { 5271.279785f, 2820.159912f, 445.200989f, -3.13286f, 192351, 192416 } // Flag on wall intersect +}; + +// Keep turret +struct BfWGTurretPos +{ + float x; + float y; + float z; + float o; +}; + +#define WG_MAX_TURRET 15 +const BfWGTurretPos 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 +#define WG_MAX_KEEP_NPC 39 +const BfWGObjectPosition 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 Plumembrase + { 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 +}; + +#define WG_MAX_OUTSIDE_NPC 14 +#define WG_OUTSIDE_ALLIANCE_NPC 7 +const BfWGObjectPosition 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 BfWGWGTeleporterData +{ + uint32 entry; // gameobject entry + float x; + float y; + float z; + float o; +}; + +#define WG_MAX_TELEPORTER 12 +const BfWGWGTeleporterData 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 BfWGTowerData +{ + uint32 towerentry; // Gameobject id of tower + uint8 nbObject; // Number of gameobjects spawned on this point + BfWGObjectPosition GameObject[6]; // Gameobject position and entry (Horde/Alliance) + + // Creature : Turrets and Guard, TODO: check if killed on tower destruction? tower damage? + uint8 nbCreatureBottom; + BfWGObjectPosition CreatureBottom[9]; + uint8 nbCreatureTop; + BfWGObjectPosition CreatureTop[5]; +}; + +#define WG_MAX_ATTACKTOWERS 3 +// 192414 : 0 in sql, 1 in header +// 192278 : 0 in sql, 3 in header +const BfWGTowerData 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 BfWGTurretData +{ + uint32 towerentry; + uint8 nbTurretBottom; + BfWGTurretPos TurretBottom[5]; + uint8 nbTurretTop; + BfWGTurretPos TurretTop[5]; +}; + +#define WG_MAX_TOWERTURRET 7 + +const BfWGTurretData TowerTurret[WG_MAX_TOWERTURRET] = +{ + { + 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 BfWGWorkShopDataBase +{ + uint32 entry; + uint32 worldstate; + uint32 type; + uint32 nameid; + BfWGObjectPosition CapturePoint; + uint8 nbcreature; + BfWGObjectPosition CreatureData[10]; + uint8 nbgob; + BfWGObjectPosition GameObjectData[10]; +}; +// 6 engineer per faction in sql / 6 engineer per faction in header +#define WG_MAX_WORKSHOP 6 +const BfWGWorkShopDataBase WGWorkShopDataBase[WG_MAX_WORKSHOP] = { + { + 192031, + 3701, + BATTLEFIELD_WG_WORKSHOP_NE, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NE, + { 4949.344238f, 2432.585693f, 320.176971f, 1.386214f, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NE, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NE }, + 1, + { + { 4939.759766f, 2389.060059f, 326.153015f, 3.263770f, 30400, 30499 }, + { 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 } + }, + 6, + { + { 4778.189f, 2438.060f, 345.644f, -2.940f, 192280, 192274 }, + { 5024.569f, 2532.750f, 344.023f, -1.937f, 192280, 192274 }, + { 4811.399f, 2441.899f, 358.207f, -2.003f, 192435, 192406 }, + { 4805.669f, 2407.479f, 358.191f, 1.780f, 192435, 192406 }, + { 5004.350f, 2486.360f, 358.449f, 2.172f, 192435, 192406 }, + { 4983.279f, 2503.090f, 358.177f, -0.427f, 192435, 192406 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } + } + }, + { + 192030, + 3700, + BATTLEFIELD_WG_WORKSHOP_NW, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NW, + { 4948.524414f, 3342.337891f, 376.875366f, 4.400566f, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NW, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_NW }, + 1, + { + { 4964.890137f, 3383.060059f, 382.911011f, 6.126110f, 30400, 30499 }, + { 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 } + }, + 4, + { + { 5006.339f, 3280.399f, 371.162f, 2.225f, 192280, 192274 }, + { 5041.609f, 3294.399f, 382.149f, -1.631f, 192434, 192406 }, + { 4857.970f, 3335.439f, 368.881f, -2.945f, 192280, 192274 }, + { 4855.629f, 3297.620f, 376.739f, -3.132f, 192435, 192406 }, + { 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 } + } + }, + { + 192033, + 3703, + BATTLEFIELD_WG_WORKSHOP_SE, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_SE, + { 4398.076660f, 2356.503662f, 376.190491f, 0.525406f, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SE, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SE }, + 9, + { + { 4417.919922f, 2331.239990f, 370.919006f, 5.846850f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4418.609863f, 2355.290039f, 372.490997f, 6.021390f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4391.669922f, 2300.610107f, 374.743011f, 4.921830f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4349.120117f, 2299.280029f, 374.743011f, 4.904380f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4333.549805f, 2333.909912f, 376.156006f, 0.973007f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4413.430176f, 2393.449951f, 376.359985f, 1.064650f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4388.129883f, 2411.979980f, 374.743011f, 1.640610f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4349.540039f, 2411.260010f, 374.743011f, 2.059490f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4357.669922f, 2357.989990f, 382.006989f, 1.675520f, 30400, 30499 }, + { 0, 0, 0, 0, 0, 0 } + }, + 2, + { + { 4417.250f, 2301.139f, 377.213f, 0.026f, 192435, 192406 }, + { 4417.939f, 2324.810f, 371.576f, 3.080f, 192280, 192274 }, + { 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 } + } + }, + { + 192032, + 3702, + BATTLEFIELD_WG_WORKSHOP_SW, + BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_SW, + { 4390.776367f, 3304.094482f, 372.429077f, 6.097023f, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SW, BATTLEFIELD_WG_GAMEOBJECT_FACTORY_BANNER_SW }, + 9, + { + { 4425.290039f, 3291.510010f, 370.773987f, 0.122173f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4424.609863f, 3321.100098f, 369.800995f, 0.034907f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4392.399902f, 3354.610107f, 369.597992f, 1.570800f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4370.979980f, 3355.020020f, 371.196991f, 1.675520f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4394.660156f, 3231.989990f, 369.721985f, 4.625120f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4366.979980f, 3233.560059f, 371.584991f, 4.939280f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4337.029785f, 3261.659912f, 373.524994f, 3.263770f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4323.779785f, 3287.100098f, 378.894989f, 2.862340f, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, + { 4354.149902f, 3312.820068f, 378.045990f, 1.675520f, 30400, 30499 }, + { 0, 0, 0, 0, 0, 0 } + }, + 3, + { + { 4438.299f, 3361.080f, 371.567f, -0.017f, 192435, 192406 }, + { 4448.169f, 3235.629f, 370.411f, -1.562f, 192435, 192406 }, + { 4424.149f, 3286.540f, 371.545f, 3.124f, 192280, 192274 }, + { 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 } + } + }, + { + 192028, + 3698, + BATTLEFIELD_WG_WORKSHOP_KEEP_WEST, + 0, + { 0, 0, 0, 0, 0, 0 }, + 1, + { + { 5392.910156f, 2975.260010f, 415.222992f, 4.555310f, 30400, 30499 }, + { 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 }, + { 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 } + } + }, + { + 192029, + 3699, + BATTLEFIELD_WG_WORKSHOP_KEEP_EAST, + 0, + { 0, 0, 0, 0, 0, 0 }, + 1, + { + { 5391.609863f, 2707.719971f, 415.050995f, 4.555310f, 30400, 30499 }, + { 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 }, + { 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 } + } + } +}; + +// ******************************************************************** +// * Structs using for Building,Graveyard,Workshop * +// ******************************************************************** +// Structure for different buildings that can be destroyed during battle +struct BfWGGameObjectBuilding +{ + BfWGGameObjectBuilding(BattlefieldWG *WG) + { + m_WG = WG; + m_Team = 0; + m_Build = NULL; + m_Type = 0; + m_WorldState = 0; + m_State = 0; + m_NameId = 0; + } + + // the team that controls this point + uint8 m_Team; + + // WG object + BattlefieldWG *m_WG; + + // Linked gameobject + GameObject *m_Build; + + // eWGGameObjectBuildingType + uint32 m_Type; + + // WorldState + uint32 m_WorldState; + + // eWGGameObjectState + uint32 m_State; + + // Name id for warning text + uint32 m_NameId; + + // GameObject associations + GameObjectSet m_GameObjectList[2]; + + // Creature associations + GuidSet m_CreatureBottomList[2]; + GuidSet m_CreatureTopList[2]; + GuidSet m_TurretBottomList; + GuidSet m_TurretTopList; + + void Rebuild() + { + switch (m_Type) + { + case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER: + case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST: + case BATTLEFIELD_WG_OBJECTTYPE_DOOR: + case BATTLEFIELD_WG_OBJECTTYPE_WALL: + m_Team = m_WG->GetDefenderTeam(); // Objects that are part of the keep should be the defender's + break; + case BATTLEFIELD_WG_OBJECTTYPE_TOWER: + m_Team = m_WG->GetAttackerTeam(); // The towers in the south should be the attacker's + break; + default: + m_Team = TEAM_NEUTRAL; + break; + } + + // Rebuild gameobject + m_Build->Rebuild(); + + // Update worldstate + m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT - (m_Team * 3); + m_WG->SendUpdateWorldState(m_WorldState, m_State); + UpdateCreatureAndGo(); + m_Build->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[m_Team]); + } + + // Called when associated gameobject is damaged + void Damaged() + { + // Update worldstate + m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE - (m_Team * 3); + m_WG->SendUpdateWorldState(m_WorldState, m_State); + + // Send warning message + if (m_NameId) // tower damage + name + m_WG->SendWarningToAllInZone(m_NameId); + + for (GuidSet::const_iterator itr = m_CreatureTopList[m_WG->GetAttackerTeam()].begin(); itr != m_CreatureTopList[m_WG->GetAttackerTeam()].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + for (GuidSet::const_iterator itr = m_TurretTopList.begin(); itr != m_TurretTopList.end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + if (m_Type == BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER) + m_WG->AddDamagedTower(m_WG->GetDefenderTeam()); + else if (m_Type == BATTLEFIELD_WG_OBJECTTYPE_TOWER) + m_WG->AddDamagedTower(m_WG->GetAttackerTeam()); + } + + // Called when associated gameobject is destroyed + void Destroyed() + { + // Update worldstate + m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY - (m_Team * 3); + m_WG->SendUpdateWorldState(m_WorldState, m_State); + + // Warn players + if (m_NameId) + m_WG->SendWarningToAllInZone(m_NameId); + + switch (m_Type) + { + // Inform the global wintergrasp script of the destruction of this object + case BATTLEFIELD_WG_OBJECTTYPE_TOWER: + case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER: + m_WG->AddBrokenTower(TeamId(m_Team)); + break; + case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST: + m_WG->AllowToClickOnOrb(true); + if (m_WG->GetRelic()) + m_WG->GetRelic()->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + else + sLog->outError("BATTLEFIELD: WG: Relic cant be clickable"); + break; + } + + m_WG->BrokenWallOrTower(TeamId(m_Team)); + } + + void Init(GameObject *go, uint32 type, uint32 worldstate, uint32 nameid) + { + // GameObject associated to object + m_Build = go; + + // Type of building (WALL/TOWER/DOOR) + m_Type = type; + + // WorldState for client (icon on map) + m_WorldState = worldstate; + + // NameId for Warning text + m_NameId = nameid; + + switch (m_Type) + { + case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER: + case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST: + case BATTLEFIELD_WG_OBJECTTYPE_DOOR: + case BATTLEFIELD_WG_OBJECTTYPE_WALL: + m_Team = m_WG->GetDefenderTeam(); // Objects that are part of the keep should be the defender's + break; + case BATTLEFIELD_WG_OBJECTTYPE_TOWER: + m_Team = m_WG->GetAttackerTeam(); // The towers in the south should be the attacker's + break; + default: + m_Team = TEAM_NEUTRAL; + break; + } + + m_State = sWorld->getWorldState(m_WorldState); + if (m_Build) + { + switch (m_State) + { + case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT: + case BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT: + m_Build->Rebuild(); + break; + case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY: + case BATTLEFIELD_WG_OBJECTSTATE_HORDE_DESTROY: + m_Build->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); + m_Build->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + m_Build->SetUInt32Value(GAMEOBJECT_DISPLAYID, m_Build->GetGOInfo()->building.destroyedDisplayId); + break; + case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE: + case BATTLEFIELD_WG_OBJECTSTATE_HORDE_DAMAGE: + m_Build->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DAMAGED); + m_Build->SetUInt32Value(GAMEOBJECT_DISPLAYID, m_Build->GetGOInfo()->building.damagedDisplayId); + break; + } + } + + int32 towerid = -1; + switch (go->GetEntry()) + { + case 190221: + towerid = 0; + break; + case 190373: + towerid = 1; + break; + case 190377: + towerid = 2; + break; + case 190378: + towerid = 3; + break; + case 190356: + towerid = 4; + break; + case 190357: + towerid = 5; + break; + case 190358: + towerid = 6; + break; + } + + if (towerid > 3) + { + // Spawn associate gameobjects + for (uint8 i = 0; i < AttackTowers[towerid - 4].nbObject; i++) + { + BfWGObjectPosition gob = AttackTowers[towerid - 4].GameObject[i]; + if (GameObject *go = m_WG->SpawnGameObject(gob.entryh, gob.x, gob.y, gob.z, gob.o)) + m_GameObjectList[TEAM_HORDE].insert(go); + if (GameObject *go = m_WG->SpawnGameObject(gob.entrya, gob.x, gob.y, gob.z, gob.o)) + m_GameObjectList[TEAM_ALLIANCE].insert(go); + } + + // Spawn associate npc bottom + for (uint8 i = 0; i < AttackTowers[towerid - 4].nbCreatureBottom; i++) + { + BfWGObjectPosition crea = AttackTowers[towerid - 4].CreatureBottom[i]; + if (Creature *creature = m_WG->SpawnCreature(crea.entryh, crea.x, crea.y, crea.z, crea.o, TEAM_HORDE)) + m_CreatureBottomList[TEAM_HORDE].insert(creature->GetGUID()); + if (Creature *creature = m_WG->SpawnCreature(crea.entrya, crea.x, crea.y, crea.z, crea.o, TEAM_ALLIANCE)) + m_CreatureBottomList[TEAM_ALLIANCE].insert(creature->GetGUID()); + } + + // Spawn associate npc top + for (uint8 i = 0; i < AttackTowers[towerid - 4].nbCreatureTop; i++) + { + BfWGObjectPosition crea = AttackTowers[towerid - 4].CreatureTop[i]; + if (Creature *creature = m_WG->SpawnCreature(crea.entryh, crea.x, crea.y, crea.z, crea.o, TEAM_HORDE)) + m_CreatureTopList[TEAM_HORDE].insert(creature->GetGUID()); + if (Creature *creature = m_WG->SpawnCreature(crea.entrya, crea.x, crea.y, crea.z, crea.o, TEAM_ALLIANCE)) + m_CreatureTopList[TEAM_ALLIANCE].insert(creature->GetGUID()); + } + } + + if (towerid >= 0) + { + // Spawn Turret bottom + for (uint8 i = 0; i < TowerTurret[towerid].nbTurretBottom; i++) + { + BfWGTurretPos turretpos = TowerTurret[towerid].TurretBottom[i]; + if (Creature *turret = m_WG->SpawnCreature(28366, turretpos.x, turretpos.y, turretpos.z, turretpos.o, TeamId(0))) + { + m_TurretBottomList.insert(turret->GetGUID()); + switch (go->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + turret->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + turret->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->HideNpc(turret); + } + } + + // Spawn Turret top + for (uint8 i = 0; i < TowerTurret[towerid].nbTurretTop; i++) + { + BfWGTurretPos turretpos = TowerTurret[towerid].TurretTop[i]; + if (Creature *turret = m_WG->SpawnCreature(28366, turretpos.x, turretpos.y, turretpos.z, turretpos.o, TeamId(0))) + { + m_TurretTopList.insert(turret->GetGUID()); + switch (go->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + turret->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + turret->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->HideNpc(turret); + } + } + UpdateCreatureAndGo(); + } + } + + void UpdateCreatureAndGo() + { + for (GuidSet::const_iterator itr = m_CreatureTopList[m_WG->GetDefenderTeam()].begin(); itr != m_CreatureTopList[m_WG->GetDefenderTeam()].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + for (GuidSet::const_iterator itr = m_CreatureTopList[m_WG->GetAttackerTeam()].begin(); itr != m_CreatureTopList[m_WG->GetAttackerTeam()].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->ShowNpc(creature, true); + + for (GuidSet::const_iterator itr = m_CreatureBottomList[m_WG->GetDefenderTeam()].begin(); itr != m_CreatureBottomList[m_WG->GetDefenderTeam()].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + for (GuidSet::const_iterator itr = m_CreatureBottomList[m_WG->GetAttackerTeam()].begin(); itr != m_CreatureBottomList[m_WG->GetAttackerTeam()].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->ShowNpc(creature, true); + + for (GameObjectSet::const_iterator itr = m_GameObjectList[m_WG->GetDefenderTeam()].begin(); itr != m_GameObjectList[m_WG->GetDefenderTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); + + for (GameObjectSet::const_iterator itr = m_GameObjectList[m_WG->GetAttackerTeam()].begin(); itr != m_GameObjectList[m_WG->GetAttackerTeam()].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); + } + + void UpdateTurretAttack(bool disable) + { + for (GuidSet::const_iterator itr = m_TurretBottomList.begin(); itr != m_TurretBottomList.end(); ++itr) + { + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature *creature = unit->ToCreature()) + { + if (m_Build) + { + if (disable) + { + switch (m_Build->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + creature->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + creature->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->HideNpc(creature); + } + else + { + switch (m_Build->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + creature->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + creature->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->ShowNpc(creature, true); + } + } + } + } + } + + for (GuidSet::const_iterator itr = m_TurretTopList.begin(); itr != m_TurretTopList.end(); ++itr) + { + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + { + if (Creature *creature = unit->ToCreature()) + { + if (m_Build) + { + if (disable) + { + switch (m_Build->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + creature->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + creature->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->HideNpc(creature); + } + else + { + switch (m_Build->GetEntry()) + { + case 190221: + case 190373: + case 190377: + case 190378: + { + creature->setFaction(WintergraspFaction[m_WG->GetDefenderTeam()]); + break; + } + case 190356: + case 190357: + case 190358: + { + creature->setFaction(WintergraspFaction[m_WG->GetAttackerTeam()]); + break; + } + } + m_WG->ShowNpc(creature, true); + } + } + } + } + } + } + + void Save() + { + sWorld->setWorldState(m_WorldState, m_State); + } +}; + +// Structure for the 6 workshop +struct BfWGWorkShopData +{ + BattlefieldWG *m_WG; // Object du joug + GameObject *m_Build; + uint32 m_Type; + uint32 m_State; // For worldstate + uint32 m_WorldState; + uint32 m_TeamControl; // Team witch control the workshop + GuidSet m_CreatureOnPoint[2]; // Contain all Creature associate to this point + GameObjectSet m_GameObjectOnPoint[2]; // Contain all Gameobject associate to this point + uint32 m_NameId; // Id of trinity_string witch contain name of this node, using for alert message + + BfWGWorkShopData(BattlefieldWG * WG) + { + m_WG = WG; + m_Build = NULL; + m_Type = 0; + m_State = 0; + m_WorldState = 0; + m_TeamControl = 0; + m_NameId = 0; + } + + // Spawning associate creature and store them + void AddCreature(BfWGObjectPosition obj) + { + if (Creature *creature = m_WG->SpawnCreature(obj.entryh, obj.x, obj.y, obj.z, obj.o, TEAM_HORDE)) + m_CreatureOnPoint[TEAM_HORDE].insert(creature->GetGUID()); + + if (Creature *creature = m_WG->SpawnCreature(obj.entrya, obj.x, obj.y, obj.z, obj.o, TEAM_ALLIANCE)) + m_CreatureOnPoint[TEAM_ALLIANCE].insert(creature->GetGUID()); + + } + + // Spawning Associate gameobject and store them + void AddGameObject(BfWGObjectPosition obj) + { + if (GameObject *gameobject = m_WG->SpawnGameObject(obj.entryh, obj.x, obj.y, obj.z, obj.o)) + m_GameObjectOnPoint[TEAM_HORDE].insert(gameobject); + if (GameObject *gameobject = m_WG->SpawnGameObject(obj.entrya, obj.x, obj.y, obj.z, obj.o)) + m_GameObjectOnPoint[TEAM_ALLIANCE].insert(gameobject); + } + + // Init method, setup variable + void Init(uint32 worldstate, uint32 type, uint32 nameid) + { + m_WorldState = worldstate; + m_Type = type; + m_NameId = nameid; + } + + // Called on change faction in CapturePoint class + void ChangeControl(uint8 team, bool init /* for first call in setup */ ) + { + switch (team) + { + case BATTLEFIELD_WG_TEAM_NEUTRAL: + { + // Send warning message to all player for inform a faction attack a workshop + // alliance / horde attacking workshop + m_WG->SendWarningToAllInZone(m_TeamControl ? m_NameId : m_NameId + 1); + break; + } + case BATTLEFIELD_WG_TEAM_ALLIANCE: + { + // Show Alliance creature + for (GuidSet::const_iterator itr = m_CreatureOnPoint[TEAM_ALLIANCE].begin(); itr != m_CreatureOnPoint[TEAM_ALLIANCE].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->ShowNpc(creature, creature->GetEntry() != 30499); + + // Hide Horde creature + for (GuidSet::const_iterator itr = m_CreatureOnPoint[TEAM_HORDE].begin(); itr != m_CreatureOnPoint[TEAM_HORDE].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + // Show Alliance gameobject + for (GameObjectSet::const_iterator itr = m_GameObjectOnPoint[TEAM_ALLIANCE].begin(); itr != m_GameObjectOnPoint[TEAM_ALLIANCE].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); + + // Hide Horde gameobject + for (GameObjectSet::const_iterator itr = m_GameObjectOnPoint[TEAM_HORDE].begin(); itr != m_GameObjectOnPoint[TEAM_HORDE].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); + + + // Updating worldstate + m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT; + m_WG->SendUpdateWorldState(m_WorldState, m_State); + + // Warning message + if (!init) // workshop taken - alliance + m_WG->SendWarningToAllInZone(m_NameId); + + // Found associate graveyard and update it + if (m_Type < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST) + if (m_WG && m_WG->GetGraveYardById(m_Type)) + m_WG->GetGraveYardById(m_Type)->ChangeControl(TEAM_ALLIANCE); + + m_TeamControl = team; + break; + } + case BATTLEFIELD_WG_TEAM_HORDE: + { + // Show Horde creature + for (GuidSet::const_iterator itr = m_CreatureOnPoint[TEAM_HORDE].begin(); itr != m_CreatureOnPoint[TEAM_HORDE].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->ShowNpc(creature, creature->GetEntry() != 30400); + + // Hide Alliance creature + for (GuidSet::const_iterator itr = m_CreatureOnPoint[TEAM_ALLIANCE].begin(); itr != m_CreatureOnPoint[TEAM_ALLIANCE].end(); ++itr) + if (Unit *unit = sObjectAccessor->FindUnit((*itr))) + if (Creature *creature = unit->ToCreature()) + m_WG->HideNpc(creature); + + // Hide Alliance gameobject + for (GameObjectSet::const_iterator itr = m_GameObjectOnPoint[TEAM_ALLIANCE].begin(); itr != m_GameObjectOnPoint[TEAM_ALLIANCE].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); + + // Show Horde gameobject + for (GameObjectSet::const_iterator itr = m_GameObjectOnPoint[TEAM_HORDE].begin(); itr != m_GameObjectOnPoint[TEAM_HORDE].end(); ++itr) + (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); + + // Update worlstate + m_State = BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT; + m_WG->SendUpdateWorldState(m_WorldState, m_State); + + // Warning message + if (!init) // workshop taken - horde + m_WG->SendWarningToAllInZone(m_NameId + 1); + + // Update graveyard control + if (m_Type < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST) + if (m_WG && m_WG->GetGraveYardById(m_Type)) + m_WG->GetGraveYardById(m_Type)->ChangeControl(TEAM_HORDE); + + m_TeamControl = team; + break; + } + } + if (!init) + m_WG->UpdateCounterVehicle(false); + } + + void UpdateGraveYardAndWorkshop() + { + if (m_Type < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST) + m_WG->GetGraveYardById(m_Type)->ChangeControl(TeamId(m_TeamControl)); + else + ChangeControl(m_WG->GetDefenderTeam(), true); + } + + void Save() + { + sWorld->setWorldState(m_WorldState, m_State); + } +}; + +#endif diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 3b96b842ff7..d4cb88983d6 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1148,7 +1148,7 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player* player, uint32 team) if (group->IsMember(playerGuid)) { uint8 subgroup = group->GetMemberGroup(playerGuid); - player->SetBattlegroundRaid(group, subgroup); + player->SetBattlegroundOrBattlefieldRaid(group, subgroup); } else { diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 65ba16007d4..930cfbdf404 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -17,6 +17,7 @@ file(GLOB_RECURSE sources_Achievements Achievements/*.cpp Achievements/*.h) file(GLOB_RECURSE sources_Addons Addons/*.cpp Addons/*.h) file(GLOB_RECURSE sources_AI AI/*.cpp AI/*.h) file(GLOB_RECURSE sources_AuctionHouse AuctionHouse/*.cpp AuctionHouse/*.h) +file(GLOB_RECURSE sources_Battlefield Battlefield/*.cpp Battlefield/*.h) file(GLOB_RECURSE sources_Battlegrounds Battlegrounds/*.cpp Battlegrounds/*.h) file(GLOB_RECURSE sources_Calendar Calendar/*.cpp Calendar/*.h) file(GLOB_RECURSE sources_Chat Chat/*.cpp Chat/*.h) @@ -66,6 +67,7 @@ set(game_STAT_SRCS ${sources_Addons} ${sources_AI} ${sources_AuctionHouse} + ${sources_Battlefield} ${sources_Battlegrounds} ${sources_Calendar} ${sources_Chat} @@ -132,6 +134,9 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI ${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse + ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield + + ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield/Zones ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds/Zones ${CMAKE_CURRENT_SOURCE_DIR}/Calendar diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 85fa2c3e362..0726260f18d 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -831,6 +831,13 @@ bool GameObject::IsDynTransport() const return gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT || (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT && !gInfo->transport.pause); } +bool GameObject::IsDestructibleBuilding() const +{ + GameObjectTemplate const* gInfo = GetGOInfo(); + if (!gInfo) return false; + return gInfo->type == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING; +} + Unit* GameObject::GetOwner() const { return ObjectAccessor::GetUnit(*this, GetOwnerGUID()); @@ -847,7 +854,7 @@ bool GameObject::isAlwaysVisibleFor(WorldObject const* seer) const if (WorldObject::isAlwaysVisibleFor(seer)) return true; - if (IsTransport()) + if (IsTransport() || IsDestructibleBuilding()) return true; return false; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 95be55e595e..b817ef82f7b 100755 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -631,6 +631,7 @@ class GameObject : public WorldObject, public GridObject<GameObject> bool IsTransport() const; bool IsDynTransport() const; + bool IsDestructibleBuilding() const; uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 8694ac65eeb..a1af85dc04c 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -41,7 +41,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "SpellAuraEffects.h" - +#include "BattlefieldMgr.h" #include "TemporarySummon.h" #include "Totem.h" #include "OutdoorPvPMgr.h" @@ -2210,7 +2210,12 @@ void WorldObject::SetZoneScript() if (map->IsDungeon()) m_zoneScript = (ZoneScript*)((InstanceMap*)map)->GetInstanceScript(); else if (!map->IsBattlegroundOrArena()) - m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId()); + { + if (Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(GetZoneId())) + m_zoneScript = bf; + else + m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId()); + } } } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e45d75199b2..59f0b9fb1b0 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -70,6 +70,7 @@ #include "DisableMgr.h" #include "WeatherMgr.h" #include "LFGMgr.h" +#include "BattlefieldMgr.h" #include "CharacterDatabaseCleaner.h" #include "InstanceScript.h" #include <cmath> @@ -2405,6 +2406,7 @@ void Player::RemoveFromWorld() StopCastingBindSight(); UnsummonPetTemporaryIfAny(); sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); + sBattlefieldMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); } ///- Do not add/remove the player from the object storage @@ -5483,7 +5485,12 @@ void Player::RepopAtGraveyard() if (Battleground *bg = GetBattleground()) ClosestGrave = bg->GetClosestGraveYard(this); else - ClosestGrave = sObjectMgr->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam()); + { + if (sBattlefieldMgr.GetBattlefieldToZoneId(GetZoneId())) + ClosestGrave = sBattlefieldMgr.GetBattlefieldToZoneId(GetZoneId())->GetClosestGraveYard(this); + else + ClosestGrave = sObjectMgr->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam()); + } // stop countdown until repop m_deathTimer = 0; @@ -7379,6 +7386,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) { sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone); + sBattlefieldMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); + sBattlefieldMgr.HandlePlayerEnterZone(this, newZone); SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange... } @@ -7513,7 +7522,7 @@ void Player::CheckDuelDistance(time_t currTime) bool Player::IsOutdoorPvPActive() { - return isAlive() && !HasInvisibilityAura() && !HasStealthAura() && (IsPvP() || sWorld->IsPvPRealm()) && !HasUnitMovementFlag(MOVEMENTFLAG_FLYING) && !isInFlight(); + return isAlive() && !HasInvisibilityAura() && !HasStealthAura() && IsPvP() && !HasUnitMovementFlag(MOVEMENTFLAG_FLYING) && !isInFlight(); } void Player::DuelComplete(DuelCompleteType type) @@ -22547,7 +22556,7 @@ bool Player::isUsingLfg() return sLFGMgr->GetState(guid) != LFG_STATE_NONE; } -void Player::SetBattlegroundRaid(Group* group, int8 subgroup) +void Player::SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup) { //we must move references from m_group to m_originalGroup SetOriginalGroup(GetGroup(), GetSubGroup()); @@ -22557,7 +22566,7 @@ void Player::SetBattlegroundRaid(Group* group, int8 subgroup) m_group.setSubGroup((uint8)subgroup); } -void Player::RemoveFromBattlegroundRaid() +void Player::RemoveFromBattlegroundOrBattlefieldRaid() { //remove existing reference m_group.unlink(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e84f4ea306b..5b03e8cca99 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2378,8 +2378,8 @@ class Player : public Unit, public GridObject<Player> Player* GetNextRandomRaidMember(float radius); PartyResult CanUninviteFromGroup() const; // Battleground Group System - void SetBattlegroundRaid(Group* group, int8 subgroup = -1); - void RemoveFromBattlegroundRaid(); + void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup = -1); + void RemoveFromBattlegroundOrBattlefieldRaid(); Group * GetOriginalGroup() { return m_originalGroup.getTarget(); } GroupReference& GetOriginalGroupRef() { return m_originalGroup; } uint8 GetOriginalSubGroup() const { return m_originalGroup.getSubGroup(); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ff598119c37..5aafa49090f 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -54,7 +54,7 @@ #include "Vehicle.h" #include "Transport.h" #include "InstanceScript.h" - +#include "BattlefieldMgr.h" #include <math.h> float baseMoveSpeed[MAX_MOVE_TYPE] = @@ -15487,9 +15487,14 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh... // handle player kill only if not suicide (spirit of redemption for example) if (player && this != victim) + { if (OutdoorPvP* pvp = player->GetOutdoorPvP()) pvp->HandleKill(player, victim); + if (Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(player->GetZoneId())) + bf->HandleKill(player, victim); + } + //if (pVictim->GetTypeId() == TYPEID_PLAYER) // if (OutdoorPvP* pvp = pVictim->ToPlayer()->GetOutdoorPvP()) // pvp->HandlePlayerActivityChangedpVictim->ToPlayer(); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index ce193f798f0..f9a9a3bfc55 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -178,8 +178,13 @@ void Vehicle::ApplyAllImmunities() // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { - case 160: + case 160: //Isle of conquest turret + case 244: //Wintergrasp turret _me->SetControlled(true, UNIT_STAT_ROOT); + //me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT); + //me->SetSpeed(MOVE_TURN_RATE, 0.7f); + //me->SetSpeed(MOVE_PITCH_RATE, 0.7f); + //me->m_movementInfo.flags2=59; _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; default: @@ -464,6 +469,20 @@ void Vehicle::Dismiss() _me->AddObjectToRemoveList(); } +void Vehicle::TeleportVehicle(float x, float y, float z, float ang) +{ + vehiclePlayers.clear(); + for(int8 i = 0; i < 8; i++) + if (Unit* player = GetPassenger(i)) + vehiclePlayers.insert(player->GetGUID()); + + RemoveAllPassengers(); // this can unlink Guns from Siege Engines + _me->NearTeleportTo(x, y, z, ang); + for (GuidSet::const_iterator itr = vehiclePlayers.begin(); itr != vehiclePlayers.end(); ++itr) + if(Unit* plr = sObjectAccessor->FindUnit(*itr)) + plr->NearTeleportTo(x, y, z, ang); +} + void Vehicle::InitMovementInfoForBase() { uint32 vehicleFlags = GetVehicleInfo()->m_flags; diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index 79d5bbb0801..a95bd14d965 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -98,6 +98,7 @@ struct VehicleAccessory typedef std::vector<VehicleAccessory> VehicleAccessoryList; typedef std::map<uint32, VehicleAccessoryList> VehicleAccessoryMap; typedef std::map<int8, VehicleSeat> SeatMap; +typedef std::set<uint64> GuidSet; class Vehicle { @@ -129,6 +130,7 @@ class Vehicle void RelocatePassengers(float x, float y, float z, float ang); void RemoveAllPassengers(); void Dismiss(); + void TeleportVehicle(float x, float y, float z, float ang); bool IsVehicleInUse() { return Seats.begin() != Seats.end(); } SeatMap Seats; @@ -144,6 +146,7 @@ class Vehicle Unit* _me; VehicleEntry const* _vehicleInfo; + GuidSet vehiclePlayers; uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players }; diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 78f98ed9fca..f3192810575 100755 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -194,6 +194,7 @@ class ObjectAccessor // ACCESS LIKE THAT IS NOT THREAD SAFE static Pet * FindPet(uint64); static Player* FindPlayer(uint64); + static Creature* FindCreature(uint64); static Unit* FindUnit(uint64); Player* FindPlayerByName(const char* name); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e309809ef22..be24cba0375 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -836,6 +836,11 @@ class ObjectMgr return &mCreatureQuestRelations; } + QuestRelations* GetCreatureQuestInvolvedRelation() + { + return &mCreatureQuestInvolvedRelations; + } + QuestRelationBounds GetCreatureQuestRelationBounds(uint32 creature_entry) { return mCreatureQuestRelations.equal_range(creature_entry); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3c3b71deddc..4fb8e43cc7a 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -57,7 +57,7 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(0), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL), -m_bgGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(0), +m_bgGroup(NULL), m_bfGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(0), m_subGroupsCounts(NULL), m_guid(0), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0) { for (uint8 i = 0; i < TARGETICONCOUNT; ++i) @@ -102,7 +102,7 @@ bool Group::Create(Player *leader) m_leaderGuid = leaderGuid; m_leaderName = leader->GetName(); - m_groupType = isBGGroup() ? GROUPTYPE_BGRAID : GROUPTYPE_NORMAL; + m_groupType = (isBGGroup() || isBFGroup()) ? GROUPTYPE_BGRAID : GROUPTYPE_NORMAL; if (m_groupType & GROUPTYPE_RAID) _initRaidSubGroupsCounter(); @@ -114,7 +114,7 @@ bool Group::Create(Player *leader) m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) { m_dungeonDifficulty = leader->GetDungeonDifficulty(); m_raidDifficulty = leader->GetRaidDifficulty(); @@ -200,7 +200,7 @@ void Group::ConvertToLFG() { m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_UNK1); m_lootMethod = NEED_BEFORE_GREED; - if (!isBGGroup()) + if (!isBGGroup() && !isBFGroup()) CharacterDatabase.PExecute("UPDATE groups SET groupType='%u' WHERE guid='%u'", uint8(m_groupType), m_dbStoreId); SendUpdate(); } @@ -211,7 +211,7 @@ void Group::ConvertToRaid() _initRaidSubGroupsCounter(); - if (!isBGGroup()) + if (!isBGGroup() && !isBFGroup()) CharacterDatabase.PExecute("UPDATE groups SET groupType='%u' WHERE guid='%u'", uint8(m_groupType), m_dbStoreId); SendUpdate(); @@ -226,7 +226,7 @@ bool Group::AddInvite(Player* player) if (!player || player->GetGroupInvite()) return false; Group* group = player->GetGroup(); - if (group && group->isBGGroup()) + if (group && (group->isBGGroup() || group->isBFGroup())) group = player->GetOriginalGroup(); if (group) return false; @@ -323,8 +323,8 @@ bool Group::AddMember(Player* player) if (player) { player->SetGroupInvite(NULL); - if (player->GetGroup() && isBGGroup()) //if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() - player->SetBattlegroundRaid(this, subGroup); + if (player->GetGroup() && (isBGGroup() || isBFGroup())) //if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() + player->SetBattlegroundOrBattlefieldRaid(this, subGroup); else if (player->GetGroup()) //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() player->SetOriginalGroup(this, subGroup); else //if player is not in group, then call set group @@ -343,7 +343,7 @@ bool Group::AddMember(Player* player) } // insert into the table if we're not a battleground group - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) CharacterDatabase.PExecute("INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(%u, %u, %u, %u, %u)", m_dbStoreId, GUID_LOPART(member.guid), member.flags, member.group, member.roles); @@ -352,7 +352,7 @@ bool Group::AddMember(Player* player) if (player) { - if (!IsLeader(player->GetGUID()) && !isBGGroup()) + if (!IsLeader(player->GetGUID()) && !isBGGroup() && !isBFGroup()) { // reset the new member's instances, unless he is currently in one of them // including raid/heroic instances that they are not permanently bound to! @@ -397,15 +397,15 @@ bool Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /*= GROU if (isLFGGroup() && method == GROUP_REMOVEMETHOD_KICK) return m_memberSlots.size(); - // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG allow 1 member group) - if (GetMembersCount() > (isBGGroup() ? 1u : 2u)) + // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG/BF allow 1 member group) + if (GetMembersCount() > ((isBGGroup() || isBFGroup()) ? 1u : 2u)) { Player* player = sObjectMgr->GetPlayer(guid); if (player) { // Battleground group handling - if (isBGGroup()) - player->RemoveFromBattlegroundRaid(); + if (isBGGroup() || isBFGroup()) + player->RemoveFromBattlegroundOrBattlefieldRaid(); else // Regular group { @@ -513,7 +513,7 @@ void Group::ChangeLeader(const uint64 &guid) sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid); - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) { // Remove the groups permanent instance bindings for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) @@ -563,8 +563,8 @@ void Group::Disband(bool hideDestroy /* = false */) //we cannot call _removeMember because it would invalidate member iterator //if we are removing player from battleground raid - if (isBGGroup()) - player->RemoveFromBattlegroundRaid(); + if (isBGGroup() || isBFGroup()) + player->RemoveFromBattlegroundOrBattlefieldRaid(); else { //we can remove player who is in battleground from his original group @@ -608,7 +608,7 @@ void Group::Disband(bool hideDestroy /* = false */) RemoveAllInvites(); - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("DELETE FROM groups WHERE guid = %u", m_dbStoreId); @@ -1213,7 +1213,7 @@ void Group::SendUpdate() Player* member = sObjectMgr->GetPlayer(citr2->guid); uint8 onlineState = (member) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; - onlineState = onlineState | ((isBGGroup()) ? MEMBER_STATUS_PVP : 0); + onlineState = onlineState | ((isBGGroup() || isBFGroup()) ? MEMBER_STATUS_PVP : 0); data << citr2->name; data << uint64(citr2->guid); // guid @@ -1305,7 +1305,7 @@ bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group) SubGroupCounterIncrease(group); - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid)); return true; @@ -1538,7 +1538,7 @@ void Roll::targetObjectBuildLink() void Group::SetDungeonDifficulty(Difficulty difficulty) { m_dungeonDifficulty = difficulty; - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE guid ='%u'", m_dungeonDifficulty, m_dbStoreId); for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) @@ -1555,7 +1555,7 @@ void Group::SetDungeonDifficulty(Difficulty difficulty) void Group::SetRaidDifficulty(Difficulty difficulty) { m_raidDifficulty = difficulty; - if (!isBGGroup()) + if (!isBGGroup() || !isBFGroup()) CharacterDatabase.PExecute("UPDATE groups SET raiddifficulty = %u WHERE guid ='%u'", m_raidDifficulty, m_dbStoreId); for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) @@ -1584,7 +1584,7 @@ bool Group::InCombatToInstance(uint32 instanceId) void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) { - if (isBGGroup()) + if (isBGGroup() || isBFGroup()) return; // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND @@ -1692,7 +1692,7 @@ InstanceGroupBind* Group::GetBoundInstance(MapEntry const* mapEntry) InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load) { - if (!save || isBGGroup()) + if (!save || isBGGroup() || isBFGroup()) return NULL; InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; @@ -1807,6 +1807,11 @@ bool Group::isBGGroup() const return m_bgGroup != NULL; } +bool Group::isBFGroup() const +{ + return m_bfGroup != NULL; +} + bool Group::IsCreated() const { return GetMembersCount() > 0; @@ -1922,6 +1927,11 @@ void Group::SetBattlegroundGroup(Battleground *bg) m_bgGroup = bg; } +void Group::SetBattlefieldGroup(Battlefield *bg) +{ + m_bfGroup = bg; +} + void Group::SetGroupMemberFlag(uint64 guid, const bool &apply, GroupMemberFlags flag) { // Assistants, main assistants and main tanks are only available in raid groups diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 25e2fb9a96f..12e3c20af17 100755 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -26,6 +26,7 @@ #include "QueryResult.h" #include "SharedDefines.h" #include "Player.h" +#include "../../Battlefield/BattlefieldMgr.h" //FIXME class Creature; class GroupReference; @@ -204,6 +205,7 @@ class Group bool IsFull() const; bool isLFGGroup() const; bool isRaidGroup() const; + bool isBFGroup() const; bool isBGGroup() const; bool IsCreated() const; const uint64& GetLeaderGUID() const; @@ -239,6 +241,7 @@ class Group void ConvertToRaid(); void SetBattlegroundGroup(Battleground *bg); + void SetBattlefieldGroup(Battlefield *bf); GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot); void ChangeMembersGroup(const uint64 &guid, const uint8 &group); @@ -319,6 +322,7 @@ class Group GroupType m_groupType; Difficulty m_dungeonDifficulty; Difficulty m_raidDifficulty; + Battlefield* m_bfGroup; Battleground* m_bgGroup; uint64 m_targetIcons[TARGETICONCOUNT]; LootMethod m_lootMethod; diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 9c5e6b54440..4368e2caa58 100755 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -250,7 +250,7 @@ class Quest bool IsWeekly() const { return QuestFlags & QUEST_FLAGS_WEEKLY; } bool IsDailyOrWeekly() const { return QuestFlags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); } bool IsAutoAccept() const { return QuestFlags & QUEST_FLAGS_AUTO_ACCEPT; } - bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25; } + bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25 || Type == QUEST_TYPE_PVP; } bool IsAllowedInRaid() const; bool IsDFQuest() const { return QuestFlags & QUEST_TRINITY_FLAGS_DF_QUEST; } uint32 CalculateHonorGain(uint8 level) const; diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 0293c350649..2fa304d2d23 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -45,6 +45,7 @@ void AddSC_SmartSCripts(); //Commands void AddSC_account_commandscript(); void AddSC_achievement_commandscript(); +void AddSC_bf_commandscript(); void AddSC_debug_commandscript(); void AddSC_event_commandscript(); void AddSC_gm_commandscript(); @@ -644,6 +645,7 @@ void AddCommandScripts() { AddSC_account_commandscript(); AddSC_achievement_commandscript(); + AddSC_bf_commandscript(); AddSC_debug_commandscript(); AddSC_event_commandscript(); AddSC_gm_commandscript(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index a14a7175522..4e92b3091c1 100755 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -753,6 +753,14 @@ CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) return tmpscript->GetAI(creature); } +GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject) +{ + ASSERT(gameobject); + + GET_SCRIPT_RET(GameObjectScript, gameobject->GetScriptId(), tmpscript, NULL); + return tmpscript->GetAI(gameobject); +} + void ScriptMgr::OnCreatureUpdate(Creature* creature, uint32 diff) { ASSERT(creature); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index fb47282e9db..75dcf161815 100755 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -37,6 +37,7 @@ class Channel; class ChatCommand; class Creature; class CreatureAI; +class GameObjectAI; class DynamicObject; class GameObject; class Guild; @@ -468,6 +469,9 @@ class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> virtual void OnDestroyed(GameObject* /*go*/, Player* /*player*/, uint32 /*eventId*/) { } // Called when the gameobject is damaged (destructible buildings only). virtual void OnDamaged(GameObject* /*go*/, Player* /*player*/, uint32 /*eventId*/) { } + + // Called when a CreatureAI object is needed for the creature. + virtual GameObjectAI* GetAI(GameObject* /*gameobject*/) const { return NULL; } }; class AreaTriggerScript : public ScriptObject @@ -867,6 +871,7 @@ class ScriptMgr uint32 GetDialogStatus(Player* player, GameObject* go); void OnGameObjectDestroyed(GameObject* go, Player* player, uint32 eventId); void OnGameObjectDamaged(GameObject* go, Player* player, uint32 eventId); + GameObjectAI* GetGameObjectAI(GameObject* gameobject); void OnGameObjectUpdate(GameObject* go, uint32 diff); public: /* AreaTriggerScript */ diff --git a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp index 59c4911ae3a..4f867b47c25 100755 --- a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp @@ -586,46 +586,6 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) } } -void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); - - Battleground *bg = _player->GetBattleground(); - - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); -} - -void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); - - Battleground *bg = _player->GetBattleground(); - - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); -} - void WorldSession::HandleBattlemasterJoinArena(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp index 81f771fdada..a30bdbca0a8 100755 --- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp @@ -36,7 +36,8 @@ #include "zlib.h" #include "ObjectAccessor.h" #include "Object.h" -#include "Battleground.h" +#include "BattlegroundMgr.h" +#include "BattlefieldMgr.h" #include "OutdoorPvP.h" #include "Pet.h" #include "SocialMgr.h" @@ -1723,11 +1724,64 @@ void WorldSession::SendSetPhaseShift(uint32 PhaseShift) SendPacket(&data); } +//Battlefield and Battleground +void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); + + Battleground* bg = _player->GetBattleground(); + + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); + + if (Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(_player->GetZoneId())) + bf->SendAreaSpiritHealerQueryOpcode(_player,guid); +} + +void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); + + Battleground* bg = _player->GetBattleground(); + + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); + + if (Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(_player->GetZoneId())) + bf->AddPlayerToResurrectQueue(guid, _player->GetGUID()); +} + void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/) { if (_player->isInFlight()) return; + if(Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(_player->GetZoneId())) + { + // bf->PlayerAskToLeave(_player); FIXME + return; + } + AreaTableEntry const *atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2)) return; diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 235f349e1ea..9e7de1b5f7e 100755 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1273,15 +1273,15 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x4DD*/ { "UMSG_UNKNOWN_1245", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x4DE*/ { "SMSG_BATTLEFIELD_MGR_ENTRY_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, + /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse }, /*0x4E0*/ { "SMSG_BATTLEFIELD_MGR_ENTERED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x4E1*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, + /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfQueueInviteResponse }, /*0x4E3*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x4E4*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x4E5*/ { "SMSG_BATTLEFIELD_MGR_EJECT_PENDING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x4E6*/ { "SMSG_BATTLEFIELD_MGR_EJECTED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x4E7*/ { "CMSG_BATTLEFIELD_MGR_EXIT_REQUEST", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, + /*0x4E7*/ { "CMSG_BATTLEFIELD_MGR_EXIT_REQUEST", STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleBfExitRequest }, /*0x4E8*/ { "SMSG_BATTLEFIELD_MGR_STATE_CHANGE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x4E9*/ { "UMSG_UNKNOWN_1257", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x4EA*/ { "UMSG_UNKNOWN_1258", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index f45ee79847c..78fe186450e 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -785,6 +785,16 @@ class WorldSession void HandleHearthAndResurrect(WorldPacket& recv_data); void HandleInstanceLockResponse(WorldPacket& recvPacket); + // Battlefield + void SendBfInvitePlayerToWar(uint32 BattleId,uint32 ZoneId,uint32 time); + void SendBfInvitePlayerToQueue(uint32 BattleId); + void SendBfQueueInviteResponce(uint32 BattleId,uint32 ZoneId); + void SendBfEntered(uint32 BattleId); + void SendBfLeaveMessage(uint32 BattleId); + void HandleBfQueueInviteResponse(WorldPacket &recv_data); + void HandleBfEntryInviteResponse(WorldPacket &recv_data); + void HandleBfExitRequest(WorldPacket &recv_data); + // Looking for Dungeon/Raid void HandleLfgSetCommentOpcode(WorldPacket & recv_data); void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recv_data); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 27a34bb8740..5742620c3f3 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -35,6 +35,7 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "ScriptMgr.h" +#include "BattlefieldMgr.h" class Aura; // @@ -4815,8 +4816,12 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool case 2584: // Waiting to Resurrect // Waiting to resurrect spell cancel, we must remove player from resurrect queue if (target->GetTypeId() == TYPEID_PLAYER) - if (Battleground *bg = target->ToPlayer()->GetBattleground()) + { + if (Battleground* bg = target->ToPlayer()->GetBattleground()) bg->RemovePlayerFromResurrectQueue(target->GetGUID()); + if(Battlefield* bf = sBattlefieldMgr.GetBattlefieldToZoneId(target->GetZoneId())) + bf->RemovePlayerFromResurrectQueue(target->GetGUID()); + } break; case 36730: // Flame Strike { @@ -4853,6 +4858,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this); break; case 58600: // Restricted Flight Area + case 58730: // Restricted Flight Area if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) target->CastSpell(target, 58601, true); break; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 797a8ecfcbe..feb0686f05f 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -52,6 +52,7 @@ #include "DisableMgr.h" #include "SpellScript.h" #include "InstanceScript.h" +#include "BattlefieldMgr.h" extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -5472,8 +5473,9 @@ SpellCastResult Spell::CheckCast(bool strict) // allow always ghost flight spells if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive()) { + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldToZoneId(m_originalCaster->GetZoneId()); if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) - if (pArea->flags & AREA_FLAG_NO_FLY_ZONE) + if ((pArea->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn())) return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } break; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b9cd951d479..14c3975a018 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -6976,6 +6976,7 @@ void Spell::EffectPlayerNotification(SpellEffIndex effIndex) case 58730: // Restricted Flight Area case 58600: // Restricted Flight Area unitTarget->ToPlayer()->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); + unitTarget->PlayDirectSound(9417); // Fel Reaver sound break; } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index f1879099a0a..b519dad28c2 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -25,6 +25,7 @@ #include "Chat.h" #include "Spell.h" #include "BattlegroundMgr.h" +#include "BattlefieldMgr.h" #include "CreatureAI.h" #include "MapManager.h" #include "BattlegroundIC.h" @@ -3289,6 +3290,26 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 return false; break; } + case 58730: // No fly Zone - Wintergrasp + { + if (!player) + return false; + + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldToZoneId(player->GetZoneId()); + if (!Bf || Bf->CanFlyIn() || (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))) + return false; + break; + } + case 57940: // Essence of Wintergrasp - Northrend + { + if (!player) + return false; + + Battlefield* Bf = sBattlefieldMgr.GetBattlefieldToZoneId(4197); + if (!Bf || player->GetTeamId() != Bf->GetDefenderTeam()) + return false; + break; + } case SPELL_OIL_REFINERY: // Oil Refinery - Isle of Conquest. case SPELL_QUARRY: // Quarry - Isle of Conquest. { diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 15cc7c9abaf..186d0cdc381 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -50,6 +50,7 @@ #include "MapManager.h" #include "CreatureAIRegistry.h" #include "BattlegroundMgr.h" +#include "BattlefieldMgr.h" #include "OutdoorPvPMgr.h" #include "TemporarySummon.h" #include "WaypointMovementGenerator.h" @@ -1184,6 +1185,15 @@ void World::LoadConfigSettings(bool reload) // MySQL ping time interval m_int_configs[CONFIG_DB_PING_INTERVAL] = sConfig->GetIntDefault("MaxPingTime", 30); + // Wintergrasp + m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = sConfig->GetBoolDefault("Wintergrasp.Enable", false); + m_int_configs[CONFIG_WINTERGRASP_PLR_MAX] = sConfig->GetIntDefault("Wintergrasp.PlayerMax", 100); + m_int_configs[CONFIG_WINTERGRASP_PLR_MIN] = sConfig->GetIntDefault("Wintergrasp.PlayerMin", 0); + m_int_configs[CONFIG_WINTERGRASP_PLR_MIN_LVL] = sConfig->GetIntDefault("Wintergrasp.PlayerMinLvl", 77); + m_int_configs[CONFIG_WINTERGRASP_BATTLETIME] = sConfig->GetIntDefault("Wintergrasp.BattleTimer", 30); + m_int_configs[CONFIG_WINTERGRASP_NOBATTLETIME] = sConfig->GetIntDefault("Wintergrasp.NoBattleTimer", 150); + m_int_configs[CONFIG_WINTERGRASP_RESTART_AFTER_CRASH] = sConfig->GetIntDefault("Wintergrasp.CrashRestartTimer", 10); + sScriptMgr->OnConfigLoad(reload); } @@ -1698,6 +1708,10 @@ void World::SetInitialWorldSettings() sLog->outString("Starting Outdoor PvP System"); sOutdoorPvPMgr->InitOutdoorPvP(); + ///- Initialize Battlefield + sLog->outString("Starting Battlefield System"); + sBattlefieldMgr.InitBattlefield(); + sLog->outString("Loading Transports..."); sMapMgr->LoadTransports(); @@ -1948,6 +1962,9 @@ void World::Update(uint32 diff) sOutdoorPvPMgr->Update(diff); RecordTimeDiff("UpdateOutdoorPvPMgr"); + sBattlefieldMgr.Update(diff); + RecordTimeDiff("BattlefieldMgr"); + ///- Delete all characters which have been deleted X days before if (m_timers[WUPDATE_DELETECHARS].Passed()) { diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 1f3cd3ccd99..9a2f7df3c9e 100755 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -158,6 +158,7 @@ enum WorldBoolConfigs CONFIG_ALLOW_TICKETS, CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES, CONFIG_PRESERVE_CUSTOM_CHANNELS, + CONFIG_WINTERGRASP_ENABLE, BOOL_CONFIG_VALUE_COUNT }; @@ -306,6 +307,12 @@ enum WorldIntConfigs CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION, CONFIG_PERSISTENT_CHARACTER_CLEAN_FLAGS, CONFIG_MAX_INSTANCES_PER_HOUR, + CONFIG_WINTERGRASP_PLR_MAX, + CONFIG_WINTERGRASP_PLR_MIN, + CONFIG_WINTERGRASP_PLR_MIN_LVL, + CONFIG_WINTERGRASP_BATTLETIME, + CONFIG_WINTERGRASP_NOBATTLETIME, + CONFIG_WINTERGRASP_RESTART_AFTER_CRASH, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index de660b8f106..9e384502ee9 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -82,6 +82,9 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI ${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse + ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield + + ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield/Zones ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds/Zones ${CMAKE_SOURCE_DIR}/src/server/game/Calendar diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index 809e78204f4..bf86ada75f9 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -12,6 +12,7 @@ set(scripts_STAT_SRCS ${scripts_STAT_SRCS} Commands/cs_account.cpp Commands/cs_achievement.cpp + Commands/cs_bf.cpp Commands/cs_gm.cpp Commands/cs_npc.cpp Commands/cs_go.cpp diff --git a/src/server/scripts/Commands/cs_bf.cpp b/src/server/scripts/Commands/cs_bf.cpp new file mode 100644 index 00000000000..76e6665f0b4 --- /dev/null +++ b/src/server/scripts/Commands/cs_bf.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* ScriptData +Name: bf_commandscript +%Complete: 100 +Comment: All bf related commands +Category: commandscripts +EndScriptData */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "BattlefieldMgr.h" + +class bf_commandscript : public CommandScript +{ +public: + bf_commandscript() : CommandScript("bf_commandscript") { } + + ChatCommand* GetCommands() const + { + static ChatCommand battlefieldcommandTable[] = + { + { "start", SEC_ADMINISTRATOR, false, &HandleBattlefieldStart, "", NULL }, + { "stop", SEC_ADMINISTRATOR, false, &HandleBattlefieldEnd, "", NULL }, + { "switch", SEC_ADMINISTRATOR, false, &HandleBattlefieldSwitch, "", NULL }, + { "timer", SEC_ADMINISTRATOR, false, &HandleBattlefieldTimer, "", NULL }, + { "enable", SEC_ADMINISTRATOR, false, &HandleBattlefieldEnable, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand commandTable[] = + { + { "bf", SEC_ADMINISTRATOR, false, NULL, "", battlefieldcommandTable }, + { NULL, 0, false, NULL, "", NULL } + }; + return commandTable; + } + + static bool HandleBattlefieldStart(ChatHandler* handler, const char* args) + { + uint32 battleid = 0; + char* battleid_str = strtok((char*)args, " "); + if (!battleid_str) + return false; + + battleid = atoi(battleid_str); + + Battlefield* bf = sBattlefieldMgr.GetBattlefieldByBattleId(battleid); + + if (!bf) + return false; + + bf->StartBattle(); + + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp (Command start used)"); + + return true; + } + + static bool HandleBattlefieldEnd(ChatHandler* handler, const char* args) + { + uint32 battleid = 0; + char* battleid_str = strtok((char*)args, " "); + if (!battleid_str) + return false; + + battleid = atoi(battleid_str); + + Battlefield* bf = sBattlefieldMgr.GetBattlefieldByBattleId(battleid); + + if (!bf) + return false; + + bf->EndBattle(true); + + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp (Command stop used)"); + + return true; + } + + static bool HandleBattlefieldEnable(ChatHandler* handler, const char* args) + { + uint32 battleid = 0; + char* battleid_str = strtok((char*)args, " "); + if (!battleid_str) + return false; + + battleid = atoi(battleid_str); + + Battlefield* bf = sBattlefieldMgr.GetBattlefieldByBattleId(battleid); + + if (!bf) + return false; + + if (bf->GetEnable()) + { + bf->SetEnable(false); + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp is disabled"); + } + else + { + bf->SetEnable(true); + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp is enabled"); + } + + return true; + } + + static bool HandleBattlefieldSwitch(ChatHandler* handler, const char* args) + { + uint32 battleid = 0; + char* battleid_str = strtok((char*)args, " "); + if (!battleid_str) + return false; + + battleid = atoi(battleid_str); + + Battlefield* bf = sBattlefieldMgr.GetBattlefieldByBattleId(battleid); + + if (!bf) + return false; + + bf->EndBattle(false); + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp (Command switch used)"); + + return true; + } + + static bool HandleBattlefieldTimer(ChatHandler* handler, const char* args) + { + uint32 battleid = 0; + uint32 time = 0; + char* battleid_str = strtok((char*)args, " "); + if (!battleid_str) + return false; + char* time_str = strtok(NULL, " "); + if (!time_str) + return false; + + battleid = atoi(battleid_str); + + time = atoi(time_str); + + Battlefield* bf = sBattlefieldMgr.GetBattlefieldByBattleId(battleid); + + if (!bf) + return false; + + bf->SetTimer(time * IN_MILLISECONDS); + bf->SendInitWorldStatesToAll(); + if (battleid == 1) + handler->SendGlobalGMSysMessage("Wintergrasp (Command timer used)"); + + return true; + } +}; + +void AddSC_bf_commandscript() +{ + new bf_commandscript(); +} diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 3e1f500ebce..14924d89c96 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -174,6 +174,7 @@ set(scripts_STAT_SRCS Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp Northrend/IcecrownCitadel/boss_sindragosa.cpp Northrend/zuldrak.cpp + Northrend/wintergrasp.cpp Northrend/icecrown.cpp Northrend/Gundrak/boss_slad_ran.cpp Northrend/Gundrak/instance_gundrak.cpp diff --git a/src/server/scripts/Northrend/wintergrasp.cpp b/src/server/scripts/Northrend/wintergrasp.cpp new file mode 100644 index 00000000000..10a6716d3f2 --- /dev/null +++ b/src/server/scripts/Northrend/wintergrasp.cpp @@ -0,0 +1,418 @@ +/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptPCH.h" +#include "BattlefieldMgr.h" +#include "BattlefieldWG.h" +#include "Battlefield.h" +#include "ScriptSystem.h" +#include "WorldSession.h" +#include "ObjectMgr.h" + +#define GOSSIP_HELLO_DEMO1 "Build catapult." +#define GOSSIP_HELLO_DEMO2 "Build demolisher." +#define GOSSIP_HELLO_DEMO3 "Build siege engine." +#define GOSSIP_HELLO_DEMO4 "I cannot build more!" + +enum eWGqueuenpctext +{ + WG_NPCQUEUE_TEXT_H_NOWAR = 14775, + WG_NPCQUEUE_TEXT_H_QUEUE = 14790, + WG_NPCQUEUE_TEXT_H_WAR = 14777, + WG_NPCQUEUE_TEXT_A_NOWAR = 14782, + WG_NPCQUEUE_TEXT_A_QUEUE = 14791, + WG_NPCQUEUE_TEXT_A_WAR = 14781, + WG_NPCQUEUE_TEXTOPTION_JOIN = -1850507, +}; + +class npc_demolisher_engineerer : public CreatureScript +{ + public: + npc_demolisher_engineerer() : CreatureScript("npc_demolisher_engineerer") + { + } + + bool OnGossipHello(Player * pPlayer, Creature * pCreature) + { + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(1); + + if (!BfWG) + return true; + + if (BfWG->GetData(pCreature->GetEntry() == 30400 ? BATTLEFIELD_WG_DATA_MAX_VEHICLE_H : BATTLEFIELD_WG_DATA_MAX_VEHICLE_A) > + BfWG->GetData(pCreature->GetEntry() == 30400 ? BATTLEFIELD_WG_DATA_VEHICLE_H : BATTLEFIELD_WG_DATA_VEHICLE_A)) + { + if (pPlayer->HasAura(SPELL_CORPORAL)) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + else if (pPlayer->HasAura(SPELL_LIEUTENANT)) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + } + } + else + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO_DEMO4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; + } + + bool OnGossipSelect(Player * pPlayer, Creature * pCreature, uint32 /*uiSender */ , uint32 uiAction) + { + pPlayer->CLOSE_GOSSIP_MENU(); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(1); + + if (!BfWG) + return true; + + if (BfWG->GetData(pCreature->GetEntry() == 30400 ? BATTLEFIELD_WG_DATA_MAX_VEHICLE_H : BATTLEFIELD_WG_DATA_MAX_VEHICLE_A) > + BfWG->GetData(pCreature->GetEntry() == 30400 ? BATTLEFIELD_WG_DATA_VEHICLE_H : BATTLEFIELD_WG_DATA_VEHICLE_A)) + { + switch (uiAction - GOSSIP_ACTION_INFO_DEF) + { + case 0: + pPlayer->CastSpell(pPlayer, 56663, false, NULL, NULL, pCreature->GetGUID()); + break; + case 1: + pPlayer->CastSpell(pPlayer, 56575, false, NULL, NULL, pCreature->GetGUID()); + break; + case 2: + pPlayer->CastSpell(pPlayer, pPlayer->GetTeamId()? 61408 : 56661, false, NULL, NULL, pCreature->GetGUID()); + break; + } + //spell 49899 Emote : 406 from sniff + //INSERT INTO `spell_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES ('49899', '0', '1', '406', '0', '0', '0', '0', '0', '0'); + if (Creature * creature = pCreature->FindNearestCreature(27852, 30.0f, true)) + creature->CastSpell(creature, 49899, true); + } + return true; + } +}; + +class npc_wg_spiritguide : public CreatureScript +{ + public: + npc_wg_spiritguide() : CreatureScript("npc_wg_spiritguide") + { + } + + bool OnGossipHello(Player * pPlayer, Creature * pCreature) + { + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (BfWG) + { + GraveYardVect gy = BfWG->GetGraveYardVect(); + for (uint8 i = 0; i < gy.size(); i++) + { + if (gy[i]->GetControlTeamId() == pPlayer->GetTeamId()) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, sObjectMgr->GetTrinityStringForDBCLocale(((BfGraveYardWG *) gy[i])->GetTextId()), GOSSIP_SENDER_MAIN, + GOSSIP_ACTION_INFO_DEF + i); + } + } + } + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; + } + + bool OnGossipSelect(Player * pPlayer, Creature * /*pCreature */ , uint32 /*uiSender */ , uint32 uiAction) + { + pPlayer->CLOSE_GOSSIP_MENU(); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (BfWG) + { + GraveYardVect gy = BfWG->GetGraveYardVect(); + for (uint8 i = 0; i < gy.size(); i++) + { + if (uiAction - GOSSIP_ACTION_INFO_DEF == i && gy[i]->GetControlTeamId() == pPlayer->GetTeamId()) + { + const WorldSafeLocsEntry *ws = sWorldSafeLocsStore.LookupEntry(gy[i]->GetGraveYardId()); + pPlayer->TeleportTo(ws->map_id, ws->x, ws->y, ws->z, 0); + } + } + } + return true; + } +}; + +class npc_wg_dalaran_queue : public CreatureScript +{ + public: + npc_wg_dalaran_queue() : CreatureScript("npc_wg_dalaran_queue") + { + } + + bool OnGossipHello(Player * pPlayer, Creature * pCreature) + { + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (BfWG) + { + + if (BfWG->IsWarTime()) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, sObjectMgr->GetTrinityStringForDBCLocale(WG_NPCQUEUE_TEXTOPTION_JOIN), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->SEND_GOSSIP_MENU(BfWG->GetDefenderTeam()? WG_NPCQUEUE_TEXT_H_WAR : WG_NPCQUEUE_TEXT_A_WAR, pCreature->GetGUID()); + } + else + { + uint32 uiTime = BfWG->GetTimer() / 1000; + pPlayer->SendUpdateWorldState(4354, time(NULL) + uiTime); + if (uiTime < 15 * MINUTE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, sObjectMgr->GetTrinityStringForDBCLocale(WG_NPCQUEUE_TEXTOPTION_JOIN), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->SEND_GOSSIP_MENU(BfWG->GetDefenderTeam()? WG_NPCQUEUE_TEXT_H_QUEUE : WG_NPCQUEUE_TEXT_A_QUEUE, pCreature->GetGUID()); + } + else + { + pPlayer->SEND_GOSSIP_MENU(BfWG->GetDefenderTeam()? WG_NPCQUEUE_TEXT_H_NOWAR : WG_NPCQUEUE_TEXT_A_NOWAR, pCreature->GetGUID()); + } + } + } + return true; + } + + bool OnGossipSelect(Player * pPlayer, Creature * /*pCreature */ , uint32 /*uiSender */ , uint32 /*uiAction */ ) + { + pPlayer->CLOSE_GOSSIP_MENU(); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (BfWG) + { + if (BfWG->IsWarTime()) + { + BfWG->InvitePlayerToWar(pPlayer); + } + else + { + uint32 uiTime = BfWG->GetTimer() / 1000; + if (uiTime < 15 * MINUTE) + BfWG->InvitePlayerToQueue(pPlayer); + } + } + return true; + } +}; + +const uint32 Vehicules[4] = { 32627, 28312, 28094, 27881 }; + +#define SPELL_VEHICLE_TELEPORT 49759 + +class go_wintergrasp_teleporter : public GameObjectScript +{ + public: + go_wintergrasp_teleporter() : GameObjectScript("go_wintergrasp_teleporter") + { + } + + struct go_wintergrasp_teleporterAI : public GameObjectAI + { + go_wintergrasp_teleporterAI(GameObject * g) : GameObjectAI(g) + { + uiCheckTimer = 1000; + } + + void UpdateAI(const uint32 diff) + { + if (uiCheckTimer <= diff) + { + for (uint8 i = 0; i < 4; i++) + if (Creature * pVehicle = go->FindNearestCreature(Vehicules[i], 3.0f, true)) + if (!pVehicle->HasAura(SPELL_VEHICLE_TELEPORT)) + { + if (pVehicle->GetVehicle()) + { + if (Unit * player = pVehicle->GetVehicle()->GetPassenger(0)) + { + uint32 gofaction = go->GetUInt32Value(GAMEOBJECT_FACTION); + uint32 plfaction = player->getFaction(); + if (gofaction == plfaction) + { + pVehicle->CastSpell(pVehicle, SPELL_VEHICLE_TELEPORT, true); + if (Creature * TargetTeleport = pVehicle->FindNearestCreature(23472, 100.0f, true)) + { + float x, y, z, o; + TargetTeleport->GetPosition(x, y, z, o); + pVehicle->GetVehicle()->TeleportVehicle(x, y, z, o); + } + } + } + } + } + uiCheckTimer = 1000; + } + else + uiCheckTimer -= diff; + } + private: + uint32 uiCheckTimer; + }; + + GameObjectAI *GetAI(GameObject * go) const + { + return new go_wintergrasp_teleporterAI(go); + } +}; + +class npc_wintergrasp_quest_giver : public CreatureScript +{ + public: + npc_wintergrasp_quest_giver() : CreatureScript("npc_wintergrasp_quest_giver") + { + } + + bool OnGossipHello(Player * pPlayer, Creature * pCreature) + { + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + BattlefieldWG *BfWG = (BattlefieldWG *) sBattlefieldMgr.GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); + if (BfWG) + { + if (pCreature->isQuestGiver()) + { + Object* pObject = (Object *) pCreature; + QuestRelations* pObjectQR = sObjectMgr->GetCreatureQuestRelationMap(); + QuestRelations* pObjectQIR = sObjectMgr->GetCreatureQuestInvolvedRelation(); + + QuestMenu & qm = pPlayer->PlayerTalkClass->GetQuestMenu(); + qm.ClearMenu(); + + for (QuestRelations::const_iterator i = pObjectQIR->lower_bound(pObject->GetEntry()); i != pObjectQIR->upper_bound(pObject->GetEntry()); ++i) + { + uint32 quest_id = i->second; + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + if (status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_INCOMPLETE) + qm.AddMenuItem(quest_id, 4); + } + + for (QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i) + { + uint32 quest_id = i->second; + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id); + if (!pQuest) + continue; + + switch (quest_id) + { + // Horde attacker + case 13193: + case 13202: + case 13180: + case 13200: + case 13201: + case 13223: + if (BfWG->GetAttackerTeam() == TEAM_HORDE) + { + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + + if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_NONE && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 2); + } + break; + // Horde defender + case 13199: + case 13192: + case 13178: + case 13191: + case 13194: + case 13539: + case 13185: + if (BfWG->GetDefenderTeam() == TEAM_HORDE) + { + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + + if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_NONE && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 2); + } + break; + // Alliance attacker + case 13196: + case 13198: + case 13179: + case 13222: + case 13195: + if (BfWG->GetAttackerTeam() == TEAM_ALLIANCE) + { + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + + if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_NONE && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 2); + } + break; + // Alliance defender + case 13154: + case 13153: + case 13177: + case 13538: + case 13186: + case 13156: + if (BfWG->GetDefenderTeam() == TEAM_ALLIANCE) + { + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + + if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_NONE && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 2); + } + break; + default: + QuestStatus status = pPlayer->GetQuestStatus(quest_id); + + if (pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 4); + else if (status == QUEST_STATUS_NONE && pPlayer->CanTakeQuest(pQuest, false)) + qm.AddMenuItem(quest_id, 2); + break; + } + } + } + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID()); + return true; + } + return true; + } +}; + +void AddSC_wintergrasp() +{ + new npc_wg_dalaran_queue(); + new npc_wg_spiritguide(); + new npc_demolisher_engineerer(); + new go_wintergrasp_teleporter(); + new npc_wintergrasp_quest_giver(); +} diff --git a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h b/src/server/scripts/PrecompiledHeaders/ScriptPCH.h index 1cd25309055..e73771b49e5 100644 --- a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h +++ b/src/server/scripts/PrecompiledHeaders/ScriptPCH.h @@ -18,6 +18,7 @@ #include "InstanceScript.h" #include "CombatAI.h" #include "PassiveAI.h" +#include "GameObjectAI.h" #include "Chat.h" #include "DBCStructure.h" #include "DBCStores.h" diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 94e0491229b..9d2035a6c5c 100755 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -50,6 +50,7 @@ enum DebugLogFilters LOG_FILTER_LOOT = 0x00100000, // Loot related LOG_FILTER_GUILD = 0x00200000, // Guild related LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related + LOG_FILTER_BATTLEFIELD = 0x00800000, // Battlefield related }; enum LogTypes diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index eb1e33626c6..229f159fb59 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1388,6 +1388,57 @@ AllowTickets = 1 DungeonFinder.Enable = 0 # +# Wintergrasp.Enable +# Description: Enable the Wintergrasp battlefield. +# Default: 0 - (Disabled) +# 1 - (Enabled, Experimental as of still being in development) + +Wintergrasp.Enable = 0 + +# +# Wintergrasp.PlayerMax +# Description: Maximum number of players allowed in Wintergrasp. +# Default: 100 + +Wintergrasp.PlayerMax = 100 + +# +# Wintergrasp.PlayerMin +# Description: Minimum number of players required for Wintergrasp. +# Default: 0 + +Wintergrasp.PlayerMin = 0 + +# +# Wintergrasp.PlayerMinLvl +# Description: Required character level for the Wintergrasp battle. +# Default: 77 + +Wintergrasp.PlayerMinLvl = 77 + +# +# Wintergrasp.BattleTimer +# Description: Time (in minutes) for the Wintergrasp battle to last. +# Default: 30 + +Wintergrasp.BattleTimer = 30 + +# +# Wintergrasp.NoBattleTimer +# Description: Time (in minutes) between Wintergrasp battles. +# Default: 150 + +Wintergrasp.NoBattleTimer = 150 + +# +# Wintergrasp.CrashRestartTimer +# Description: Time (in minutes) to delay the restart of Wintergrasp if the world server +# crashed during a running battle. +# Default: 10 + +Wintergrasp.CrashRestartTimer = 10 + +# # DBC.EnforceItemAttributes # Description: Disallow overriding item attributes stored in DBC files with values from the # database. |