Merge pull request #224 from mod-playerbots/test-staging

Test staging
This commit is contained in:
Keleborn
2026-07-03 09:02:05 -07:00
committed by GitHub
43 changed files with 770 additions and 244 deletions
@@ -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\'');
+105
View File
@@ -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
View File
@@ -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
+26 -10
View File
@@ -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
+14 -3
View File
@@ -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
+3 -1
View File
@@ -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);
}
}
+8 -2
View File
@@ -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;
+23 -23
View File
@@ -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
+1 -1
View File
@@ -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).
+30 -8
View File
@@ -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;
+1 -1
View File
@@ -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;
+45 -22
View File
@@ -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();
}
+4
View File
@@ -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;
+8 -8
View File
@@ -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);
+2 -2
View File
@@ -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))
+1 -1
View File
@@ -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
+18 -9
View File
@@ -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);
+3 -1
View File
@@ -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];
+8
View File
@@ -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
+1
View File
@@ -58,6 +58,7 @@ public:
sServerMailMgr->SendServerMail(
session->GetPlayer(),
servMail.id,
servMail.senderEntry,
money,
items,
conditions,