@@ -0,0 +1,3 @@
|
||||
-- DB update 2026_06_01_00 -> 2026_06_24_00
|
||||
ALTER TABLE `mail_server_template`
|
||||
ADD COLUMN `senderEntry` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Entry from creature_template. 0 for default "Customer Support" sender.' AFTER `id`;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- DB update 2026_06_18_03 -> 2026_06_20_00
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` = 64132;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (64132, 'spell_yogg_saron_constrictor_tentacle_aura');
|
||||
@@ -0,0 +1,57 @@
|
||||
-- DB update 2026_06_20_00 -> 2026_06_21_00
|
||||
|
||||
-- Set Extra Flag NO_MOVE_FLAGS_UPDATE.
|
||||
UPDATE `creature_template` SET `flags_extra` = `flags_extra` |512 WHERE (`entry` = 28465);
|
||||
|
||||
-- Remove Movement Flags.
|
||||
DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 28465);
|
||||
|
||||
-- Remove MT and waypoint ids.
|
||||
UPDATE `creature` SET `MovementType` = 0 WHERE (`id` = 28465) AND (`guid` IN (100536, 100540));
|
||||
UPDATE `creature_addon` SET `path_id` = 0 WHERE (`guid` IN (100536, 100540));
|
||||
|
||||
-- Move Heb Drakkar Striker paths on waypoints table.
|
||||
DELETE FROM `waypoint_data` WHERE (`id` IN (1005360, 1005400));
|
||||
DELETE FROM `waypoints` WHERE `entry` IN (10053600, 10054000);
|
||||
INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `point_comment`) VALUES
|
||||
(10053600, 1, 5997.71, -3803.25, 384.444, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 2, 5971.09, -3866.25, 390.999, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 3, 5896.79, -3922, 387, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 4, 5846.83, -3912.56, 378.944, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 5, 5803.36, -3868.98, 376.389, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 6, 5803.01, -3817.95, 376.055, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 7, 5839.45, -3767.71, 375.888, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 8, 5879.84, -3723.38, 375.222, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 9, 5906.52, -3689.99, 375.222, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 10, 5948.16, -3694.75, 375.222, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10053600, 11, 5986.21, -3743.16, 378.722, NULL, 'Heb Drakkar Striker 1'),
|
||||
(10054000, 1, 5921.5, -3765.99, 374.932, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 2, 5892.01, -3795.87, 373.182, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 3, 5894.13, -3870.95, 381.932, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 4, 5936.05, -3933.15, 399.932, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 5, 5992.46, -3987.92, 399.932, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 6, 6035.39, -3982.35, 382.682, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 7, 6084.95, -3923.61, 382.682, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 8, 6090.31, -3870.81, 401.877, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 9, 6015.04, -3792.97, 401.877, NULL, 'Heb Drakkar Striker 2'),
|
||||
(10054000, 10, 5975.41, -3758.67, 379.627, NULL, 'Heb Drakkar Striker 2');
|
||||
|
||||
-- Add Heb Drakkar Striker Specific GUID.
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (-100536, -100540));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(-100536, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Respawn - Set Disable Gravity On'),
|
||||
(-100536, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 53, 0, 10053600, 1, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Respawn - Start Patrol Path 10053600'),
|
||||
(-100536, 0, 2, 3, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Aggro - Set Disable Gravity Off'),
|
||||
(-100536, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Aggro - Dismount'),
|
||||
(-100536, 0, 4, 5, 7, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Evade - Set Disable Gravity On'),
|
||||
(-100536, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 43, 0, 9074, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Evade - Mount To Model 9074'),
|
||||
(-100536, 0, 6, 0, 0, 0, 100, 0, 5000, 5000, 16000, 16000, 0, 0, 11, 11976, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - In Combat - Cast \'Strike\''),
|
||||
(-100536, 0, 7, 0, 0, 0, 100, 0, 4000, 14000, 50000, 60000, 0, 0, 11, 51951, 32, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - In Combat - Cast \'Rabies\''),
|
||||
(-100540, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Respawn - Set Disable Gravity On'),
|
||||
(-100540, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 53, 0, 10054000, 1, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Respawn - Start Patrol Path 10054000'),
|
||||
(-100540, 0, 2, 3, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Aggro - Set Disable Gravity Off'),
|
||||
(-100540, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Aggro - Dismount'),
|
||||
(-100540, 0, 4, 5, 7, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Evade - Set Disable Gravity On'),
|
||||
(-100540, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 43, 0, 9074, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - On Evade - Mount To Model 9074'),
|
||||
(-100540, 0, 6, 0, 0, 0, 100, 0, 5000, 5000, 16000, 16000, 0, 0, 11, 11976, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - In Combat - Cast \'Strike\''),
|
||||
(-100540, 0, 7, 0, 0, 0, 100, 0, 4000, 14000, 50000, 60000, 0, 0, 11, 51951, 32, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Heb\'Drakkar Striker - In Combat - Cast \'Rabies\'');
|
||||
@@ -0,0 +1,105 @@
|
||||
-- DB update 2026_06_21_00 -> 2026_06_22_00
|
||||
|
||||
-- Add Spell Script Name.
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` = 51036;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(51036, 'spell_venture_pilot_summon');
|
||||
|
||||
-- Add new Sniffed Waypoints
|
||||
DELETE FROM `waypoints` WHERE `entry` IN (28192, 2819200, 2822900);
|
||||
INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `orientation`, `point_comment`) VALUES
|
||||
(2819200, 1, 5142.8774, 4676.631, 73.46826, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 2, 5199.205, 4727.144, 72.46811, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 3, 5264.4897, 4794.4497, 69.96814, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 4, 5309.7544, 4842.0576, 59.273388, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 5, 5339.674, 4877.8887, 46.18986, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 6, 5403.4263, 4944.932, 15.161798, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 7, 5455.6265, 5002.442, -3.115965, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 8, 5529.6377, 5085.854, -31.67146, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 9, 5599.5723, 5174.9565, -62.560642, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 10, 5622.023, 5202.6616, -68.72743, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2819200, 11, 5635.8755, 5225.5605, -75.11644, NULL, 'Archmage Pentarus Flying Machine'),
|
||||
(2822900, 1, 5508.8813, 4993.8525, -26.99996, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 2, 5527.892, 5024.44, -33.166454, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 3, 5555.9478, 5055.0166, -40.555496, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 4, 5573.23, 5081.3677, -46.416637, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 5, 5596.7915, 5120.5415, -60.861324, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 6, 5616.4214, 5169.3354, -73.94473, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 7, 5639.541, 5246.319, -82.02806, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 8, 5649.434, 5336.935, -80.611534, NULL, 'Venture Co. Pilot'),
|
||||
(2822900, 9, 5649.434, 5336.935, -80.611534, NULL, 'Venture Co. Pilot');
|
||||
|
||||
-- Set Sniffed walk and run speed (Archmage Pentarus' Flying Machine).
|
||||
UPDATE `creature_template` SET `speed_run` = 3.14, `speed_walk` = 6 WHERE `entry` = 28192;
|
||||
|
||||
-- Set Default Aura (Archmage Pentarus' Flying Machine).
|
||||
UPDATE `creature_template_addon` SET `auras` = '48602' WHERE (`entry` = 28192);
|
||||
|
||||
-- Edit SAI & Action List (Archmage Pentarus)
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28160;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28160);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28160, 0, 0, 0, 62, 0, 100, 512, 10024, 0, 0, 0, 0, 0, 80, 2816000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus - On Gossip Option 0 Selected - Run Script');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2816000);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(2816000, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus - Actionlist - Close Gossip'),
|
||||
(2816000, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 134, 50860, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus - Actionlist - Invoker Cast \'Flight to Sholazar\''),
|
||||
(2816000, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus - Actionlist - Say Line 0'),
|
||||
(2816000, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 190488, 19, 0, 0, 0, 0, 8, 0, 0, 0, 0, 5828.64, 427.118, 670.096, 0.820303, 'Archmage Pentarus - Actionlist - Summon Gameobject \'Pentarus\' Portal to Sholazar Basin\'');
|
||||
|
||||
-- Set SAI & Action Lists (Archmage Pentarus Flying Machine).
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28192;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28192);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28192, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 80, 2819200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Just Summoned - Run Script'),
|
||||
(28192, 0, 1, 0, 34, 0, 100, 0, 8, 22, 0, 0, 0, 0, 80, 2819201, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Reached Point 22 - Run Script'),
|
||||
(28192, 0, 2, 0, 58, 0, 100, 0, 0, 2819200, 0, 0, 0, 0, 80, 2819202, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Path 2819200 Finished - Run Script'),
|
||||
(28192, 0, 3, 4, 34, 0, 100, 0, 8, 23, 0, 0, 0, 0, 223, 24, 0, 0, 0, 0, 0, 10, 103289, 27987, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Reached Point 23 - Do Action ID 24'),
|
||||
(28192, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 53119, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Reached Point 23 - Cast \'Cosmetic Flame Dart\''),
|
||||
(28192, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - On Reached Point 23 - Despawn Instant');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (2819200, 2819201, 2819202));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(2819200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51076, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Cast \'Flight to Sholazar (Trigger Warning)\''),
|
||||
(2819200, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 134, 46598, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Invoker Cast \'Ride Vehicle Hardcoded\''),
|
||||
(2819200, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Set Fly On'),
|
||||
(2819200, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 75, 51038, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Add Aura \'Flight to Sholazar Periodic\''),
|
||||
(2819200, 9, 4, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 69, 22, 0, 1, 0, 0, 0, 8, 0, 0, 0, 0, 5828.73, 428.093, 669.899, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Move To Position'),
|
||||
(2819201, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 50987, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Cast \'Teleport to Sholazar\''),
|
||||
(2819201, 9, 1, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 53, 0, 2819200, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Start Waypoint Path 2819200'),
|
||||
(2819202, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 53119, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Cast \'Cosmetic Flame Dart\''),
|
||||
(2819202, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 75, 61360, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Add Aura \'Parachute\''),
|
||||
(2819202, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 50630, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Cast \'Eject All Passengers\''),
|
||||
(2819202, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 69, 23, 0, 1, 0, 0, 0, 8, 0, 0, 0, 0, 5637.41, 5301.54, -109.587, 0, 'Archmage Pentarus\' Flying Machine - Actionlist - Move To Position');
|
||||
|
||||
-- Set SAI & Action List Venture Co. Pilot
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28229;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28229);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28229, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 80, 2822900, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - On Just Summoned - Run Script');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 2822900);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(2822900, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Set Reactstate Passive'),
|
||||
(2822900, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Set Fly On'),
|
||||
(2822900, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 48602, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Cast \'Flight\''),
|
||||
(2822900, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51044, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Cast \'Venture Co. Air Patrol Rockets\''),
|
||||
(2822900, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 51043, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Cast \'Venture Co. Air Patrol Periodic (Kill Shot)\''),
|
||||
(2822900, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 53, 0, 2822900, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Start Waypoint Path 2822900'),
|
||||
(2822900, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Say Line 0'),
|
||||
(2822900, 9, 7, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 'Venture Co. Pilot - Actionlist - Say Line 0');
|
||||
|
||||
-- Edit SAI (Monte Muzzleshot).
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 27987;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27987);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(27987, 0, 0, 0, 25, 0, 100, 512, 0, 0, 0, 0, 0, 0, 60, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Monte Muzzleshot - On Reset - Set Fly On'),
|
||||
(27987, 0, 1, 0, 72, 0, 100, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Monte Muzzleshot - On Action 24 Done - Say Line 0');
|
||||
|
||||
-- Delete unecessary Action List (Monte Muzzleshot).
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2798700) AND (`source_type` = 9);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- DB update 2026_06_22_00 -> 2026_06_25_00
|
||||
-- Riding Jokkum cast is now handled by spell_q13010_jokkum_summon
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 30331) AND (`source_type` = 0) AND (`id` IN (5));
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_q13010_jokkum_summon';
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_riding_jokkum';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(56541, 'spell_q13010_jokkum_summon'),
|
||||
(56606, 'spell_riding_jokkum');
|
||||
@@ -0,0 +1,24 @@
|
||||
-- DB update 2026_06_25_00 -> 2026_06_26_00
|
||||
-- PrevQuestID 11239 to 11231, make Of Keys and Cages the prerequisite, not In Service to the Light
|
||||
UPDATE `quest_template_addon` SET `PrevQuestID` = 11231 WHERE (`ID` = 11432);
|
||||
|
||||
-- Add Mage-Lieutenant Malister's text
|
||||
DELETE FROM `creature_text` WHERE (`CreatureID` = 23888) AND (`GroupID` = 0) AND (`ID` = 0);
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(23888, 0, 0, '$n, I would have words with you.', 15, 0, 100, 0, 0, 0, 23634, 0, 'Mage-Lieutenant Malister - Quest 11231');
|
||||
|
||||
-- Father Levariol - Store player who completes Of Keys and Cages and send to Mage-Lieutenant Malister
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 24038;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24038);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(24038, 0, 1, 2, 20, 0, 100, 0, 11231, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Father Levariol - Store player who completes Of Keys and Cages - Quest 11231'),
|
||||
(24038, 0, 2, 3, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 1, 0, 0, 0, 0, 0, 19, 23888, 0, 0, 0, 0, 0, 0, 0, 'Father Levariol - Send stored target to Mage-Lieutenant Malister - Quest 11231'),
|
||||
(24038, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 19, 23888, 0, 0, 0, 0, 0, 0, 0, 'Father Levariol - DO_ACTION to Mage-Lieutenant Malister - Quest 11231');
|
||||
|
||||
-- Mage-Lieutenant Malister - On SET_DATA, whisper to stored target
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 23888;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 23888) AND (`source_type` = 0) AND (`id` IN (0));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(23888, 0, 0, 0, 72, 0, 100, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 0, 'Mage-Lieutenant Malister - On ACTION_DONE whisper to stored target - Quest 11231');
|
||||
+1
-1
@@ -65,7 +65,7 @@ enum AccountTypes
|
||||
enum AccountFlag
|
||||
{
|
||||
ACCOUNT_FLAG_GM = 0x1, // Account is GM
|
||||
ACCOUNT_FLAG_NOKICK = 0x2, // NYI UNK
|
||||
ACCOUNT_FLAG_NOKICK = 0x2, // Will not be logged out while AFK
|
||||
ACCOUNT_FLAG_COLLECTOR = 0x4, // NYI Collector's Edition
|
||||
ACCOUNT_FLAG_TRIAL = 0x8, // Trial account
|
||||
ACCOUNT_FLAG_CANCELLED = 0x10, // NYI UNK
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "Log.h"
|
||||
#include "World.h"
|
||||
#include "soapStub.h"
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
void ACSoapThread(const std::string& host, uint16 port)
|
||||
{
|
||||
@@ -33,10 +35,15 @@ void ACSoapThread(const std::string& host, uint16 port)
|
||||
soap.recv_timeout = 5;
|
||||
soap.send_timeout = 5;
|
||||
|
||||
// allow rebinding while the previous socket is still in TIME_WAIT (e.g. on a quick restart)
|
||||
soap.bind_flags = SO_REUSEADDR;
|
||||
|
||||
if (!soap_valid_socket(soap_bind(&soap, host.c_str(), port, 100)))
|
||||
{
|
||||
LOG_ERROR("network.soap", "ACSoap: couldn't bind to {}:{}", host, port);
|
||||
exit(-1);
|
||||
// graceful shutdown: exit() here would destroy SocketMgr before StopNetwork() and assert
|
||||
World::StopNow(ERROR_EXIT_CODE);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("network.soap", "ACSoap: bound to http://{}:{}", host, port);
|
||||
@@ -103,21 +110,28 @@ int ns1__executeCommand(soap* soap, char* command, char** result)
|
||||
return soap_sender_fault(soap, "Command can not be empty", "The supplied command was an empty string");
|
||||
|
||||
LOG_DEBUG("network.soap", "ACSoap: got command '{}'", command);
|
||||
SOAPCommand connection;
|
||||
|
||||
// Shared so the object survives if we stop waiting below: the queued command keeps a raw
|
||||
// pointer to it and the world thread may still run it after that. The extra reference is
|
||||
// released by commandFinished() once the world side is done with it.
|
||||
auto connection = std::make_shared<SOAPCommand>();
|
||||
connection->m_self = connection;
|
||||
|
||||
// commands are executed in the world thread. We have to wait for them to be completed
|
||||
sWorld->QueueCliCommand(new CliCommandHolder(connection.get(), command, &SOAPCommand::print, &SOAPCommand::commandFinished));
|
||||
|
||||
// Wait for the command to finish, but bail on shutdown: ProcessCliCommands() (which fulfils
|
||||
// the promise) stops once the world loop exits, so an unbounded wait here would deadlock.
|
||||
std::future<void> finished = connection->finishedPromise.get_future();
|
||||
while (finished.wait_for(std::chrono::seconds(1)) != std::future_status::ready)
|
||||
{
|
||||
// CliCommandHolder will be deleted from world, accessing after queueing is NOT save
|
||||
CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished);
|
||||
sWorld->QueueCliCommand(cmd);
|
||||
if (World::IsStopped())
|
||||
return soap_receiver_fault(soap, "Server is shutting down", "Command aborted: the server is shutting down");
|
||||
}
|
||||
|
||||
// Wait until the command has finished executing
|
||||
connection.finishedPromise.get_future().wait();
|
||||
|
||||
// The command has finished executing already
|
||||
char* printBuffer = soap_strdup(soap, connection.m_printBuffer.c_str());
|
||||
if (connection.hasCommandSucceeded())
|
||||
char* printBuffer = soap_strdup(soap, connection->m_printBuffer.c_str());
|
||||
if (connection->hasCommandSucceeded())
|
||||
{
|
||||
*result = printBuffer;
|
||||
return SOAP_OK;
|
||||
@@ -130,6 +144,8 @@ void SOAPCommand::commandFinished(void* soapconnection, bool success)
|
||||
{
|
||||
SOAPCommand* con = (SOAPCommand*)soapconnection;
|
||||
con->setCommandSuccess(success);
|
||||
// world side is done with us; drop the keep-alive (may free the object)
|
||||
con->m_self.reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
void process_message(struct soap* soap_message);
|
||||
void ACSoapThread(const std::string& host, uint16 port);
|
||||
@@ -58,6 +59,8 @@ public:
|
||||
bool m_success;
|
||||
std::string m_printBuffer;
|
||||
std::promise<void> finishedPromise;
|
||||
// keep-alive while a queued command still references this object; released in commandFinished()
|
||||
std::shared_ptr<SOAPCommand> m_self;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4528,7 +4528,6 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_RECEIVE_HEAL:
|
||||
case SMART_EVENT_DAMAGED:
|
||||
case SMART_EVENT_DAMAGED_TARGET:
|
||||
{
|
||||
if (var0 > e.event.minMaxRepeat.max || var0 < e.event.minMaxRepeat.min)
|
||||
@@ -4537,6 +4536,25 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
ProcessAction(e, unit);
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_DAMAGED:
|
||||
{
|
||||
if (e.event.minMaxRepeat.rangeMin) // health check mode
|
||||
{
|
||||
if (!me || !me->IsEngaged() || !me->GetMaxHealth())
|
||||
return;
|
||||
if (!me->HealthBelowPctDamaged(e.event.minMaxRepeat.rangeMin, var0))
|
||||
return;
|
||||
ProcessAction(e, unit);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (var0 > e.event.minMaxRepeat.max || var0 < e.event.minMaxRepeat.min)
|
||||
return;
|
||||
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
ProcessAction(e, unit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_MOVEMENTINFORM:
|
||||
{
|
||||
if ((e.event.movementInform.type && var0 != e.event.movementInform.type) || (e.event.movementInform.id && var1 != e.event.movementInform.id))
|
||||
|
||||
@@ -282,6 +282,12 @@ void SmartAIMgr::LoadSmartAIFromDB()
|
||||
if (temp.event.minMaxRepeat.repeatMin == 0 && temp.event.minMaxRepeat.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_DAMAGED:
|
||||
// health check mode stays below the threshold on every following hit, so force one-shot;
|
||||
// normal mode keeps repeatMin/repeatMax as a cooldown (0 = fire on every hit), so leave it repeatable.
|
||||
if (temp.event.minMaxRepeat.rangeMin)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_VICTIM_CASTING:
|
||||
case SMART_EVENT_FRIENDLY_IS_CC:
|
||||
if (temp.event.friendlyCC.repeatMin == 0 && temp.event.friendlyCC.repeatMax == 0)
|
||||
@@ -1075,7 +1081,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_EVENT_MANA_PCT:
|
||||
case SMART_EVENT_TARGET_HEALTH_PCT:
|
||||
case SMART_EVENT_TARGET_MANA_PCT:
|
||||
case SMART_EVENT_DAMAGED:
|
||||
case SMART_EVENT_DAMAGED_TARGET:
|
||||
case SMART_EVENT_RECEIVE_HEAL:
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
|
||||
@@ -1084,6 +1089,25 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_DAMAGED:
|
||||
if (e.event.minMaxRepeat.rangeMin) // health check mode
|
||||
{
|
||||
if (e.event.minMaxRepeat.rangeMin > 100)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid health pct value ({}), must be between 1 and 100, skipped.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.minMaxRepeat.rangeMin);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // normal mode
|
||||
{
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
|
||||
@@ -128,7 +128,7 @@ enum SMART_EVENT
|
||||
SMART_EVENT_CHARMED = 29, // onRemove (0 - on apply, 1 - on remove)
|
||||
SMART_EVENT_CHARMED_TARGET = 30, // NONE
|
||||
SMART_EVENT_SPELLHIT_TARGET = 31, // SpellID, School, CooldownMin, CooldownMax
|
||||
SMART_EVENT_DAMAGED = 32, // MinDmg, MaxDmg, CooldownMin, CooldownMax
|
||||
SMART_EVENT_DAMAGED = 32, // MinDmg, MaxDmg, CooldownMin, CooldownMax, rangeMin (hpPct, if set: health check mode, one-shot)
|
||||
SMART_EVENT_DAMAGED_TARGET = 33, // MinDmg, MaxDmg, CooldownMin, CooldownMax
|
||||
SMART_EVENT_MOVEMENTINFORM = 34, // MovementType(any), PointID, PathId(0 - any)
|
||||
SMART_EVENT_SUMMON_DESPAWNED = 35, // Entry, CooldownMin, CooldownMax
|
||||
|
||||
@@ -264,7 +264,7 @@ Creature::Creature(): Unit(), MovableMapObject(), m_groupLootTimer(0), lootingGr
|
||||
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_alreadyCallForHelp(false), m_AlreadyCallAssistance(false),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), _gossipMenuId(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
|
||||
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr),
|
||||
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
|
||||
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _highestPlayerAttackerLevel(0), _isCombatMovementAllowed(true)
|
||||
{
|
||||
m_regenTimer = CREATURE_REGEN_INTERVAL;
|
||||
m_valuesCount = UNIT_END;
|
||||
@@ -750,7 +750,7 @@ void Creature::Update(uint32 diff)
|
||||
{
|
||||
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
|
||||
if (group)
|
||||
group->EndRoll(&loot, GetMap());
|
||||
group->EndRoll(&loot);
|
||||
m_groupLootTimer = 0;
|
||||
lootingGroupLowGUID = 0;
|
||||
}
|
||||
@@ -2874,6 +2874,13 @@ void Creature::AtEngage(Unit* target)
|
||||
UpdateSpeed(MOVE_FLIGHT, true);
|
||||
}
|
||||
|
||||
// Notify controlled creatures (guardians/pets) so they assist when
|
||||
// the owner enters combat via assist/aggro chain, not only via damage.
|
||||
for (Unit* controlled : m_Controlled)
|
||||
if (Creature* cControlled = controlled->ToCreature())
|
||||
if (CreatureAI* controlledAI = cControlled->AI())
|
||||
controlledAI->OwnerAttackedBy(target);
|
||||
|
||||
MovementGeneratorType const movetype = GetMotionMaster()->GetCurrentMovementGeneratorType();
|
||||
if (movetype == WAYPOINT_MOTION_TYPE || movetype == ESCORT_MOTION_TYPE || (IsAIEnabled && AI()->IsEscorted()))
|
||||
{
|
||||
@@ -3836,7 +3843,7 @@ bool Creature::IsDamageEnoughForLootingAndReward() const
|
||||
return m_creatureInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (_playerDamageReq == 0 && _damagedByPlayer);
|
||||
}
|
||||
|
||||
void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= true*/)
|
||||
void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= true*/, uint8 attackerLevel /*= 0*/)
|
||||
{
|
||||
if (_playerDamageReq)
|
||||
_playerDamageReq > unDamage ? _playerDamageReq -= unDamage : _playerDamageReq = 0;
|
||||
@@ -3845,12 +3852,16 @@ void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= tr
|
||||
{
|
||||
_damagedByPlayer = damagedByPlayer;
|
||||
}
|
||||
|
||||
if (attackerLevel > _highestPlayerAttackerLevel)
|
||||
_highestPlayerAttackerLevel = attackerLevel;
|
||||
}
|
||||
|
||||
void Creature::ResetPlayerDamageReq()
|
||||
{
|
||||
_playerDamageReq = GetHealth() / 2;
|
||||
_damagedByPlayer = false;
|
||||
_highestPlayerAttackerLevel = 0;
|
||||
}
|
||||
|
||||
uint32 Creature::GetPlayerDamageReq() const
|
||||
|
||||
@@ -380,9 +380,10 @@ public:
|
||||
void SetLootRewardDisabled(bool disable) { DisableLootReward = disable; }
|
||||
[[nodiscard]] bool IsLootRewardDisabled() const { return DisableLootReward; }
|
||||
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
|
||||
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true);
|
||||
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true, uint8 attackerLevel = 0);
|
||||
void ResetPlayerDamageReq();
|
||||
[[nodiscard]] uint32 GetPlayerDamageReq() const;
|
||||
[[nodiscard]] uint8 GetHighestPlayerAttackerLevel() const { return _highestPlayerAttackerLevel; }
|
||||
|
||||
[[nodiscard]] uint32 GetOriginalEntry() const { return m_originalEntry; }
|
||||
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
||||
@@ -554,6 +555,7 @@ private:
|
||||
|
||||
uint32 _playerDamageReq;
|
||||
bool _damagedByPlayer;
|
||||
uint8 _highestPlayerAttackerLevel;
|
||||
bool _isCombatMovementAllowed;
|
||||
};
|
||||
|
||||
|
||||
@@ -766,7 +766,7 @@ void GameObject::Update(uint32 diff)
|
||||
{
|
||||
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
|
||||
if (group)
|
||||
group->EndRoll(&loot, GetMap());
|
||||
group->EndRoll(&loot);
|
||||
m_groupLootTimer = 0;
|
||||
lootingGroupLowGUID = 0;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ uint32 Bag::GetItemCount(uint32 item, Item* eItem) const
|
||||
for (uint32 i = 0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem && pItem != eItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
if (pItem && pItem != eItem && pItem->HasSocket())
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,8 +1014,11 @@ bool Item::HasSocket() const
|
||||
uint8 Item::GetGemCountWithID(uint32 GemID) const
|
||||
{
|
||||
uint8 count = 0;
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot <= PRISMATIC_ENCHANTMENT_SLOT; ++enchant_slot)
|
||||
{
|
||||
if (enchant_slot == BONUS_ENCHANTMENT_SLOT)
|
||||
continue;
|
||||
|
||||
uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if (!enchant_id)
|
||||
continue;
|
||||
@@ -1033,8 +1036,11 @@ uint8 Item::GetGemCountWithID(uint32 GemID) const
|
||||
uint8 Item::GetGemCountWithLimitCategory(uint32 limitCategory) const
|
||||
{
|
||||
uint8 count = 0;
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot <= PRISMATIC_ENCHANTMENT_SLOT; ++enchant_slot)
|
||||
{
|
||||
if (enchant_slot == BONUS_ENCHANTMENT_SLOT)
|
||||
continue;
|
||||
|
||||
uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if (!enchant_id)
|
||||
continue;
|
||||
|
||||
@@ -180,38 +180,38 @@ enum ItemFlags : uint32
|
||||
|
||||
enum ItemFlags2 : uint32
|
||||
{
|
||||
ITEM_FLAG2_FACTION_HORDE = 0x00000001,
|
||||
ITEM_FLAG2_FACTION_ALLIANCE = 0x00000002,
|
||||
ITEM_FLAG2_FACTION_HORDE = 0x00000001, // Only Horde can equip, loot, or buy back this item
|
||||
ITEM_FLAG2_FACTION_ALLIANCE = 0x00000002, // Only Alliance can equip, loot, or buy back this item
|
||||
ITEM_FLAG2_DONT_IGNORE_BUY_PRICE = 0x00000004, // when item uses extended cost, gold is also required
|
||||
ITEM_FLAG2_CLASSIFY_AS_CASTER = 0x00000008, // NYI
|
||||
ITEM_FLAG2_CLASSIFY_AS_CASTER = 0x00000008, // NYI - unused
|
||||
ITEM_FLAG2_CLASSIFY_AS_PHYSICAL = 0x00000010, // NYI
|
||||
ITEM_FLAG2_EVERYONE_CAN_ROLL_NEED = 0x00000020, // NYI
|
||||
ITEM_FLAG2_NO_TRADE_BIND_ON_ACQUIRE = 0x00000040, // NYI
|
||||
ITEM_FLAG2_CAN_TRADE_BIND_ON_ACQUIRE = 0x00000080, // NYI
|
||||
ITEM_FLAG2_CAN_ONLY_ROLL_GREED = 0x00000100,
|
||||
ITEM_FLAG2_EVERYONE_CAN_ROLL_NEED = 0x00000020, // Anyone can roll need
|
||||
ITEM_FLAG2_NO_TRADE_BIND_ON_ACQUIRE = 0x00000040, // NYI - unused
|
||||
ITEM_FLAG2_CAN_TRADE_BIND_ON_ACQUIRE = 0x00000080, // NYI - unused
|
||||
ITEM_FLAG2_CAN_ONLY_ROLL_GREED = 0x00000100, // Need rolls disallowed, only Greed / Disenchant / Pass
|
||||
ITEM_FLAG2_CASTER_WEAPON = 0x00000200, // NYI
|
||||
ITEM_FLAG2_DELETE_ON_LOGIN = 0x00000400, // NYI
|
||||
ITEM_FLAG2_INTERNAL_ITEM = 0x00000800, // NYI
|
||||
ITEM_FLAG2_NO_VENDOR_VALUE = 0x00001000, // NYI
|
||||
ITEM_FLAG2_DELETE_ON_LOGIN = 0x00000400, // NYI - unused
|
||||
ITEM_FLAG2_INTERNAL_ITEM = 0x00000800, // NYI - unused
|
||||
ITEM_FLAG2_NO_VENDOR_VALUE = 0x00001000, // NYI - unused
|
||||
ITEM_FLAG2_SHOW_BEFORE_DISCOVERED = 0x00002000, // NYI
|
||||
ITEM_FLAG2_OVERRIDE_GOLD_COST = 0x00004000, // NYI
|
||||
ITEM_FLAG2_OVERRIDE_GOLD_COST = 0x00004000, // NYI - unused
|
||||
ITEM_FLAG2_IGNORE_DEFAULT_RATED_BG_RESTRICTIONS = 0x00008000, // NYI
|
||||
ITEM_FLAG2_NOT_USABLE_IN_RATED_BG = 0x00010000, // NYI
|
||||
ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK = 0x00020000, // NYI
|
||||
ITEM_FLAG2_CONFIRM_BEFORE_USE = 0x00040000, // NYI
|
||||
ITEM_FLAG2_REEVALUATE_BONDING_ON_TRANSFORM = 0x00080000, // NYI
|
||||
ITEM_FLAG2_NO_TRANSFORM_ON_CHARGE_DEPLETION = 0x00100000, // NYI
|
||||
ITEM_FLAG2_CONFIRM_BEFORE_USE = 0x00040000, // NYI - unused
|
||||
ITEM_FLAG2_REEVALUATE_BONDING_ON_TRANSFORM = 0x00080000, // NYI - unused
|
||||
ITEM_FLAG2_NO_TRANSFORM_ON_CHARGE_DEPLETION = 0x00100000, // NYI - unused
|
||||
ITEM_FLAG2_NO_ALTER_ITEM_VISUAL = 0x00200000, // NYI
|
||||
ITEM_FLAG2_NO_SOURCE_FOR_ITEM_VISUAL = 0x00400000, // NYI
|
||||
ITEM_FLAG2_IGNORE_QUALITY_FOR_ITEM_VISUAL_SOURCE = 0x00800000, // NYI
|
||||
ITEM_FLAG2_NO_DURABILITY = 0x01000000, // NYI
|
||||
ITEM_FLAG2_ROLE_TANK = 0x02000000, // NYI
|
||||
ITEM_FLAG2_ROLE_HEALER = 0x04000000, // NYI
|
||||
ITEM_FLAG2_ROLE_DAMAGE = 0x08000000, // NYI
|
||||
ITEM_FLAG2_CAN_DROP_IN_CHALLENGE_MODE = 0x10000000, // NYI
|
||||
ITEM_FLAG2_NEVER_STACK_IN_LOOT_UI = 0x20000000, // NYI
|
||||
ITEM_FLAG2_DISENCHANT_TO_LOOT_TABLE = 0x40000000, // NYI
|
||||
ITEM_FLAG2_USED_IN_A_TRADESKILL = 0x80000000 // NYI
|
||||
ITEM_FLAG2_IGNORE_QUALITY_FOR_ITEM_VISUAL_SOURCE = 0x00800000, // NYI - unused
|
||||
ITEM_FLAG2_NO_DURABILITY = 0x01000000, // NYI - unused
|
||||
ITEM_FLAG2_ROLE_TANK = 0x02000000, // NYI - unused
|
||||
ITEM_FLAG2_ROLE_HEALER = 0x04000000, // NYI - unused
|
||||
ITEM_FLAG2_ROLE_DAMAGE = 0x08000000, // NYI - unused
|
||||
ITEM_FLAG2_CAN_DROP_IN_CHALLENGE_MODE = 0x10000000, // NYI - unused
|
||||
ITEM_FLAG2_NEVER_STACK_IN_LOOT_UI = 0x20000000, // NYI - unused
|
||||
ITEM_FLAG2_DISENCHANT_TO_LOOT_TABLE = 0x40000000, // NYI - unused
|
||||
ITEM_FLAG2_USED_IN_A_TRADESKILL = 0x80000000 // NYI - unused
|
||||
};
|
||||
|
||||
enum ItemFlagsCustom : uint32
|
||||
|
||||
@@ -2123,7 +2123,7 @@ void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, b
|
||||
|
||||
void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
|
||||
{
|
||||
Acore::MessageDistDeliverer notifier(this, data, 0.0f, false, skipped_rcvr);
|
||||
Acore::MessageDistDeliverer notifier(this, data, 0.0f, Acore::TeamFilter::All, skipped_rcvr);
|
||||
notifier.Visit(GetObjectVisibilityContainer().GetVisiblePlayersMap());
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "KillRewarder.h"
|
||||
#include "Creature.h"
|
||||
#include "Formulas.h"
|
||||
#include "Group.h"
|
||||
#include "Pet.h"
|
||||
@@ -161,6 +162,19 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
else
|
||||
xp = 0;
|
||||
}
|
||||
|
||||
// An ungrouped helper who out-levels everyone eligible for the kill and for
|
||||
// whom the victim is gray halves the tagger's XP, matching the group
|
||||
// gray-member penalty. Closes a power-leveling exploit.
|
||||
if (xp)
|
||||
if (Creature* creature = _victim->ToCreature())
|
||||
{
|
||||
uint8 const referenceLevel = _group ? _maxLevel : player->GetLevel();
|
||||
uint8 const highestLevel = creature->GetHighestPlayerAttackerLevel();
|
||||
if (highestLevel > referenceLevel && creature->GetLevel() <= Acore::XP::GetGrayLevel(highestLevel))
|
||||
xp = xp / 2 + 1;
|
||||
}
|
||||
|
||||
if (xp)
|
||||
{
|
||||
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
|
||||
|
||||
@@ -3891,10 +3891,10 @@ bool Player::HasSpell(uint32 spell) const
|
||||
return (itr != m_spells.end() && itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(m_activeSpec));
|
||||
}
|
||||
|
||||
bool Player::HasTalent(uint32 spell, uint8 /*spec*/) const
|
||||
bool Player::HasTalent(uint32 spell, uint8 spec) const
|
||||
{
|
||||
PlayerTalentMap::const_iterator itr = m_talents.find(spell);
|
||||
return (itr != m_talents.end() && itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(m_activeSpec));
|
||||
return (itr != m_talents.end() && itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(spec));
|
||||
}
|
||||
|
||||
bool Player::HasActiveSpell(uint32 spell) const
|
||||
@@ -5703,7 +5703,7 @@ void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcv
|
||||
if (skipped_rcvr != this)
|
||||
SendDirectMessage(data);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, 0.0f, false, skipped_rcvr);
|
||||
Acore::MessageDistDeliverer notifier(this, data, 0.0f, Acore::TeamFilter::All, skipped_rcvr);
|
||||
notifier.Visit(GetObjectVisibilityContainer().GetVisiblePlayersMap());
|
||||
}
|
||||
|
||||
@@ -9418,7 +9418,7 @@ void Player::Say(std::string_view text, Language language, WorldObject const* /*
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), false, nullptr, true);
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), Acore::TeamFilter::All, nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY));
|
||||
}
|
||||
|
||||
@@ -9446,7 +9446,7 @@ void Player::Yell(std::string_view text, Language language, WorldObject const* /
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), false, nullptr, true);
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), Acore::TeamFilter::All, nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL));
|
||||
}
|
||||
|
||||
@@ -9474,8 +9474,27 @@ void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/,
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT), nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
|
||||
if (GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT))
|
||||
{
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), Acore::TeamFilter::All, nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Same faction
|
||||
{
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), Acore::TeamFilter::OwnTeam, nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
|
||||
}
|
||||
// Opposite faction
|
||||
{
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, "");
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), Acore::TeamFilter::OtherTeam, nullptr, true);
|
||||
Cell::VisitObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool /*isBossEmote = false*/)
|
||||
@@ -13922,8 +13941,11 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi
|
||||
return res;
|
||||
|
||||
// check unique-equipped on gems
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + 3; ++enchant_slot)
|
||||
for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot <= PRISMATIC_ENCHANTMENT_SLOT; ++enchant_slot)
|
||||
{
|
||||
if (enchant_slot == BONUS_ENCHANTMENT_SLOT)
|
||||
continue;
|
||||
|
||||
uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
|
||||
if (!enchant_id)
|
||||
continue;
|
||||
|
||||
@@ -655,7 +655,7 @@ enum PlayerSlots
|
||||
|
||||
#define INVENTORY_SLOT_BAG_0 255
|
||||
|
||||
enum EquipmentSlots : uint32 // 19 slots
|
||||
enum EquipmentSlots // 19 slots
|
||||
{
|
||||
EQUIPMENT_SLOT_START = 0,
|
||||
EQUIPMENT_SLOT_HEAD = 0,
|
||||
|
||||
@@ -347,7 +347,7 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
|
||||
if (skipItem && skipItem->GetTemplate()->GemProperties)
|
||||
for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
if (pItem != skipItem && pItem->HasSocket())
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
|
||||
if (inBankAlso)
|
||||
@@ -365,7 +365,7 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
|
||||
if (skipItem && skipItem->GetTemplate()->GemProperties)
|
||||
for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
|
||||
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
if (pItem != skipItem && pItem->HasSocket())
|
||||
count += pItem->GetGemCountWithID(item);
|
||||
}
|
||||
|
||||
@@ -754,7 +754,7 @@ bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_
|
||||
continue;
|
||||
|
||||
Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
|
||||
if (pItem && pItem->GetTemplate()->Socket[0].Color)
|
||||
if (pItem && pItem->HasSocket())
|
||||
{
|
||||
tempcount += pItem->GetGemCountWithID(item);
|
||||
if (tempcount >= count)
|
||||
@@ -2455,6 +2455,10 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
|
||||
SKILL_FISHING
|
||||
}; //Copy from function Item::GetSkill()
|
||||
|
||||
// Anyone can roll need on this item
|
||||
if (proto->HasFlag2(ITEM_FLAG2_EVERYONE_CAN_ROLL_NEED))
|
||||
return EQUIP_ERR_OK;
|
||||
|
||||
if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
|
||||
|
||||
@@ -1233,7 +1233,18 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
|
||||
uint32 unDamage = health < damage ? health : damage;
|
||||
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr
|
||||
|| attacker->GetCharmerGUID().IsPlayer());
|
||||
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer);
|
||||
|
||||
uint8 attackerLevel = 0;
|
||||
if (damagedByPlayer)
|
||||
{
|
||||
Player* attackerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!attackerPlayer && attacker->m_movedByPlayer)
|
||||
attackerPlayer = attacker->m_movedByPlayer->ToPlayer();
|
||||
if (attackerPlayer)
|
||||
attackerLevel = attackerPlayer->GetLevel();
|
||||
}
|
||||
|
||||
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer, attackerLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11335,22 +11346,7 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
|
||||
|
||||
if (forced && IsClientControlled())
|
||||
{
|
||||
Player* player = const_cast<Player*>(GetClientControlling());
|
||||
uint32 const counter = player->GetSession()->GetOrderCounter();
|
||||
|
||||
// register forced speed changes for WorldSession::HandleForceSpeedChangeAck
|
||||
// and do it only for real sent packets and use run for run/mounted as client expected
|
||||
++player->m_forced_speed_changes[mtype];
|
||||
|
||||
WorldPacket data(speedOpcodes[static_cast<size_t>(SpeedOpcodeIndex::PC)], 18);
|
||||
data << GetPackGUID();
|
||||
data << counter;
|
||||
if (mtype == MOVE_RUN)
|
||||
data << uint8(0); // new 2.1.0
|
||||
|
||||
data << GetSpeed(mtype);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
player->GetSession()->IncrementOrderCounter();
|
||||
SendSpeedToController(mtype, const_cast<Player*>(GetClientControlling()));
|
||||
}
|
||||
else if (forced)
|
||||
{
|
||||
@@ -11383,6 +11379,24 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SendSpeedToController(UnitMoveType mtype, Player* target) const
|
||||
{
|
||||
SpeedOpcodePair const& speedOpcodes = SetSpeed2Opc_table[mtype];
|
||||
uint32 const counter = target->GetSession()->GetOrderCounter();
|
||||
|
||||
++target->m_forced_speed_changes[mtype];
|
||||
|
||||
WorldPacket data(speedOpcodes[static_cast<size_t>(SpeedOpcodeIndex::PC)], 18);
|
||||
data << GetPackGUID();
|
||||
data << counter;
|
||||
if (mtype == MOVE_RUN)
|
||||
data << uint8(0);
|
||||
|
||||
data << GetSpeed(mtype);
|
||||
target->GetSession()->SendPacket(&data);
|
||||
target->GetSession()->IncrementOrderCounter();
|
||||
}
|
||||
|
||||
void Unit::setDeathState(DeathState s, bool despawn)
|
||||
{
|
||||
// death state needs to be updated before RemoveAllAurasOnDeath() calls HandleChannelDeathItem(..) so that
|
||||
@@ -14711,6 +14725,10 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
||||
_oldFactionId = GetFaction();
|
||||
SetFaction(charmer->GetFaction());
|
||||
|
||||
// snapshot current speed rates so we can detect speed changes
|
||||
for (uint8 i = MOVE_WALK; i < MAX_MOVE_TYPE; ++i)
|
||||
_charmStartSpeedRate[i] = m_speed_rate[i];
|
||||
|
||||
// Set charmed
|
||||
charmer->SetCharm(this, true);
|
||||
|
||||
@@ -14862,9 +14880,6 @@ void Unit::RemoveCharmedBy(Unit* charmer)
|
||||
CastStop();
|
||||
AttackStop();
|
||||
|
||||
// xinef: update speed after charming
|
||||
UpdateSpeed(MOVE_RUN, false);
|
||||
|
||||
// xinef: do not break any controlled motion slot
|
||||
if (GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
{
|
||||
@@ -14967,7 +14982,15 @@ void Unit::RemoveCharmedBy(Unit* charmer)
|
||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
||||
}
|
||||
else
|
||||
ToPlayer()->SetClientControl(this, true); // verified
|
||||
{
|
||||
Player* targetPlayer = ToPlayer();
|
||||
targetPlayer->SetClientControl(this, true); // verified
|
||||
|
||||
// Re-sync only the speed types that changed during the charm.
|
||||
for (uint8 i = MOVE_WALK; i < MAX_MOVE_TYPE; ++i)
|
||||
if (m_speed_rate[i] != _charmStartSpeedRate[i])
|
||||
SendSpeedToController(UnitMoveType(i), targetPlayer);
|
||||
}
|
||||
|
||||
// a guardian should always have charminfo
|
||||
if (playerCharmer && this != charmer->GetFirstControlled())
|
||||
@@ -15863,7 +15886,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
|
||||
if ((!player || !(player->GetDelayedOperations() & DELAYED_VEHICLE_TELEPORT)) && vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
|
||||
if (((Minion*)vehicleBase)->GetOwner() == this)
|
||||
{
|
||||
if (!vehicleInfo || vehicleInfo->m_ID != 349)
|
||||
if (!vehicleInfo || (vehicleInfo->m_ID != 349 && vehicleBase->GetEntry() != 28192))
|
||||
{
|
||||
vehicle->Dismiss();
|
||||
}
|
||||
|
||||
@@ -1744,6 +1744,7 @@ public:
|
||||
[[nodiscard]] float GetSpeedRate(UnitMoveType mtype) const { return m_speed_rate[mtype]; }
|
||||
void SetSpeed(UnitMoveType mtype, float rate, bool forced = false);
|
||||
void SetSpeedRate(UnitMoveType mtype, float rate) { m_speed_rate[mtype] = rate; }
|
||||
void SendSpeedToController(UnitMoveType mtype, Player* target) const;
|
||||
|
||||
void propagateSpeedChange() { GetMotionMaster()->propagateSpeedChange(); }
|
||||
|
||||
@@ -2188,6 +2189,9 @@ protected:
|
||||
|
||||
float m_speed_rate[MAX_MOVE_TYPE];
|
||||
|
||||
// snapshot of speed rates taken when SetCharmedBy() is called
|
||||
float _charmStartSpeedRate[MAX_MOVE_TYPE]{};
|
||||
|
||||
CharmInfo* m_charmInfo;
|
||||
SharedVisionList m_sharedVision;
|
||||
|
||||
|
||||
@@ -96,33 +96,63 @@ namespace Acore
|
||||
void Visit(CreatureMapType&);
|
||||
};
|
||||
|
||||
enum class TeamFilter
|
||||
{
|
||||
All,
|
||||
OwnTeam,
|
||||
OtherTeam,
|
||||
};
|
||||
|
||||
struct MessageDistDeliverer
|
||||
{
|
||||
WorldObject const* i_source;
|
||||
WorldPacket const* i_message;
|
||||
uint32 i_phaseMask;
|
||||
float i_distSq;
|
||||
TeamFilter teamFilter;
|
||||
TeamId teamId;
|
||||
Player const* skipped_receiver;
|
||||
bool required3dDist;
|
||||
MessageDistDeliverer(WorldObject const* src, WorldPacket const* msg, float dist, bool own_team_only = false, Player const* skipped = nullptr, bool req3dDist = false)
|
||||
: i_source(src), i_message(msg), i_phaseMask(src->GetPhaseMask()), i_distSq(dist * dist)
|
||||
, teamId((own_team_only && src->IsPlayer()) ? src->ToPlayer()->GetTeamId() : TEAM_NEUTRAL)
|
||||
, skipped_receiver(skipped), required3dDist(req3dDist)
|
||||
{
|
||||
}
|
||||
|
||||
MessageDistDeliverer(WorldObject const* src, WorldPacket const* msg, float dist, TeamFilter teamFilter = TeamFilter::All, Player const* skipped = nullptr, bool req3dDist = false) :
|
||||
i_source(src),
|
||||
i_message(msg),
|
||||
i_phaseMask(src->GetPhaseMask()),
|
||||
i_distSq(dist * dist),
|
||||
teamFilter(src->IsPlayer() ? teamFilter : TeamFilter::All),
|
||||
teamId(src->IsPlayer() ? src->ToPlayer()->GetTeamId() : TEAM_NEUTRAL),
|
||||
skipped_receiver(skipped),
|
||||
required3dDist(req3dDist)
|
||||
{ }
|
||||
|
||||
void Visit(VisiblePlayersMap const& m);
|
||||
void Visit(PlayerMapType& m);
|
||||
void Visit(CreatureMapType& m);
|
||||
void Visit(DynamicObjectMapType& m);
|
||||
template<class SKIP> void Visit(GridRefMgr<SKIP>&) {}
|
||||
|
||||
void SendPacket(Player* player)
|
||||
template <class SKIP> void Visit(GridRefMgr<SKIP>&) { }
|
||||
|
||||
void SendPacket(Player* player) const
|
||||
{
|
||||
// never send packet to self
|
||||
if (player == i_source || (teamId != TEAM_NEUTRAL && player->GetTeamId() != teamId) || skipped_receiver == player)
|
||||
if (player == i_source || skipped_receiver == player)
|
||||
return;
|
||||
|
||||
switch (teamFilter)
|
||||
{
|
||||
default:
|
||||
case TeamFilter::All:
|
||||
break;
|
||||
case TeamFilter::OwnTeam:
|
||||
if (player->GetTeamId() != teamId)
|
||||
return;
|
||||
break;
|
||||
case TeamFilter::OtherTeam:
|
||||
if (player->GetTeamId() == teamId)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!player->HaveAtClient(i_source))
|
||||
return;
|
||||
|
||||
|
||||
@@ -1414,20 +1414,20 @@ bool Group::CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choice)
|
||||
|
||||
if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
|
||||
{
|
||||
CountTheRoll(rollI, nullptr);
|
||||
CountTheRoll(rollI);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//called when roll timer expires
|
||||
void Group::EndRoll(Loot* pLoot, Map* allowedMap)
|
||||
void Group::EndRoll(Loot* pLoot)
|
||||
{
|
||||
for (Rolls::iterator itr = RollId.begin(); itr != RollId.end();)
|
||||
{
|
||||
if ((*itr)->getLoot() == pLoot)
|
||||
{
|
||||
CountTheRoll(itr, allowedMap); //i don't have to edit player votes, who didn't vote ... he will pass
|
||||
CountTheRoll(itr); //i don't have to edit player votes, who didn't vote ... he will pass
|
||||
itr = RollId.begin();
|
||||
}
|
||||
else
|
||||
@@ -1466,7 +1466,7 @@ void Group::RemovePlayerFromRolls(ObjectGuid guid)
|
||||
}
|
||||
}
|
||||
|
||||
void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
void Group::CountTheRoll(Rolls::iterator rollI)
|
||||
{
|
||||
Roll* roll = *rollI;
|
||||
if (!roll->isValid()) // is loot already deleted ?
|
||||
@@ -1491,7 +1491,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
continue;
|
||||
|
||||
player = ObjectAccessor::FindPlayer(itr->first);
|
||||
if (!player || (allowedMap != nullptr && player->FindMap() != allowedMap))
|
||||
if (!player)
|
||||
{
|
||||
--roll->totalNeed;
|
||||
continue;
|
||||
@@ -1555,7 +1555,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
roll->totalNeed = 0;
|
||||
}
|
||||
}
|
||||
if (roll->totalNeed == 0 && roll->totalGreed > 0) // pussywizard: if (roll->totalNeed == 0 && ...), not else if, because numbers can be modified above if player is on a different map
|
||||
if (roll->totalNeed == 0 && roll->totalGreed > 0) // if (roll->totalNeed == 0 && ...), not else if, because totalNeed can be decremented above when a needing player is offline
|
||||
{
|
||||
if (!roll->playerVote.empty())
|
||||
{
|
||||
@@ -1571,7 +1571,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
continue;
|
||||
|
||||
player = ObjectAccessor::FindPlayer(itr->first);
|
||||
if (!player || (allowedMap != nullptr && player->FindMap() != allowedMap))
|
||||
if (!player)
|
||||
{
|
||||
--roll->totalGreed;
|
||||
continue;
|
||||
@@ -1669,7 +1669,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
|
||||
roll->totalGreed = 0;
|
||||
}
|
||||
}
|
||||
if (roll->totalNeed == 0 && roll->totalGreed == 0) // pussywizard: if, not else, because numbers can be modified above if player is on a different map
|
||||
if (roll->totalNeed == 0 && roll->totalGreed == 0) // if, not else, because the totals can be decremented above when a rolling player is offline
|
||||
{
|
||||
SendLootAllPassed(*roll);
|
||||
|
||||
|
||||
@@ -306,9 +306,9 @@ public:
|
||||
void NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject);
|
||||
void MasterLoot(Loot* loot, WorldObject* pLootedObject);
|
||||
Rolls::iterator GetRoll(ObjectGuid Guid);
|
||||
void CountTheRoll(Rolls::iterator roll, Map* allowedMap);
|
||||
void CountTheRoll(Rolls::iterator roll);
|
||||
bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise);
|
||||
void EndRoll(Loot* loot, Map* allowedMap);
|
||||
void EndRoll(Loot* loot);
|
||||
void RemovePlayerFromRolls(ObjectGuid guid);
|
||||
|
||||
Rolls GetRolls() const { return RollId; }
|
||||
|
||||
@@ -945,16 +945,6 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
||||
// Place character in world (and load zone) before some object loading
|
||||
pCurrChar->LoadCorpse(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION));
|
||||
|
||||
// setting Ghost+speed if dead
|
||||
if (pCurrChar->m_deathState != DeathState::Alive)
|
||||
{
|
||||
// not blizz like, we must correctly save and load player instead...
|
||||
if (pCurrChar->getRace() == RACE_NIGHTELF)
|
||||
pCurrChar->CastSpell(pCurrChar, 20584, true, 0); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
|
||||
|
||||
pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
|
||||
}
|
||||
|
||||
// Set FFA PvP for non GM in non-rest mode
|
||||
if (sWorld->IsFFAPvPRealm() && !pCurrChar->IsGameMaster() && !pCurrChar->HasPlayerFlag(PLAYER_FLAGS_RESTING))
|
||||
if (!pCurrChar->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
|
||||
|
||||
@@ -426,7 +426,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ
|
||||
bool preventAfkSanctuaryLogout = sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 1
|
||||
&& GetPlayer()->isAFK() && sAreaTableStore.LookupEntry(GetPlayer()->GetAreaId())->IsSanctuary();
|
||||
|
||||
bool preventAfkLogout = sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 2
|
||||
bool preventAfkLogout = ((sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 2) || HasAccountFlag(ACCOUNT_FLAG_NOKICK))
|
||||
&& GetPlayer()->isAFK();
|
||||
|
||||
/// @todo: Possibly add RBAC permission to log out in combat
|
||||
|
||||
@@ -41,8 +41,8 @@ void ServerMailMgr::LoadMailServerTemplates()
|
||||
|
||||
_serverMailStore.clear(); // for reload case
|
||||
|
||||
// 0 1 2 3 4 5
|
||||
QueryResult result = CharacterDatabase.Query("SELECT `id`, `moneyA`, `moneyH`, `subject`, `body`, `active` FROM `mail_server_template`");
|
||||
// 0 1 2 3 4 5 6
|
||||
QueryResult result = CharacterDatabase.Query("SELECT `id`, `senderEntry`, `moneyA`, `moneyH`, `subject`, `body`, `active` FROM `mail_server_template`");
|
||||
if (!result)
|
||||
{
|
||||
LOG_INFO("server.loading", ">> Loaded 0 server mail rewards. DB table `mail_server_template` is empty.");
|
||||
@@ -60,11 +60,12 @@ void ServerMailMgr::LoadMailServerTemplates()
|
||||
|
||||
ServerMail& servMail = _serverMailStore[id];
|
||||
servMail.id = id;
|
||||
servMail.moneyA = fields[1].Get<uint32>();
|
||||
servMail.moneyH = fields[2].Get<uint32>();
|
||||
servMail.subject = fields[3].Get<std::string>();
|
||||
servMail.body = fields[4].Get<std::string>();
|
||||
servMail.active = fields[5].Get<uint8>();
|
||||
servMail.senderEntry = fields[1].Get<uint32>();
|
||||
servMail.moneyA = fields[2].Get<uint32>();
|
||||
servMail.moneyH = fields[3].Get<uint32>();
|
||||
servMail.subject = fields[4].Get<std::string>();
|
||||
servMail.body = fields[5].Get<std::string>();
|
||||
servMail.active = fields[6].Get<uint8>();
|
||||
|
||||
// Skip non-activated entries
|
||||
if (!servMail.active)
|
||||
@@ -75,6 +76,12 @@ void ServerMailMgr::LoadMailServerTemplates()
|
||||
LOG_ERROR("sql.sql", "Table `mail_server_template` has moneyA {} or moneyH {} larger than MAX_MONEY_AMOUNT {} for id {}, skipped.", servMail.moneyA, servMail.moneyH, MAX_MONEY_AMOUNT, servMail.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (servMail.senderEntry && !sObjectMgr->GetCreatureTemplate(servMail.senderEntry))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `mail_server_template` has invalid senderEntry {} (no matching creature_template) for id {}, falling back to default sender.", servMail.senderEntry, servMail.id);
|
||||
servMail.senderEntry = 0;
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
LoadMailServerTemplatesItems();
|
||||
@@ -281,7 +288,7 @@ void ServerMailMgr::LoadMailServerTemplatesConditions()
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void ServerMailMgr::SendServerMail(Player* player, uint32 id, uint32 money,
|
||||
void ServerMailMgr::SendServerMail(Player* player, uint32 id, uint32 senderEntry, uint32 money,
|
||||
std::vector<ServerMailItems> const& items,
|
||||
std::vector<ServerMailCondition> const& conditions,
|
||||
std::string const& subject, std::string const& body) const
|
||||
@@ -292,7 +299,9 @@ void ServerMailMgr::SendServerMail(Player* player, uint32 id, uint32 money,
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
MailSender sender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
|
||||
MailSender sender = senderEntry
|
||||
? MailSender(MAIL_CREATURE, senderEntry, MAIL_STATIONERY_DEFAULT)
|
||||
: MailSender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
|
||||
MailDraft draft(subject, body);
|
||||
|
||||
draft.AddMoney(money);
|
||||
|
||||
@@ -128,6 +128,7 @@ struct ServerMail
|
||||
{
|
||||
ServerMail() = default;
|
||||
uint32 id{ 0 };
|
||||
uint32 senderEntry{ 0 }; ///< Entry from creature_template. 0 for default "Customer Support" sender.
|
||||
uint32 moneyA{ 0 };
|
||||
uint32 moneyH{ 0 };
|
||||
std::string subject;
|
||||
@@ -205,6 +206,7 @@ public:
|
||||
*
|
||||
* @param player The recipient player.
|
||||
* @param id The template ID.
|
||||
* @param senderEntry Entry from creature_template. 0 for default "Customer Support" sender.
|
||||
* @param money Money reward.
|
||||
* @param items List of items to include in the mail.
|
||||
* @param conditions List of the conditions for the mail.
|
||||
@@ -212,7 +214,7 @@ public:
|
||||
* @param body Mail body.
|
||||
* @param active Whether the mail template is active.
|
||||
*/
|
||||
void SendServerMail(Player* player, uint32 id, uint32 money, std::vector<ServerMailItems> const& items, std::vector<ServerMailCondition> const& conditions, std::string const& subject, std::string const& body) const;
|
||||
void SendServerMail(Player* player, uint32 id, uint32 senderEntry, uint32 money, std::vector<ServerMailItems> const& items, std::vector<ServerMailCondition> const& conditions, std::string const& subject, std::string const& body) const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the entire server mail store.
|
||||
|
||||
@@ -5209,6 +5209,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].BasePoints = 1;
|
||||
});
|
||||
|
||||
// 51036 Summon Venture Co. Air Patrol
|
||||
ApplySpellFix({ 51036 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_CASTER);
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -428,6 +428,13 @@ class spell_bonfires_blessing : public AuraScript
|
||||
return ValidateSpellInfo({ SPELL_BONFIRES_BLESSING });
|
||||
}
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
Unit* actor = eventInfo.GetActor();
|
||||
Unit* actionTarget = eventInfo.GetActionTarget();
|
||||
return actor && actionTarget && actor->IsValidAttackTarget(actionTarget);
|
||||
}
|
||||
|
||||
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL))
|
||||
@@ -439,6 +446,7 @@ class spell_bonfires_blessing : public AuraScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_bonfires_blessing::CheckProc);
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_bonfires_blessing::OnApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -83,9 +83,14 @@ enum Shadowmourne
|
||||
|
||||
bool IsVampire(Unit const* unit)
|
||||
{
|
||||
if (unit->HasAnyAuras(SPELL_ESSENCE_OF_BLOOD_QUEEN, SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, SPELL_FRENZIED_BLOODTHIRST))
|
||||
return true;
|
||||
return false;
|
||||
if (!unit)
|
||||
return false;
|
||||
|
||||
return unit->HasAnyAuras(
|
||||
sSpellMgr->GetSpellIdForDifficulty(SPELL_ESSENCE_OF_BLOOD_QUEEN, unit),
|
||||
sSpellMgr->GetSpellIdForDifficulty(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, unit),
|
||||
sSpellMgr->GetSpellIdForDifficulty(SPELL_FRENZIED_BLOODTHIRST, unit)
|
||||
);
|
||||
}
|
||||
|
||||
enum Events
|
||||
|
||||
@@ -33,7 +33,7 @@ enum Says
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_UNBALANCING_STRIKE = 26613,
|
||||
SPELL_UNBALANCING_STRIKE = 55470,
|
||||
SPELL_DISRUPTING_SHOUT = 55543,
|
||||
SPELL_JAGGED_KNIFE = 55550,
|
||||
SPELL_HOPELESS = 29125,
|
||||
|
||||
@@ -595,6 +595,7 @@ public:
|
||||
case NOT_STARTED:
|
||||
{
|
||||
_horsemanAchievement = true;
|
||||
_events.CancelEvent(EVENT_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER);
|
||||
|
||||
if (!horsemanKilled)
|
||||
break;
|
||||
|
||||
@@ -102,6 +102,8 @@ enum YoggSpells
|
||||
SPELL_FOCUSED_ANGER = 57688,
|
||||
|
||||
// CONSTRICTOR TENTACLE
|
||||
SPELL_CONSTRICTOR_TENTACLE = 64132,
|
||||
SPELL_CONSTRICTOR_TENTACLE_SUMMON = 64133,
|
||||
SPELL_LUNGE = 64123,
|
||||
SPELL_SQUEEZE = 64125,
|
||||
|
||||
@@ -853,7 +855,7 @@ struct boss_yoggsaron_sara : public ScriptedAI
|
||||
events.Repeat(Milliseconds(uint32((50000 + urand(0, 10000)) * _summonSpeed)));
|
||||
break;
|
||||
case EVENT_SARA_P2_SUMMON_T2: // CONSTRICTOR
|
||||
SpawnTentacle(NPC_CONSTRICTOR_TENTACLE);
|
||||
me->CastCustomSpell(SPELL_CONSTRICTOR_TENTACLE, SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
events.Repeat(Milliseconds(uint32((15000 + urand(0, 5000))* _summonSpeed)));
|
||||
break;
|
||||
case EVENT_SARA_P2_SUMMON_T3: // CORRUPTOR
|
||||
@@ -886,7 +888,7 @@ struct boss_yoggsaron_sara : public ScriptedAI
|
||||
me->SetPosition(me->GetPositionX(), me->GetPositionY(), 355, me->GetOrientation());
|
||||
|
||||
SpawnTentacle(NPC_CRUSHER_TENTACLE);
|
||||
SpawnTentacle(NPC_CONSTRICTOR_TENTACLE);
|
||||
me->CastCustomSpell(SPELL_CONSTRICTOR_TENTACLE, SPELLVALUE_MAX_TARGETS, 1, me, false);
|
||||
SpawnTentacle(NPC_CORRUPTOR_TENTACLE);
|
||||
SpawnTentacle(NPC_CORRUPTOR_TENTACLE);
|
||||
|
||||
@@ -1569,13 +1571,46 @@ struct boss_yoggsaron_constrictor_tentacle : public ScriptedAI
|
||||
boss_yoggsaron_constrictor_tentacle(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
me->SetCombatMovement(false);
|
||||
_checkTimer = 1;
|
||||
_playerGUID.Clear();
|
||||
}
|
||||
|
||||
uint32 _checkTimer;
|
||||
ObjectGuid _playerGUID;
|
||||
|
||||
void GrabPlayer(Unit* target)
|
||||
{
|
||||
target->CastSpell(me, SPELL_LUNGE, true);
|
||||
target->CastSpell(target, SPELL_SQUEEZE, true);
|
||||
_playerGUID = target->GetGUID();
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
{
|
||||
me->CastSpell(me, SPELL_TENTACLE_ERUPT, true);
|
||||
me->CastSpell(me, SPELL_VOID_ZONE_SMALL, true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
|
||||
me->SetInCombatWithZone();
|
||||
|
||||
// The summoner is the marked player (64133 is self-cast); 64132 already
|
||||
// picked a valid enemy, so only re-check that they can still be squeezed.
|
||||
// Fall back to the nearest valid player otherwise.
|
||||
Unit* target = nullptr;
|
||||
if (Player* player = summoner ? summoner->ToPlayer() : nullptr)
|
||||
if (player->IsAlive() && !player->HasAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me)))
|
||||
target = player;
|
||||
|
||||
if (!target)
|
||||
target = SelectConstrictTarget();
|
||||
|
||||
if (target)
|
||||
GrabPlayer(target);
|
||||
|
||||
// Summoned from a player, so register with Sara to keep the encounter's
|
||||
// despawn handling working.
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
if (Creature* sara = instance->GetCreature(DATA_SARA))
|
||||
sara->AI()->JustSummoned(me);
|
||||
}
|
||||
|
||||
Unit* SelectConstrictTarget()
|
||||
{
|
||||
Player* target = nullptr;
|
||||
@@ -1598,27 +1633,6 @@ struct boss_yoggsaron_constrictor_tentacle : public ScriptedAI
|
||||
return target;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_checkTimer)
|
||||
{
|
||||
_checkTimer += diff;
|
||||
if (_checkTimer >= 1000 && !me->HasUnitState(UNIT_STATE_STUNNED))
|
||||
{
|
||||
if (Unit* target = SelectConstrictTarget())
|
||||
{
|
||||
target->CastSpell(me, SPELL_LUNGE, true);
|
||||
target->CastSpell(target, SPELL_SQUEEZE, true);
|
||||
_playerGUID = target->GetGUID();
|
||||
_checkTimer = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_checkTimer = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_REMOVE_STUN)
|
||||
@@ -1629,6 +1643,8 @@ struct boss_yoggsaron_constrictor_tentacle : public ScriptedAI
|
||||
{
|
||||
if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID))
|
||||
player->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me));
|
||||
|
||||
me->DespawnOrUnsummon(5s);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2677,6 +2693,28 @@ class spell_yogg_saron_target_selectors : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 64132 - Constrictor Tentacle
|
||||
class spell_yogg_saron_constrictor_tentacle_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_yogg_saron_constrictor_tentacle_aura);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_CONSTRICTOR_TENTACLE_SUMMON });
|
||||
}
|
||||
|
||||
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
// Spawns the tentacle on the marked player so it grabs them on the spot.
|
||||
GetTarget()->CastSpell(GetTarget(), SPELL_CONSTRICTOR_TENTACLE_SUMMON, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_constrictor_tentacle_aura::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
// 63305 - Grim Reprisal
|
||||
class spell_yogg_saron_grim_reprisal_aura : public AuraScript
|
||||
{
|
||||
@@ -2807,6 +2845,7 @@ void AddSC_boss_yoggsaron()
|
||||
RegisterSpellScript(spell_yogg_saron_empowering_shadows);
|
||||
RegisterSpellScript(spell_yogg_saron_in_the_maws_of_the_old_god);
|
||||
RegisterSpellScript(spell_yogg_saron_target_selectors);
|
||||
RegisterSpellScript(spell_yogg_saron_constrictor_tentacle_aura);
|
||||
RegisterSpellScript(spell_yogg_saron_grim_reprisal_aura);
|
||||
|
||||
// ACHIEVEMENTS
|
||||
|
||||
@@ -166,7 +166,6 @@ struct violet_hold_trashAI : public npc_escortAI
|
||||
{
|
||||
Instance = c->GetInstanceScript();
|
||||
PortalLoc = Instance->GetData(DATA_PORTAL_LOCATION);
|
||||
AddedWaypoints = false;
|
||||
UseAlternate = false;
|
||||
}
|
||||
|
||||
@@ -209,58 +208,59 @@ struct violet_hold_trashAI : public npc_escortAI
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
npc_escortAI::InitializeAI();
|
||||
|
||||
switch (PortalLoc)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < 6; i++)
|
||||
AddWaypoint(i, FirstPortalTrashWPs[i][0] + irand(-1, 1), FirstPortalTrashWPs[i][1] + irand(-1, 1), FirstPortalTrashWPs[i][2] + irand(-1, 1), 0);
|
||||
me->SetHomePosition(FirstPortalTrashWPs[5][0], FirstPortalTrashWPs[5][1], FirstPortalTrashWPs[5][2], 3.149439f);
|
||||
break;
|
||||
case 1:
|
||||
UseAlternate = (bool)urand(0, 1);
|
||||
if (!UseAlternate)
|
||||
{
|
||||
for (int i = 0; i < 9; i++)
|
||||
AddWaypoint(i, SecondPortalTrashWPs1[i][0] + irand(-1, 1), SecondPortalTrashWPs1[i][1] + irand(-1, 1), SecondPortalTrashWPs1[i][2], 0);
|
||||
me->SetHomePosition(SecondPortalTrashWPs1[8][0] + irand(-1, 1), SecondPortalTrashWPs1[8][1] + irand(-1, 1), SecondPortalTrashWPs1[8][2] + irand(-1, 1), 3.149439f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
AddWaypoint(i, SecondPortalTrashWPs2[i][0] + irand(-1, 1), SecondPortalTrashWPs2[i][1] + irand(-1, 1), SecondPortalTrashWPs2[i][2], 0);
|
||||
me->SetHomePosition(SecondPortalTrashWPs2[7][0], SecondPortalTrashWPs2[7][1], SecondPortalTrashWPs2[7][2], 3.149439f);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < 8; i++)
|
||||
AddWaypoint(i, ThirdPortalTrashWPs[i][0] + irand(-1, 1), ThirdPortalTrashWPs[i][1] + irand(-1, 1), ThirdPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(ThirdPortalTrashWPs[7][0], ThirdPortalTrashWPs[7][1], ThirdPortalTrashWPs[7][2], 3.149439f);
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < 9; i++)
|
||||
AddWaypoint(i, FourthPortalTrashWPs[i][0] + irand(-1, 1), FourthPortalTrashWPs[i][1] + irand(-1, 1), FourthPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(FourthPortalTrashWPs[8][0], FourthPortalTrashWPs[8][1], FourthPortalTrashWPs[8][2], 3.149439f);
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < 6; i++)
|
||||
AddWaypoint(i, FifthPortalTrashWPs[i][0] + irand(-1, 1), FifthPortalTrashWPs[i][1] + irand(-1, 1), FifthPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(FifthPortalTrashWPs[5][0], FifthPortalTrashWPs[5][1], FifthPortalTrashWPs[5][2], 3.149439f);
|
||||
break;
|
||||
case 5:
|
||||
for (int i = 0; i < 4; i++)
|
||||
AddWaypoint(i, SixthPoralTrashWPs[i][0] + irand(-1, 1), SixthPoralTrashWPs[i][1] + irand(-1, 1), SixthPoralTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(SixthPoralTrashWPs[3][0], SixthPoralTrashWPs[3][1], SixthPoralTrashWPs[3][2], 3.149439f);
|
||||
break;
|
||||
}
|
||||
SetDespawnAtEnd(false);
|
||||
Start(true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!AddedWaypoints)
|
||||
{
|
||||
AddedWaypoints = true;
|
||||
switch (PortalLoc)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < 6; i++)
|
||||
AddWaypoint(i, FirstPortalTrashWPs[i][0] + irand(-1, 1), FirstPortalTrashWPs[i][1] + irand(-1, 1), FirstPortalTrashWPs[i][2] + irand(-1, 1), 0);
|
||||
me->SetHomePosition(FirstPortalTrashWPs[5][0], FirstPortalTrashWPs[5][1], FirstPortalTrashWPs[5][2], 3.149439f);
|
||||
break;
|
||||
case 1:
|
||||
UseAlternate = (bool)urand(0, 1);
|
||||
if (!UseAlternate)
|
||||
{
|
||||
for (int i = 0; i < 9; i++)
|
||||
AddWaypoint(i, SecondPortalTrashWPs1[i][0] + irand(-1, 1), SecondPortalTrashWPs1[i][1] + irand(-1, 1), SecondPortalTrashWPs1[i][2], 0);
|
||||
me->SetHomePosition(SecondPortalTrashWPs1[8][0] + irand(-1, 1), SecondPortalTrashWPs1[8][1] + irand(-1, 1), SecondPortalTrashWPs1[8][2] + irand(-1, 1), 3.149439f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
AddWaypoint(i, SecondPortalTrashWPs2[i][0] + irand(-1, 1), SecondPortalTrashWPs2[i][1] + irand(-1, 1), SecondPortalTrashWPs2[i][2], 0);
|
||||
me->SetHomePosition(SecondPortalTrashWPs2[7][0], SecondPortalTrashWPs2[7][1], SecondPortalTrashWPs2[7][2], 3.149439f);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < 8; i++)
|
||||
AddWaypoint(i, ThirdPortalTrashWPs[i][0] + irand(-1, 1), ThirdPortalTrashWPs[i][1] + irand(-1, 1), ThirdPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(ThirdPortalTrashWPs[7][0], ThirdPortalTrashWPs[7][1], ThirdPortalTrashWPs[7][2], 3.149439f);
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < 9; i++)
|
||||
AddWaypoint(i, FourthPortalTrashWPs[i][0] + irand(-1, 1), FourthPortalTrashWPs[i][1] + irand(-1, 1), FourthPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(FourthPortalTrashWPs[8][0], FourthPortalTrashWPs[8][1], FourthPortalTrashWPs[8][2], 3.149439f);
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < 6; i++)
|
||||
AddWaypoint(i, FifthPortalTrashWPs[i][0] + irand(-1, 1), FifthPortalTrashWPs[i][1] + irand(-1, 1), FifthPortalTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(FifthPortalTrashWPs[5][0], FifthPortalTrashWPs[5][1], FifthPortalTrashWPs[5][2], 3.149439f);
|
||||
break;
|
||||
case 5:
|
||||
for (int i = 0; i < 4; i++)
|
||||
AddWaypoint(i, SixthPoralTrashWPs[i][0] + irand(-1, 1), SixthPoralTrashWPs[i][1] + irand(-1, 1), SixthPoralTrashWPs[i][2], 0);
|
||||
me->SetHomePosition(SixthPoralTrashWPs[3][0], SixthPoralTrashWPs[3][1], SixthPoralTrashWPs[3][2], 3.149439f);
|
||||
break;
|
||||
}
|
||||
SetDespawnAtEnd(false);
|
||||
Start(true);
|
||||
}
|
||||
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
}
|
||||
|
||||
@@ -302,7 +302,6 @@ struct violet_hold_trashAI : public npc_escortAI
|
||||
|
||||
protected:
|
||||
InstanceScript* Instance;
|
||||
bool AddedWaypoints;
|
||||
uint32 PortalLoc;
|
||||
bool UseAlternate;
|
||||
};
|
||||
@@ -834,7 +833,6 @@ struct npc_azure_saboteur : public npc_escortAI
|
||||
_boss = _instance->GetData(DATA_WAVE_COUNT) == 6
|
||||
? _instance->GetPersistentData(PERSISTENT_DATA_FIRST_BOSS)
|
||||
: _instance->GetPersistentData(PERSISTENT_DATA_SECOND_BOSS);
|
||||
_addedWaypoints = false;
|
||||
_isOpening = false;
|
||||
}
|
||||
|
||||
@@ -870,48 +868,49 @@ struct npc_azure_saboteur : public npc_escortAI
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
npc_escortAI::InitializeAI();
|
||||
|
||||
switch (_boss)
|
||||
{
|
||||
case BOSS_MORAGG:
|
||||
for (int i = 0; i < 3; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos1[i][0], SaboteurFinalPos1[i][1], SaboteurFinalPos1[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos1[2][0], SaboteurFinalPos1[2][1], SaboteurFinalPos1[2][2], 4.762346f);
|
||||
break;
|
||||
case BOSS_EREKEM:
|
||||
for (int i = 0; i < 3; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos2[i][0], SaboteurFinalPos2[i][1], SaboteurFinalPos2[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos2[2][0], SaboteurFinalPos2[2][1], SaboteurFinalPos2[2][2], 1.862674f);
|
||||
break;
|
||||
case BOSS_ICHORON:
|
||||
for (int i = 0; i < 2; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos3[i][0], SaboteurFinalPos3[i][1], SaboteurFinalPos3[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos3[1][0], SaboteurFinalPos3[1][1], SaboteurFinalPos3[1][2], 5.500638f);
|
||||
break;
|
||||
case BOSS_LAVANTHOR:
|
||||
AddWaypoint(0, SaboteurFinalPos4[0], SaboteurFinalPos4[1], SaboteurFinalPos4[2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos4[0], SaboteurFinalPos4[1], SaboteurFinalPos4[2], 3.991108f);
|
||||
break;
|
||||
case BOSS_XEVOZZ:
|
||||
AddWaypoint(0, SaboteurFinalPos5[0], SaboteurFinalPos5[1], SaboteurFinalPos5[2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos5[0], SaboteurFinalPos5[1], SaboteurFinalPos5[2], 1.100841f);
|
||||
break;
|
||||
case BOSS_ZURAMAT:
|
||||
for (int i = 0; i < 5; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos6[i][0], SaboteurFinalPos6[i][1], SaboteurFinalPos6[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos6[4][0], SaboteurFinalPos6[4][1], SaboteurFinalPos6[4][2], 0.983031f);
|
||||
break;
|
||||
}
|
||||
SetDespawnAtEnd(false);
|
||||
Start(true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
|
||||
if (!_addedWaypoints)
|
||||
{
|
||||
_addedWaypoints = true;
|
||||
switch (_boss)
|
||||
{
|
||||
case BOSS_MORAGG:
|
||||
for (int i = 0; i < 3; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos1[i][0], SaboteurFinalPos1[i][1], SaboteurFinalPos1[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos1[2][0], SaboteurFinalPos1[2][1], SaboteurFinalPos1[2][2], 4.762346f);
|
||||
break;
|
||||
case BOSS_EREKEM:
|
||||
for (int i = 0; i < 3; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos2[i][0], SaboteurFinalPos2[i][1], SaboteurFinalPos2[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos2[2][0], SaboteurFinalPos2[2][1], SaboteurFinalPos2[2][2], 1.862674f);
|
||||
break;
|
||||
case BOSS_ICHORON:
|
||||
for (int i = 0; i < 2; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos3[i][0], SaboteurFinalPos3[i][1], SaboteurFinalPos3[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos3[1][0], SaboteurFinalPos3[1][1], SaboteurFinalPos3[1][2], 5.500638f);
|
||||
break;
|
||||
case BOSS_LAVANTHOR:
|
||||
AddWaypoint(0, SaboteurFinalPos4[0], SaboteurFinalPos4[1], SaboteurFinalPos4[2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos4[0], SaboteurFinalPos4[1], SaboteurFinalPos4[2], 3.991108f);
|
||||
break;
|
||||
case BOSS_XEVOZZ:
|
||||
AddWaypoint(0, SaboteurFinalPos5[0], SaboteurFinalPos5[1], SaboteurFinalPos5[2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos5[0], SaboteurFinalPos5[1], SaboteurFinalPos5[2], 1.100841f);
|
||||
break;
|
||||
case BOSS_ZURAMAT:
|
||||
for (int i = 0; i < 5; i++)
|
||||
AddWaypoint(i, SaboteurFinalPos6[i][0], SaboteurFinalPos6[i][1], SaboteurFinalPos6[i][2], 0);
|
||||
me->SetHomePosition(SaboteurFinalPos6[4][0], SaboteurFinalPos6[4][1], SaboteurFinalPos6[4][2], 0.983031f);
|
||||
break;
|
||||
}
|
||||
SetDespawnAtEnd(false);
|
||||
Start(true);
|
||||
}
|
||||
|
||||
if (_isOpening)
|
||||
{
|
||||
_events.Update(diff);
|
||||
@@ -951,7 +950,6 @@ struct npc_azure_saboteur : public npc_escortAI
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
bool _addedWaypoints;
|
||||
uint8 _boss;
|
||||
bool _isOpening;
|
||||
EventMap _events;
|
||||
|
||||
@@ -1089,6 +1089,24 @@ class spell_shango_tracks : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 51036 - Summon Venture Co. Pilot
|
||||
class spell_venture_pilot_summon : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_venture_pilot_summon);
|
||||
|
||||
void SetDest(SpellDestination& dest)
|
||||
{
|
||||
// Spawn to the right of the caster at flight altitude (negative Y = right in local coords)
|
||||
Position const offset = { 0.0f, -10.0f, 0.0f, 0.0f };
|
||||
dest.RelocateOffset(offset);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_venture_pilot_summon::SetDest, EFFECT_0, TARGET_DEST_CASTER);
|
||||
}
|
||||
};
|
||||
|
||||
enum ReturnedSevenfold
|
||||
{
|
||||
SPELL_FREYAS_WARD = 51845,
|
||||
@@ -1138,4 +1156,5 @@ void AddSC_sholazar_basin()
|
||||
RegisterSpellScript(spell_shango_tracks);
|
||||
|
||||
RegisterSpellScript(spell_q12611_deathbolt);
|
||||
RegisterSpellScript(spell_venture_pilot_summon);
|
||||
}
|
||||
|
||||
@@ -1290,6 +1290,73 @@ struct npc_oathbound_warder : public ScriptedAI
|
||||
}
|
||||
};
|
||||
|
||||
class spell_q13010_jokkum_summon : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q13010_jokkum_summon);
|
||||
|
||||
void HandleSummon(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
Player* player = caster->ToPlayer();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
if (player->IsInDisallowedMountForm())
|
||||
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
|
||||
|
||||
uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue);
|
||||
SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetSpellInfo()->Effects[effIndex].MiscValueB));
|
||||
uint32 duration = uint32(GetSpellInfo()->GetDuration());
|
||||
|
||||
Position pos = caster->GetPosition();
|
||||
if (Creature* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id))
|
||||
{
|
||||
uint32 spellId = GetSpellInfo()->Effects[EFFECT_0].CalcValue();
|
||||
caster->CastSpell(summon, spellId, true);
|
||||
|
||||
if (summon->IsImmuneToNPC())
|
||||
summon->SetDisableGravity(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHit += SpellEffectFn(spell_q13010_jokkum_summon::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
|
||||
}
|
||||
};
|
||||
|
||||
enum KingJokkum
|
||||
{
|
||||
NPC_KING_JOKKUM = 30331
|
||||
};
|
||||
|
||||
class spell_riding_jokkum : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_riding_jokkum);
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* charm = GetUnitOwner()->GetCharm();
|
||||
if (!charm || charm->GetEntry() != NPC_KING_JOKKUM)
|
||||
return;
|
||||
|
||||
Creature* summoned = charm->ToCreature();
|
||||
if (!summoned)
|
||||
return;
|
||||
|
||||
AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode();
|
||||
if (removeMode == AURA_REMOVE_BY_CANCEL)
|
||||
summoned->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_riding_jokkum::HandleEffectRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_storm_peaks()
|
||||
{
|
||||
RegisterCreatureAI(npc_frosthound);
|
||||
@@ -1316,4 +1383,6 @@ void AddSC_storm_peaks()
|
||||
RegisterSpellScript(spell_fatal_strike);
|
||||
RegisterSpellScript(spell_player_mount_wyrm);
|
||||
RegisterSpellScript(spell_eject_passenger_wild_wyrm);
|
||||
RegisterSpellScript(spell_q13010_jokkum_summon);
|
||||
RegisterSpellScript(spell_riding_jokkum);
|
||||
}
|
||||
|
||||
@@ -304,11 +304,11 @@ struct npc_frozen_core : public ScriptedAI
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* ahune = _instance->GetCreature(DATA_AHUNE))
|
||||
Unit::Kill(me, ahune);
|
||||
|
||||
DoCastSelf(SPELL_SUMMON_LOOT_MISSILE, true);
|
||||
DoCastSelf(SPELL_MINION_DESPAWNER, true);
|
||||
|
||||
if (Creature* ahune = _instance->GetCreature(DATA_AHUNE))
|
||||
Unit::Kill(me, ahune);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
sServerMailMgr->SendServerMail(
|
||||
session->GetPlayer(),
|
||||
servMail.id,
|
||||
servMail.senderEntry,
|
||||
money,
|
||||
items,
|
||||
conditions,
|
||||
|
||||
Reference in New Issue
Block a user