Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-09-29 23:22:47 +08:00
74 changed files with 806 additions and 146 deletions
+6 -1
View File
@@ -31,7 +31,8 @@ def parsing_file(directory: str) -> None:
multiple_blank_lines_check(file, file_path) multiple_blank_lines_check(file, file_path)
trailing_whitespace_check(file, file_path) trailing_whitespace_check(file, file_path)
get_counter_check(file, file_path) get_counter_check(file, file_path)
misc_codestyle_check(file, file_path) if not file_name.endswith('.cmake') and file_name != 'CMakeLists.txt':
misc_codestyle_check(file, file_path)
if file_name != 'Object.h': if file_name != 'Object.h':
get_typeid_check(file, file_path) get_typeid_check(file, file_path)
if file_name != 'Unit.h': if file_name != 'Unit.h':
@@ -223,6 +224,10 @@ def misc_codestyle_check(file: io, file_path: str) -> None:
print( print(
f"Please use the syntax 'Class/ObjectType const*' instead of 'const Class/ObjectType*': {file_path} at line {line_number}") f"Please use the syntax 'Class/ObjectType const*' instead of 'const Class/ObjectType*': {file_path} at line {line_number}")
check_failed = True check_failed = True
if [match for match in [' if(', ' if ( '] if match in line]:
print(
f"AC have as standard: if (XXXX). Please check spaces in your condition': {file_path} at line {line_number}")
check_failed = True
# Handle the script error and update the result output # Handle the script error and update the result output
if check_failed: if check_failed:
error_handler = True error_handler = True
@@ -0,0 +1,4 @@
-- DB update 2024_09_22_02 -> 2024_09_22_03
UPDATE `item_template` SET `BuyCount` = 20 WHERE (`entry` = 32453);
UPDATE `item_template` SET `BuyCount` = 5 WHERE (`entry` = 32455);
@@ -0,0 +1,27 @@
-- DB update 2024_09_22_03 -> 2024_09_23_00
-- Bug Report #19575
-- Unlink from engineering quest chain:
-- 3638 (Goblin Engineering - Pledge of Secrecy)
-- 3640 (gnome engineering - pledge of secrecy, alliance)
-- 3642 (gnome engineering - pledge of secrecy, horde)
UPDATE `quest_template` SET `RewardNextQuest`=0 WHERE `ID`=3638 OR `ID`=3640 OR `ID`=3642;
UPDATE `quest_template` SET `RewardNextQuest`=3639 WHERE `ID`=3526 OR `ID`=3629 OR `ID`=3633 OR `ID`=4181;
UPDATE `quest_template` SET `RewardNextQuest`=3641 WHERE `ID`=3630 OR `ID`=3632 OR `ID`=3634;
UPDATE `quest_template` SET `RewardNextQuest`=3643 WHERE `ID`=3635 OR `ID`=3637;
-- Remove Pledge of Secrecy from creature_queststarter
DELETE FROM `creature_queststarter` WHERE `quest`=3638 OR `quest`=3640 OR `quest`=3642;
-- Remove Pledge of Secrecy from creature_questender
DELETE FROM `creature_questender` WHERE `quest`=3638 OR `quest`=3640 OR `quest`=3642;
-- Link quests together:
-- 3526, 3629, 3633, 4181 (Goblin Engineering) -> 3639 (Goblin Engineering - Show Your Work)
UPDATE `quest_template_addon` SET `PrevQuestID`=3633 WHERE `ID`=3639;
UPDATE `quest_template_addon` SET `NextQuestID`=3639 WHERE `ID`=3526 OR `ID`=3629 OR `ID`=3633 OR `ID`=4181;
-- 3630, 3632, 3634 (Gnome Engineering - Alliance) -> 3641 (Gnome Engineering - Show Your Work - Alliance)
UPDATE `quest_template_addon` SET `PrevQuestID`=3634 WHERE `ID`=3641;
UPDATE `quest_template_addon` SET `NextQuestID`=3641 WHERE `ID`=3630 OR `ID`=3632 OR `ID`=3634;
-- 3635, 3637 (Gnome Engineering - Horde) -> 3643 (Gnome Engineering - Show Your Work - Horde)
UPDATE `quest_template_addon` SET `PrevQuestID`=3635 WHERE `ID`=3643;
UPDATE `quest_template_addon` SET `NextQuestID`=3643 WHERE `ID`=3635 OR `ID`=3637;
@@ -0,0 +1,9 @@
-- DB update 2024_09_23_00 -> 2024_09_23_01
--
DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_item_skyguard_blasting_charges';
INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
(39844, 'spell_item_skyguard_blasting_charges');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 39844) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 30) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 185549) AND (`ConditionValue2` = 30) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(17, 0, 39844, 0, 0, 30, 0, 185549, 30, 0, 0, 0, 0, '', ' Launch a blasting charge from your flying mount at monstrous kaliri eggs.');
@@ -0,0 +1,12 @@
-- DB update 2024_09_23_01 -> 2024_09_23_02
-- Updating loot for Hound of Culuthas (Entry: 20141)
DELETE FROM `creature_loot_template` WHERE `Entry` = 20141 AND `Item` IN (25418, 25421);
INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(20141, 25418, 0, 80, 0, 1, 2, 1, 1, 'Hound of Culuthas - Razor Sharp Fang'),
(20141, 25421, 0, 0, 0, 1, 2, 1, 1, 'Hound of Culuthas - Gnarled Claw');
-- Updating loot for Eye of Culuthas (Entry: 20394)
DELETE FROM `creature_loot_template` WHERE `Entry` = 20394 AND `Item` IN (29799, 29800);
INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(20394, 29799, 0, 80, 0, 1, 2, 1, 1, 'Eye of Culuthas - Lifeless Tendril'),
(20394, 29800, 0, 0, 0, 1, 2, 1, 1, 'Eye of Culuthas - Evil Eye');
+178
View File
@@ -0,0 +1,178 @@
-- DB update 2024_09_23_02 -> 2024_09_24_00
--
-- Boat summoners
SET @GUID := 52030;
DELETE FROM `creature` WHERE `id1` IN (37964,37981,36817) AND (`guid` BETWEEN @GUID AND @GUID+2);
INSERT INTO `creature` (`guid`, `id1`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `VerifiedBuild`) VALUES
(@GUID, 37964, 0, 0, 0, 1, 1, 0, 1484.662, 348.019, -64.54687, 0.8377581, 120, 0, 0, 1, 0, 0, 0, 0, 0, 0),
(@GUID+1, 37981, 1, 0, 0, 1, 1, 0, 9843.134, 2430.733, 1313.6, 5.5676, 120, 0, 0, 1, 0, 0, 0, 0, 0, 0),
(@GUID+2, 36817, 0, 0, 0, 1, 1, 0, -8796.021, 775.0364, 95.22309, 0.01745329, 120, 0, 0, 1, 0, 0, 0, 0, 0, 0);
DELETE FROM `game_event_creature` WHERE `eventEntry`=8 AND `guid` BETWEEN @GUID AND @GUID+2;
INSERT INTO `game_event_creature` (`eventEntry`, `guid`) VALUES
(8, @GUID),
(8, @GUID+1),
(8, @GUID+2);
UPDATE `creature_template` SET `npcflag`=16777216,`VehicleId`=616,`IconName`='vehichleCursor' WHERE `entry`=37966;
UPDATE `creature_template` SET `npcflag`=16777216,`VehicleId`=615,`IconName`='vehichleCursor' WHERE `entry`=37980;
UPDATE `creature_template` SET `npcflag`=16777216,`VehicleId`=548,`IconName`='vehichleCursor' WHERE `entry`=36812;
-- trigger NPC, make invisible to players
UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 128 WHERE (`entry` IN (36817, 37964, 37981));
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (37966,37964,37981,37980,36817,36812);
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (37966,37964,37980,37981,36817,36812) AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `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
(36812, 0, 0, 0, 1, 0, 100, 1, 5000, 5000, 0, 0, 0, 0, 53, 0, 36812, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - Out of Combat - Start Waypoint Path 36812 (No Repeat)'),
(36812, 0, 1, 2, 40, 0, 100, 0, 21, 36812, 0, 0, 0, 0, 11, 50630, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Point 21 of Path 36812 Reached - Cast \'Eject All Passengers\''),
(36812, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Point 21 of Path 36812 Reached - Despawn In 2000 ms'),
(36812, 0, 3, 4, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 70143, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Just Summoned - Cast \'Vehicle Test\''),
(36812, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Just Summoned - Set Active On'),
(36812, 0, 5, 0, 1, 0, 100, 0, 0, 0, 3000, 3000, 0, 0, 75, 69341, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - Out of Combat - Add Aura \'Love Boat\''),
(36812, 0, 6, 0, 23, 0, 100, 0, 69342, 2, 1000, 1000, 0, 0, 75, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Aura \'Ride Vehicle\' - Add Aura \'Romantic\''),
(36812, 0, 7, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 28, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Stormwind Love Boat - On Passenger Removed - Remove Aura \'Romantic\''),
(37966, 0, 0, 0, 1, 0, 100, 1, 5000, 5000, 0, 0, 0, 0, 53, 0, 37966, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - Out of Combat - Start Waypoint Path 37966 (No Repeat)'),
(37966, 0, 1, 2, 40, 0, 100, 0, 31, 37966, 0, 0, 0, 0, 11, 50630, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Point 31 of Path 37966 Reached - Cast \'Eject All Passengers\''),
(37966, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Point 31 of Path 37966 Reached - Despawn In 2000 ms'),
(37966, 0, 3, 4, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 70143, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Just Summoned - Cast \'Vehicle Test\''),
(37966, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Just Summoned - Set Active On'),
(37966, 0, 5, 0, 1, 0, 100, 0, 0, 0, 3000, 3000, 0, 0, 75, 69341, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - Out of Combat - Add Aura \'Love Boat\''),
(37966, 0, 6, 0, 23, 0, 100, 0, 69342, 2, 1000, 1000, 0, 0, 75, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Aura \'Ride Vehicle\' - Add Aura \'Romantic\''),
(37966, 0, 7, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 28, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Undercity Love Boat - On Passenger Removed - Remove Aura \'Romantic\''),
(37980, 0, 0, 0, 1, 0, 100, 1, 5000, 5000, 0, 0, 0, 0, 53, 0, 37980, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - Out of Combat - Start Waypoint Path 37980 (No Repeat)'),
(37980, 0, 1, 2, 40, 0, 100, 0, 60, 37980, 0, 0, 0, 0, 11, 50630, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Point 60 of Path 37980 Reached - Cast \'Eject All Passengers\''),
(37980, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Point 60 of Path 37980 Reached - Despawn In 2000 ms'),
(37980, 0, 3, 4, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 70143, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Just Summoned - Cast \'Vehicle Test\''),
(37980, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Just Summoned - Set Active On'),
(37980, 0, 5, 0, 1, 0, 100, 0, 0, 0, 3000, 3000, 0, 0, 75, 69341, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - Out of Combat - Add Aura \'Love Boat\''),
(37980, 0, 6, 0, 23, 0, 100, 0, 69342, 2, 1000, 1000, 0, 0, 75, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Aura \'Ride Vehicle\' - Add Aura \'Romantic\''),
(37980, 0, 7, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 28, 69352, 0, 0, 0, 0, 0, 17, 0, 20, 0, 0, 0, 0, 0, 0, 'Darnassus Love Boat - On Passenger Removed - Remove Aura \'Romantic\''),
(36817, 0, 0, 0, 1, 0, 100, 0, 0, 0, 20000, 20000, 0, 0, 11, 69371, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner - Out of Combat - Cast \'Love Boat Summon\''),
(36817, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner - On Respawn - Set Active On'),
(37964, 0, 0, 0, 1, 0, 100, 0, 0, 0, 20000, 20000, 0, 0, 11, 70846, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner 02 - Out of Combat - Cast \'Love Boat Summon\''),
(37964, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner 02 - On Respawn - Set Active On'),
(37981, 0, 0, 0, 1, 0, 100, 0, 0, 0, 20000, 20000, 0, 0, 11, 70863, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner 03 - Out of Combat - Cast \'Love Boat Summon\''),
(37981, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '[DND] Love Boat Summoner 03 - On Respawn - Set Active On');
DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (37966,37980,36812);
INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES
(37966, 69342, 1, 0),
(37980, 69342, 1, 0),
(36812, 69342, 1, 0);
DELETE FROM `waypoints` WHERE `entry` IN (37966,37980,36812);
INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES
(37966, 1, 1485.332, 348.7621, -64.54687, 'Undercity Love Boat'),
(37966, 2, 1487.063, 350.9445, -64.86743, 'Undercity Love Boat'),
(37966, 3, 1494.434, 360.592, -64.86742, 'Undercity Love Boat'),
(37966, 4, 1505.792, 368.026, -64.81186, 'Undercity Love Boat'),
(37966, 5, 1520.413, 376.7361, -64.81187, 'Undercity Love Boat'),
(37966, 6, 1542.724, 389.7309, -64.81187, 'Undercity Love Boat'),
(37966, 7, 1555.352, 393.1875, -64.81187, 'Undercity Love Boat'),
(37966, 8, 1577.076, 397.1563, -64.81187, 'Undercity Love Boat'),
(37966, 9, 1618.071, 395.9705, -64.81187, 'Undercity Love Boat'),
(37966, 10, 1642.727, 391.0139, -64.81187, 'Undercity Love Boat'),
(37966, 11, 1685.007, 370.4167, -64.81187, 'Undercity Love Boat'),
(37966, 12, 1711.104, 350.4514, -64.81187, 'Undercity Love Boat'),
(37966, 13, 1738.417, 310.0278, -64.81187, 'Undercity Love Boat'),
(37966, 14, 1746.345, 286.441, -64.81187, 'Undercity Love Boat'),
(37966, 15, 1752.087, 240.5399, -64.81187, 'Undercity Love Boat'),
(37966, 16, 1750.016, 206.7309, -64.81187, 'Undercity Love Boat'),
(37966, 17, 1737.47, 167.8559, -64.81187, 'Undercity Love Boat'),
(37966, 18, 1707.885, 128.5122, -64.81187, 'Undercity Love Boat'),
(37966, 19, 1667.977, 99.80035, -64.81187, 'Undercity Love Boat'),
(37966, 20, 1624.948, 85.43229, -64.81187, 'Undercity Love Boat'),
(37966, 21, 1583.814, 83.33507, -64.81187, 'Undercity Love Boat'),
(37966, 22, 1539.444, 94.43403, -64.81187, 'Undercity Love Boat'),
(37966, 23, 1502.849, 114.3142, -64.81187, 'Undercity Love Boat'),
(37966, 24, 1482.955, 132.6806, -64.81187, 'Undercity Love Boat'),
(37966, 25, 1456.214, 170.0521, -64.81187, 'Undercity Love Boat'),
(37966, 26, 1441.738, 207.8819, -64.81187, 'Undercity Love Boat'),
(37966, 27, 1438.825, 244.4427, -64.81187, 'Undercity Love Boat'),
(37966, 28, 1450.882, 299.3177, -64.81187, 'Undercity Love Boat'),
(37966, 29, 1462.38, 320.4583, -64.81187, 'Undercity Love Boat'),
(37966, 30, 1467.97, 333.1337, -64.81187, 'Undercity Love Boat'),
(37966, 31, 1471.193, 337.8559, -64.81187, 'Undercity Love Boat'),
(37980, 1, 9843.134, 2430.733, 1313.6, 'Darnassus Love Boat'),
(37980, 2, 9847.023, 2427.627, 1313.516, 'Darnassus Love Boat'),
(37980, 3, 9856.224, 2423.156, 1313.516, 'Darnassus Love Boat'),
(37980, 4, 9871.393, 2416.719, 1313.516, 'Darnassus Love Boat'),
(37980, 5, 9888.688, 2408.337, 1313.516, 'Darnassus Love Boat'),
(37980, 6, 9901.832, 2399.545, 1313.516, 'Darnassus Love Boat'),
(37980, 7, 9915.912, 2390.616, 1313.516, 'Darnassus Love Boat'),
(37980, 8, 9930.722, 2381.382, 1313.516, 'Darnassus Love Boat'),
(37980, 9, 9946.339, 2377.861, 1313.516, 'Darnassus Love Boat'),
(37980, 10, 9964.972, 2377.967, 1313.516, 'Darnassus Love Boat'),
(37980, 11, 9977.46, 2379.141, 1313.516, 'Darnassus Love Boat'),
(37980, 12, 9989.397, 2375.556, 1313.516, 'Darnassus Love Boat'),
(37980, 13, 10006.68, 2364.491, 1313.516, 'Darnassus Love Boat'),
(37980, 14, 10022.01, 2353.608, 1313.516, 'Darnassus Love Boat'),
(37980, 15, 10031.78, 2353.427, 1313.516, 'Darnassus Love Boat'),
(37980, 16, 10041.6, 2366.207, 1313.516, 'Darnassus Love Boat'),
(37980, 17, 10043.1, 2373.267, 1313.516, 'Darnassus Love Boat'),
(37980, 18, 10040.94, 2384.248, 1313.516, 'Darnassus Love Boat'),
(37980, 19, 10040.11, 2396.392, 1313.516, 'Darnassus Love Boat'),
(37980, 20, 10043.54, 2406.759, 1313.516, 'Darnassus Love Boat'),
(37980, 21, 10051.08, 2414.868, 1313.516, 'Darnassus Love Boat'),
(37980, 22, 10059.58, 2421.014, 1313.516, 'Darnassus Love Boat'),
(37980, 23, 10061.45, 2433.856, 1313.516, 'Darnassus Love Boat'),
(37980, 24, 10056.65, 2445.88, 1313.516, 'Darnassus Love Boat'),
(37980, 25, 10049.1, 2453.844, 1313.516, 'Darnassus Love Boat'),
(37980, 26, 10039.64, 2458.193, 1313.516, 'Darnassus Love Boat'),
(37980, 27, 10030.21, 2461.353, 1313.516, 'Darnassus Love Boat'),
(37980, 28, 10013.85, 2465.007, 1313.516, 'Darnassus Love Boat'),
(37980, 29, 10007.3, 2472.648, 1313.516, 'Darnassus Love Boat'),
(37980, 30, 10001.77, 2490.97, 1313.516, 'Darnassus Love Boat'),
(37980, 31, 10007.02, 2503.859, 1313.516, 'Darnassus Love Boat'),
(37980, 32, 10014.66, 2519.925, 1313.516, 'Darnassus Love Boat'),
(37980, 33, 10022.5, 2532.248, 1313.516, 'Darnassus Love Boat'),
(37980, 34, 10032.06, 2559.106, 1313.516, 'Darnassus Love Boat'),
(37980, 35, 10032.88, 2579.188, 1313.516, 'Darnassus Love Boat'),
(37980, 36, 10032.36, 2598.909, 1313.516, 'Darnassus Love Boat'),
(37980, 37, 10029.7, 2612.815, 1313.516, 'Darnassus Love Boat'),
(37980, 38, 10022.64, 2648.693, 1313.516, 'Darnassus Love Boat'),
(37980, 39, 9999.638, 2667.306, 1313.516, 'Darnassus Love Boat'),
(37980, 40, 9985.304, 2673.353, 1313.516, 'Darnassus Love Boat'),
(37980, 41, 9967.442, 2671.7, 1313.516, 'Darnassus Love Boat'),
(37980, 42, 9938.718, 2668.114, 1313.516, 'Darnassus Love Boat'),
(37980, 43, 9898.393, 2665.895, 1313.516, 'Darnassus Love Boat'),
(37980, 44, 9874.026, 2660.383, 1313.516, 'Darnassus Love Boat'),
(37980, 45, 9848.894, 2657.903, 1313.516, 'Darnassus Love Boat'),
(37980, 46, 9834.57, 2658.452, 1313.516, 'Darnassus Love Boat'),
(37980, 47, 9820.689, 2652.576, 1313.516, 'Darnassus Love Boat'),
(37980, 48, 9802.497, 2636.835, 1313.516, 'Darnassus Love Boat'),
(37980, 49, 9795.239, 2622.99, 1313.516, 'Darnassus Love Boat'),
(37980, 50, 9785.92, 2605.789, 1313.516, 'Darnassus Love Boat'),
(37980, 51, 9784.899, 2593.911, 1313.516, 'Darnassus Love Boat'),
(37980, 52, 9793.405, 2574.175, 1313.516, 'Darnassus Love Boat'),
(37980, 53, 9812.471, 2555.666, 1313.516, 'Darnassus Love Boat'),
(37980, 54, 9829.779, 2539.537, 1313.516, 'Darnassus Love Boat'),
(37980, 55, 9841.714, 2520.574, 1313.516, 'Darnassus Love Boat'),
(37980, 56, 9847.395, 2499.439, 1313.516, 'Darnassus Love Boat'),
(37980, 57, 9850.591, 2481.936, 1313.516, 'Darnassus Love Boat'),
(37980, 58, 9846.033, 2466.465, 1313.516, 'Darnassus Love Boat'),
(37980, 59, 9838.938, 2451.995, 1313.516, 'Darnassus Love Boat'),
(37980, 60, 9833.917, 2446.236, 1313.516, 'Darnassus Love Boat'),
(36812, 1, -8795.021, 775.0364, 95.22309, 'Stormwind Love Boat'),
(36812, 2, -8791.573, 776.316, 95.0583, 'Stormwind Love Boat'),
(36812, 3, -8783.189, 778.1111, 95.0583, 'Stormwind Love Boat'),
(36812, 4, -8769.04, 777.9063, 95.0583, 'Stormwind Love Boat'),
(36812, 5, -8757.161, 764.092, 95.0583, 'Stormwind Love Boat'),
(36812, 6, -8750.976, 741.6354, 95.08608, 'Stormwind Love Boat'),
(36812, 7, -8733.618, 717.3299, 95.08608, 'Stormwind Love Boat'),
(36812, 8, -8717.854, 698.5886, 95.0583, 'Stormwind Love Boat'),
(36812, 9, -8698.192, 662.2465, 95.0583, 'Stormwind Love Boat'),
(36812, 10, -8688.56, 630.1719, 95.11386, 'Stormwind Love Boat'),
(36812, 11, -8696.212, 596.9983, 95.08608, 'Stormwind Love Boat'),
(36812, 12, -8702.024, 577.2761, 95.0583, 'Stormwind Love Boat'),
(36812, 13, -8691.561, 565.0538, 95.0583, 'Stormwind Love Boat'),
(36812, 14, -8671.857, 565.382, 95.0583, 'Stormwind Love Boat'),
(36812, 15, -8646.634, 563.7743, 95.0583, 'Stormwind Love Boat'),
(36812, 16, -8631.895, 554.441, 95.0583, 'Stormwind Love Boat'),
(36812, 17, -8618.281, 557.4114, 95.0583, 'Stormwind Love Boat'),
(36812, 18, -8608.049, 577.191, 95.0583, 'Stormwind Love Boat'),
(36812, 19, -8602.768, 595.4983, 95.0583, 'Stormwind Love Boat'),
(36812, 20, -8594.357, 623.566, 95.0583, 'Stormwind Love Boat'),
(36812, 21, -8581.717, 629.7882, 95.08608, 'Stormwind Love Boat');
@@ -0,0 +1,5 @@
-- DB update 2024_09_24_00 -> 2024_09_24_01
--
DELETE FROM `spell_script_names` WHERE `spell_id` = 36092;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(36092, 'spell_kaelthas_kael_explodes');
@@ -0,0 +1,3 @@
-- DB update 2024_09_24_01 -> 2024_09_25_00
--
UPDATE `creature_template` SET `flags_extra` = `flags_extra`|512 WHERE `entry` = 22917;
@@ -0,0 +1,30 @@
-- DB update 2024_09_25_00 -> 2024_09_25_01
--
DELETE FROM `smart_scripts` WHERE `entryorguid`=24077 AND `source_type`=0;
DELETE FROM `smart_scripts` WHERE `entryorguid`=2407700 AND `source_type`=9;
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
(24077, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 186565, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Repawn - Summon Ceremonial Dragonflayer Harpoon'),
(24077, 0, 1, 0, 8, 0, 100, 1, 42968, 0, 0, 0, 0, 0, 80, 2407700, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On spell hit - Start Script'),
(2407700, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 99, 3, 0, 0, 0, 0, 0, 20, 186565, 10, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Set loot state'),
(2407700, 9, 1, 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, 'Impaled Valgarde Scout - On Script - Talk 0'),
(2407700, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 91, 255, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Remove Bytes '),
(2407700, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 90, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Set Bytes 1'),
(2407700, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Talk 1'),
(2407700, 9, 5, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Kill Self'),
(2407700, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Impaled Valgarde Scout - On Script - Despawn');
DELETE FROM `creature_text` WHERE `CreatureID`=24077;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(24077, 0, 0, '%s groans.', 16, 0, 100, 0, 0, 0, 22743, 0, 'Impaled Valgarde Scout'),
(24077, 0, 1, '%s screams in agony as the harpoon is removed.', 16, 0, 100, 0, 0, 0, 22744, 0, 'Impaled Valgarde Scout'),
(24077, 0, 2, '%s whimpers.', 16, 0, 100, 0, 0, 0, 22745, 0, 'Impaled Valgarde Scout'),
(24077, 1, 0, 'Don\'t let my death go unavenged, stranger... give ... them... hell...', 12, 0, 100, 0, 0, 0, 22752, 0, 'Impaled Valgarde Scout'),
(24077, 1, 1, 'I\'m done for... too much blood lost... Forget about me, tell Keller... People still alive inside...', 12, 0, 100, 0, 0, 0, 22749, 0, 'Impaled Valgarde Scout'),
(24077, 1, 2, 'Not... no... Our people... Wrymskull... some live...', 12, 0, 100, 0, 0, 0, 22747, 0, 'Impaled Valgarde Scout'),
(24077, 1, 3, 'My injuries are too great. I won\'t make it... Our citizenry held in cages... ritual...', 12, 0, 100, 0, 0, 0, 22748, 0, 'Impaled Valgarde Scout'),
(24077, 1, 4, 'They left us here impaled as a warning to the others... Several still alive... prisoners of...', 12, 0, 100, 0, 0, 0, 22751, 0, 'Impaled Valgarde Scout'),
(24077, 1, 5, 'My family must know... I... for them... always for them...', 12, 0, 100, 0, 0, 0, 22750, 0, 'Impaled Valgarde Scout');
DELETE FROM `gameobject` WHERE `id`=186565;
UPDATE `gameobject_template_locale` SET `castBarCaption`='Quitando' WHERE `entry`=186565 AND `locale` IN ('esES', 'esMX');
@@ -0,0 +1,54 @@
-- DB update 2024_09_25_01 -> 2024_09_25_02
--
UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 2048 WHERE `entry` IN (
3672, -- Boahn
4403, -- Muckshell Pincer
4540, -- Scarlet Monk
7033, -- Firegut Ogre
8218, -- Witherheart the Stalker
10478, -- Splintered Skeleton
10488, -- Risen Construct
11022, -- Alexi Barov
12100, -- Lava Reaver
12262, -- Ziggurat Protector
12263, -- Slaughterhouse Protector
14688, -- Prince Sandoval
14882, -- Atal'ai Mistress
16299, -- Skeletal Shocktrooper
16422, -- Skeletal Soldier
16593, -- Shattered Hand Brawler
16808, -- Warchief Kargath Bladefist
16936, -- Dreghood Wanderer
18120, -- Ango'rosh Mauler
18211, -- Murkblood Brute
18541, -- Urdak
18860, -- Daughter of Destiny
19191, -- Arazzius the Cruel
20456, -- Ethereum Researcher
20582, -- Shattered Hand Brawler (1)
20597, -- Warchief Kargath Bladefist (1)
20683, -- Prophetess Cavrylin
20783, -- Porfus the Gem Gorger
20784, -- Armbreaker Huffaz
20785, -- Fel Tinkerer Zortan
20786, -- Gul'bor
20790, -- Malevus the Mad
20929, -- Wrath Lord
20984, -- Protectorate Defender
21639, -- Illidari Slayer
21717, -- Dragonmaw Wrangler
21805, -- Protectorate Avenger
21877, -- Karsius the Ancient Watcher
22004, -- Leoroxx
22076, -- Torloth the Magnificent
22082, -- Shadowmoon Slayer
22199, -- Slaag
22377, -- Akuno
22825, -- Matron Li-sahar
23008, -- Ethereum Jailor
23410, -- Spirit of Udalo
23411, -- Spirit of Olum
24882, -- Brutallus
37132, -- Ymirjar Battle-Maiden
38132 -- Ymirjar Battle-Maiden (1)
);
@@ -0,0 +1,6 @@
-- DB update 2024_09_25_02 -> 2024_09_25_03
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 21806;
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 21806) AND (`source_type` = 0) AND (`id` IN (2));
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
(21806, 0, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 20, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Greyheart Spellbinder - In Combat - Call For Help');
@@ -0,0 +1,2 @@
-- DB update 2024_09_25_03 -> 2024_09_26_00
UPDATE `creature_template` SET `unit_flags` = `unit_flags`|33554432|32768|512|256 WHERE `entry` = 21812;
@@ -0,0 +1,15 @@
-- DB update 2024_09_26_00 -> 2024_09_27_00
--
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5316 WHERE `MenuID`=2849 AND `OptionID`=0;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=10359 WHERE `MenuID`=2849 AND `OptionID`=4;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=2870 WHERE `MenuID`=2849 AND `OptionID`=5;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=4895 WHERE `MenuID`=2849 AND `OptionID`=8;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=7253 WHERE `MenuID`=2849 AND `OptionID`=10;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5518 WHERE `MenuID`=2849 AND `OptionID`=11;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=5316 WHERE `MenuID`=7633 AND `OptionID`=0;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=2870 WHERE `MenuID`=7633 AND `OptionID`=3;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=4895 WHERE `MenuID`=7633 AND `OptionID`=5;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=7253 WHERE `MenuID`=7633 AND `OptionID`=7;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=2870 WHERE `MenuID`=8185 AND `OptionID`=1;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=4895 WHERE `MenuID`=8357 AND `OptionID`=4;
UPDATE `gossip_menu_option` SET `OptionBroadcastTextID`=10359 WHERE `MenuID`=8357 AND `OptionID`=6;
@@ -0,0 +1,11 @@
-- DB update 2024_09_27_00 -> 2024_09_28_00
--
UPDATE `creature_template` SET `flags_extra` = `flags_extra` & ~2048 WHERE `entry` IN (
3672, -- Boahn
20783, -- Porfus the Gem Gorger
21639, -- Illidari Slayer
21717, -- Dragonmaw Wrangler
12100, -- Lava Reaver
22076, -- Torloth the Magnificent
22004 -- Leoroxx
);
@@ -0,0 +1,3 @@
-- DB update 2024_09_28_00 -> 2024_09_28_01
--
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` & ~2048 WHERE (`entry` = 22056);
@@ -0,0 +1,3 @@
-- DB update 2024_09_28_01 -> 2024_09_28_02
DELETE FROM `skill_extra_item_template` WHERE `spellId` = 28551;
INSERT INTO `skill_extra_item_template` (`spellId`, `requiredSpecialization`, `additionalCreateChance`, `additionalMaxNum`) VALUES (28551, 28675, 14, 4);
@@ -3675,6 +3675,13 @@ Battleground.BerserkingBuffRespawn = 120
Battleground.SpeedBuffRespawn = 150 Battleground.SpeedBuffRespawn = 150
#
# Battleground.Override.LowLevels.MinPlayers
# Description: Overrides the minimum number of required players per team for all levels < MaxPlayerLevel
# Default: 0 (Disabled)
Battleground.Override.LowLevels.MinPlayers = 0
# #
################################################################################################### ###################################################################################################
@@ -188,7 +188,7 @@ bool MySQLConnection::Execute(std::string_view sql)
LOG_INFO("sql.sql", "SQL: {}", sql); LOG_INFO("sql.sql", "SQL: {}", sql);
LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql)); LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_error(m_Mysql))) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(sql); // Try again return Execute(sql); // Try again
return false; return false;
@@ -226,7 +226,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again return Execute(stmt); // Try again
m_mStmt->ClearParameters(); m_mStmt->ClearParameters();
@@ -238,7 +238,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again return Execute(stmt); // Try again
m_mStmt->ClearParameters(); m_mStmt->ClearParameters();
@@ -278,7 +278,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters(); m_mStmt->ClearParameters();
@@ -290,7 +290,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
uint32 lErrno = mysql_errno(m_Mysql); uint32 lErrno = mysql_errno(m_Mysql);
LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT)); LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters(); m_mStmt->ClearParameters();
@@ -338,7 +338,7 @@ bool MySQLConnection::_Query(std::string_view sql, MySQLResult** pResult, MySQLF
LOG_INFO("sql.sql", "SQL: {}", sql); LOG_INFO("sql.sql", "SQL: {}", sql);
LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql)); LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) if (_HandleMySQLErrno(lErrno, mysql_error(m_Mysql))) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again
return false; return false;
@@ -553,8 +553,9 @@ PreparedResultSet* MySQLConnection::Query(PreparedStatementBase* stmt)
return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount); return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
} }
bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, char const* err, uint8 attempts /*= 5*/)
{ {
std::string str = "";
switch (errNo) switch (errNo)
{ {
case CR_SERVER_GONE_ERROR: case CR_SERVER_GONE_ERROR:
@@ -582,9 +583,10 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
// Don't remove 'this' pointer unless you want to skip loading all prepared statements... // Don't remove 'this' pointer unless you want to skip loading all prepared statements...
if (!this->PrepareStatements()) if (!this->PrepareStatements())
{ {
LOG_FATAL("sql.sql", "Could not re-prepare statements!"); str = "Could not re-prepare statements!";
LOG_FATAL("sql.sql", "{}", str);
std::this_thread::sleep_for(10s); std::this_thread::sleep_for(10s);
ABORT(); ABORT("{}\n\n[{}] {}", str, errNo, err);
} }
LOG_INFO("sql.sql", "Successfully reconnected to {} @{}:{} ({}).", LOG_INFO("sql.sql", "Successfully reconnected to {} @{}:{} ({}).",
@@ -599,19 +601,21 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
{ {
// Shut down the server when the mysql server isn't // Shut down the server when the mysql server isn't
// reachable for some time // reachable for some time
LOG_FATAL("sql.sql", "Failed to reconnect to the MySQL server, terminating the server to prevent data corruption!"); str = "Failed to reconnect to the MySQL server, terminating the server to prevent data corruption!";
LOG_FATAL("sql.sql", "{}", str);
// We could also initiate a shutdown through using std::raise(SIGTERM) // We could also initiate a shutdown through using std::raise(SIGTERM)
std::this_thread::sleep_for(10s); std::this_thread::sleep_for(10s);
ABORT(); ABORT("{}\n\n[{}] {}", str, errNo, err);
} }
else else
{ {
// It's possible this attempted reconnect throws 2006 at us. // It's possible this attempted reconnect throws 2006 at us.
// To prevent crazy recursive calls, sleep here. // To prevent crazy recursive calls, sleep here.
std::this_thread::sleep_for(3s); // Sleep 3 seconds std::this_thread::sleep_for(3s); // Sleep 3 seconds
return _HandleMySQLErrno(lErrno, attempts); // Call self (recursive) return _HandleMySQLErrno(lErrno, mysql_error(m_Mysql), attempts); // Call self (recursive)
} }
[[fallthrough]];
} }
case ER_LOCK_DEADLOCK: case ER_LOCK_DEADLOCK:
@@ -625,14 +629,16 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
// Outdated table or database structure - terminate core // Outdated table or database structure - terminate core
case ER_BAD_FIELD_ERROR: case ER_BAD_FIELD_ERROR:
case ER_NO_SUCH_TABLE: case ER_NO_SUCH_TABLE:
LOG_ERROR("sql.sql", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); str = "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.";
LOG_FATAL("sql.sql", "{}", str);
std::this_thread::sleep_for(10s); std::this_thread::sleep_for(10s);
ABORT(); ABORT("{}\n\n[{}] {}", str, errNo, err);
return false; return false;
case ER_PARSE_ERROR: case ER_PARSE_ERROR:
LOG_ERROR("sql.sql", "Error while parsing SQL. Core fix required."); str = "Error while parsing SQL. Core fix required.";
LOG_FATAL("sql.sql", "{}", str);
std::this_thread::sleep_for(10s); std::this_thread::sleep_for(10s);
ABORT(); ABORT("{}\n\n[{}] {}", str, errNo, err);
return false; return false;
default: default:
LOG_ERROR("sql.sql", "Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo); LOG_ERROR("sql.sql", "Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
@@ -99,7 +99,7 @@ protected:
void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags); void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags);
virtual void DoPrepareStatements() = 0; virtual void DoPrepareStatements() = 0;
virtual bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5); virtual bool _HandleMySQLErrno(uint32 errNo, char const* err = "", uint8 attempts = 5);
typedef std::vector<std::unique_ptr<MySQLPreparedStatement>> PreparedStatementContainer; typedef std::vector<std::unique_ptr<MySQLPreparedStatement>> PreparedStatementContainer;
+2 -2
View File
@@ -52,7 +52,7 @@ void UnitAI::DoMeleeAttackIfReady()
if (me->isAttackReady()) if (me->isAttackReady())
{ {
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec // xinef: prevent base and off attack in same time, delay attack at 0.2 sec
if (me->haveOffhandWeapon()) if (me->HasOffhandWeaponForAttack())
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
@@ -60,7 +60,7 @@ void UnitAI::DoMeleeAttackIfReady()
me->resetAttackTimer(); me->resetAttackTimer();
} }
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) if (me->HasOffhandWeaponForAttack() && me->isAttackReady(OFF_ATTACK))
{ {
// xinef: delay main hand attack if both will hit at the same time (players code) // xinef: delay main hand attack if both will hit at the same time (players code)
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY) if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
@@ -522,17 +522,33 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
if (loadDefault) if (loadDefault)
{ {
me->LoadEquipment(me->GetOriginalEquipmentId(), true); me->LoadEquipment(me->GetOriginalEquipmentId(), true);
if (me->HasWeapon(OFF_ATTACK))
me->SetCanDualWield(true);
else
me->SetCanDualWield(false);
return; return;
} }
if (mainHand >= 0) if (mainHand >= 0)
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(mainHand)); {
me->SetVirtualItem(0, uint32(mainHand));
me->UpdateDamagePhysical(BASE_ATTACK);
}
if (offHand >= 0) if (offHand >= 0)
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(offHand)); {
me->SetVirtualItem(1, uint32(offHand));
if (offHand >= 1)
me->SetCanDualWield(true);
else
me->SetCanDualWield(false);
}
if (ranged >= 0) if (ranged >= 0)
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(ranged)); {
me->SetVirtualItem(2, uint32(ranged));
me->UpdateDamagePhysical(RANGED_ATTACK);
}
} }
enum eNPCs enum eNPCs
@@ -146,6 +146,7 @@ Battleground::Battleground()
m_LastResurrectTime = 0; m_LastResurrectTime = 0;
m_ArenaType = 0; m_ArenaType = 0;
m_IsArena = false; m_IsArena = false;
m_IsTemplate = true;
m_WinnerId = PVP_TEAM_NEUTRAL; m_WinnerId = PVP_TEAM_NEUTRAL;
m_StartTime = 0; m_StartTime = 0;
m_ResetStatTimer = 0; m_ResetStatTimer = 0;
@@ -1006,6 +1007,10 @@ void Battleground::RemovePlayerAtLeave(Player* player)
// BG subclass specific code // BG subclass specific code
RemovePlayer(player); RemovePlayer(player);
// should remove spirit of redemption
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
// if the player was a match participant // if the player was a match participant
if (participant) if (participant)
{ {
@@ -1049,9 +1054,6 @@ void Battleground::RemovePlayerAtLeave(Player* player)
} }
} }
// Remove shapeshift auras
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL); player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
// Xinef: remove all criterias on bg leave // Xinef: remove all criterias on bg leave
@@ -1821,6 +1823,7 @@ GraveyardStruct const* Battleground::GetClosestGraveyard(Player* player)
void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry) void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry)
{ {
m_IsTemplate = false;
m_BracketId = bracketEntry->GetBracketId(); m_BracketId = bracketEntry->GetBracketId();
SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel); SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel);
} }
+24 -6
View File
@@ -23,6 +23,7 @@
#include "DBCEnums.h" #include "DBCEnums.h"
#include "GameObject.h" #include "GameObject.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "World.h"
class Creature; class Creature;
class GameObject; class GameObject;
@@ -47,11 +48,15 @@ struct GraveyardStruct;
enum BattlegroundDesertionType : uint8 enum BattlegroundDesertionType : uint8
{ {
BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG
BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline
BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it
BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires) BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires)
BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
ARENA_DESERTION_TYPE_LEAVE_BG = 5, // player leaves the Arena
ARENA_DESERTION_TYPE_LEAVE_QUEUE = 6, // player is invited to join arena and refuses to do it
ARENA_DESERTION_TYPE_NO_ENTER_BUTTON = 7, // player is invited to join arena and do nothing (time expires)
ARENA_DESERTION_TYPE_INVITE_LOGOUT = 8, // player is invited to join arena and logs out
}; };
enum BattlegroundMaps enum BattlegroundMaps
@@ -334,8 +339,20 @@ public:
[[nodiscard]] uint32 GetMinLevel() const { return m_LevelMin; } [[nodiscard]] uint32 GetMinLevel() const { return m_LevelMin; }
[[nodiscard]] uint32 GetMaxLevel() const { return m_LevelMax; } [[nodiscard]] uint32 GetMaxLevel() const { return m_LevelMax; }
[[nodiscard]] bool isTemplate() const { return m_IsTemplate; }
[[nodiscard]] bool isMaxLevel() const
{
// NOTE: this only works when the BG is not a template but the real BG
auto maxPlayerLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
return GetMinLevel() <= maxPlayerLevel && maxPlayerLevel <= GetMaxLevel();
}
[[nodiscard]] uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; } [[nodiscard]] uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
[[nodiscard]] uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; } [[nodiscard]] uint32 GetMinPlayersPerTeam() const
{
auto lowLevelsOverride = sWorld->getIntConfig(CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS);
return (lowLevelsOverride && !isTemplate() && !isMaxLevel() && !isArena()) ? lowLevelsOverride : m_MinPlayersPerTeam;
}
[[nodiscard]] int32 GetStartDelayTime() const { return m_StartDelayTime; } [[nodiscard]] int32 GetStartDelayTime() const { return m_StartDelayTime; }
[[nodiscard]] uint8 GetArenaType() const { return m_ArenaType; } [[nodiscard]] uint8 GetArenaType() const { return m_ArenaType; }
@@ -655,6 +672,7 @@ private:
bool _InBGFreeSlotQueue{ false }; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque bool _InBGFreeSlotQueue{ false }; // used to make sure that BG is only once inserted into the BattlegroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
bool m_IsArena; bool m_IsArena;
bool m_IsTemplate;
PvPTeamId m_WinnerId; PvPTeamId m_WinnerId;
int32 m_StartDelayTime; int32 m_StartDelayTime;
bool m_IsRated; // is this battle rated? bool m_IsRated; // is this battle rated?
@@ -31,6 +31,8 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include <unordered_map> #include <unordered_map>
#include "BattlegroundUtils.h"
/*********************************************************/ /*********************************************************/
/*** BATTLEGROUND QUEUE SYSTEM ***/ /*** BATTLEGROUND QUEUE SYSTEM ***/
/*********************************************************/ /*********************************************************/
@@ -760,7 +762,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId
} }
// get min and max players per team // get min and max players per team
uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam(); uint32 MinPlayersPerTeam = GetMinPlayersPerTeam(bg_template, bracketEntry);
uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam(); uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
if (bg_template->isArena()) if (bg_template->isArena())
@@ -996,7 +998,7 @@ void BattlegroundQueue::BattlegroundQueueAnnouncerUpdate(uint32 diff, Battlegrou
_queueAnnouncementTimer[bracket_id] = -1; _queueAnnouncementTimer[bracket_id] = -1;
auto bgName = bg_template->GetName(); auto bgName = bg_template->GetName();
uint32 MaxPlayers = bg_template->GetMinPlayersPerTeam() * 2; uint32 MaxPlayers = GetMinPlayersPerTeam(bg_template, bracketEntry) * 2;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80); uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80); uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
@@ -1047,7 +1049,7 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
BattlegroundBracketId bracketId = bracketEntry->GetBracketId(); BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
auto bgName = bg->GetName(); auto bgName = bg->GetName();
uint32 MinPlayers = bg->GetMinPlayersPerTeam(); uint32 MinPlayers = GetMinPlayersPerTeam(bg, bracketEntry);
uint32 MaxPlayers = MinPlayers * 2; uint32 MaxPlayers = MinPlayers * 2;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32)80); uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32)80);
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32)80); uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32)80);
@@ -1357,6 +1359,9 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
sScriptMgr->OnBattlegroundDesertion(player, BG_DESERTION_TYPE_NO_ENTER_BUTTON); sScriptMgr->OnBattlegroundDesertion(player, BG_DESERTION_TYPE_NO_ENTER_BUTTON);
} }
if (bg && bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
sScriptMgr->OnBattlegroundDesertion(player, ARENA_DESERTION_TYPE_NO_ENTER_BUTTON);
LOG_DEBUG("bg.battleground", "Battleground: removing player {} from bg queue for instance {} because of not pressing enter battle in time.", player->GetGUID().ToString(), m_BgInstanceGUID); LOG_DEBUG("bg.battleground", "Battleground: removing player {} from bg queue for instance {} because of not pressing enter battle in time.", player->GetGUID().ToString(), m_BgInstanceGUID);
player->RemoveBattlegroundQueueId(m_BgQueueTypeId); player->RemoveBattlegroundQueueId(m_BgQueueTypeId);
@@ -0,0 +1,20 @@
#include "BattlegroundUtils.h"
#include "World.h"
uint32 GetMinPlayersPerTeam(Battleground* bg, PvPDifficultyEntry const* bracketEntry)
{
// The problem addressed here is that methods such as bg->GetMinLevel() and bg->GetMaxLevel() have a different meaning
// according to whether the BG is a template (then it's the value from the `battleground_template` table)
// or if it's the real BG (then it's the specific bracket minimum level, e.g. "60" for "60-69").
if (!bg->isTemplate() || bg->isArena())
{
return bg->GetMinPlayersPerTeam();
}
auto maxPlayerLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
auto isMaxLevel = bracketEntry->minLevel <= maxPlayerLevel && maxPlayerLevel <= bracketEntry->maxLevel;
auto lowLevelsOverride = sWorld->getIntConfig(CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS);
return (lowLevelsOverride && !isMaxLevel) ? lowLevelsOverride : bg->GetMinPlayersPerTeam();
}
@@ -0,0 +1,8 @@
#ifndef BATTLEGROUNDUTILS_H
#define BATTLEGROUNDUTILS_H
#include "Battleground.h"
uint32 GetMinPlayersPerTeam(Battleground* bg, PvPDifficultyEntry const* bracketEntry);
#endif // BATTLEGROUNDUTILS_H
@@ -524,6 +524,8 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, cinfo->HoverHeight); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, cinfo->HoverHeight);
SetCanDualWield(cinfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK);
// checked at loading // checked at loading
m_defaultMovementType = MovementGeneratorType(cinfo->MovementType); m_defaultMovementType = MovementGeneratorType(cinfo->MovementType);
if (!m_wanderDistance && m_defaultMovementType == RANDOM_MOTION_TYPE) if (!m_wanderDistance && m_defaultMovementType == RANDOM_MOTION_TYPE)
@@ -568,6 +570,8 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
ReplaceAllDynamicFlags(dynamicflags); ReplaceAllDynamicFlags(dynamicflags);
SetCanDualWield(cInfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK);
SetAttackTime(BASE_ATTACK, cInfo->BaseAttackTime); SetAttackTime(BASE_ATTACK, cInfo->BaseAttackTime);
SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime); SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime);
SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime); SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime);
@@ -3173,6 +3177,14 @@ bool Creature::IsImmuneToKnockback() const
return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK); return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK);
} }
bool Creature::HasWeapon(WeaponAttackType type) const
{
const uint8 slot = uint8(type);
ItemEntry const* item = sItemStore.LookupEntry(GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot));
return ((item && item->ClassID == ITEM_CLASS_WEAPON) || (type == OFF_ATTACK && CanDualWield()));
}
/** /**
* @brief Enable or disable the creature's walk mode by removing: MOVEMENTFLAG_WALKING. Infom also the client * @brief Enable or disable the creature's walk mode by removing: MOVEMENTFLAG_WALKING. Infom also the client
*/ */
@@ -190,6 +190,8 @@ public:
void UpdateAttackPowerAndDamage(bool ranged = false) override; void UpdateAttackPowerAndDamage(bool ranged = false) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override; void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
bool HasWeapon(WeaponAttackType type) const override;
bool HasWeaponForAttack(WeaponAttackType type) const override { return (Unit::HasWeaponForAttack(type) && HasWeapon(type)); }
void SetCanDualWield(bool value) override; void SetCanDualWield(bool value) override;
[[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; } [[nodiscard]] int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
uint8 GetCurrentEquipmentId() { return m_equipmentId; } uint8 GetCurrentEquipmentId() { return m_equipmentId; }
@@ -54,7 +54,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects
CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players
CREATURE_FLAG_EXTRA_UNUSED_12 = 0x00000800, /// @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks) CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x00000800, // creature will use offhand attacks
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
CREATURE_FLAG_EXTRA_IGNORE_COMBAT = 0x00002000, CREATURE_FLAG_EXTRA_IGNORE_COMBAT = 0x00002000,
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
@@ -77,9 +77,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000, CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000,
// Masks // Masks
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12), // SKIP CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~CREATURE_FLAG_EXTRA_DUNGEON_BOSS) // SKIP
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP
}; };
enum class CreatureGroundMovementType : uint8 enum class CreatureGroundMovementType : uint8
@@ -42,7 +42,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" }; case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" };
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" }; case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" };
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" }; case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" }; case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return { "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" }; case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" }; case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" };
case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" }; case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" };
@@ -86,7 +86,7 @@ AC_API_EXPORT CreatureFlagsExtra EnumUtils<CreatureFlagsExtra>::FromIndex(std::s
case 8: return CREATURE_FLAG_EXTRA_NO_TAUNT; case 8: return CREATURE_FLAG_EXTRA_NO_TAUNT;
case 9: return CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE; case 9: return CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE;
case 10: return CREATURE_FLAG_EXTRA_GHOST_VISIBILITY; case 10: return CREATURE_FLAG_EXTRA_GHOST_VISIBILITY;
case 11: return CREATURE_FLAG_EXTRA_UNUSED_12; case 11: return CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK;
case 12: return CREATURE_FLAG_EXTRA_NO_SELL_VENDOR; case 12: return CREATURE_FLAG_EXTRA_NO_SELL_VENDOR;
case 13: return CREATURE_FLAG_EXTRA_IGNORE_COMBAT; case 13: return CREATURE_FLAG_EXTRA_IGNORE_COMBAT;
case 14: return CREATURE_FLAG_EXTRA_WORLDEVENT; case 14: return CREATURE_FLAG_EXTRA_WORLDEVENT;
@@ -127,7 +127,7 @@ AC_API_EXPORT std::size_t EnumUtils<CreatureFlagsExtra>::ToIndex(CreatureFlagsEx
case CREATURE_FLAG_EXTRA_NO_TAUNT: return 8; case CREATURE_FLAG_EXTRA_NO_TAUNT: return 8;
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return 9; case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return 9;
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return 10; case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return 10;
case CREATURE_FLAG_EXTRA_UNUSED_12: return 11; case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return 11;
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return 12; case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return 12;
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return 13; case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return 13;
case CREATURE_FLAG_EXTRA_WORLDEVENT: return 14; case CREATURE_FLAG_EXTRA_WORLDEVENT: return 14;
+8 -6
View File
@@ -2725,17 +2725,17 @@ bool WorldObject::GetClosePoint(float& x, float& y, float& z, float size, float
return true; return true;
} }
Position WorldObject::GetNearPosition(float dist, float angle) Position WorldObject::GetNearPosition(float dist, float angle, bool disableWarning)
{ {
Position pos = GetPosition(); Position pos = GetPosition();
MovePosition(pos, dist, angle); MovePosition(pos, dist, angle, disableWarning);
return pos; return pos;
} }
Position WorldObject::GetRandomNearPosition(float radius) Position WorldObject::GetRandomNearPosition(float radius, bool disableWarning)
{ {
Position pos = GetPosition(); Position pos = GetPosition();
MovePosition(pos, radius * (float) rand_norm(), (float) rand_norm() * static_cast<float>(2 * M_PI)); MovePosition(pos, radius * (float) rand_norm(), (float) rand_norm() * static_cast<float>(2 * M_PI), disableWarning);
return pos; return pos;
} }
@@ -2773,7 +2773,7 @@ void WorldObject::GetChargeContactPoint(WorldObject const* obj, float& x, float&
return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE * GetObjectScale(); return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE * GetObjectScale();
} }
void WorldObject::MovePosition(Position& pos, float dist, float angle) void WorldObject::MovePosition(Position& pos, float dist, float angle, bool disableWarning)
{ {
angle += GetOrientation(); angle += GetOrientation();
float destx, desty, destz, ground, floor; float destx, desty, destz, ground, floor;
@@ -2783,7 +2783,9 @@ void WorldObject::MovePosition(Position& pos, float dist, float angle)
// Prevent invalid coordinates here, position is unchanged // Prevent invalid coordinates here, position is unchanged
if (!Acore::IsValidMapCoord(destx, desty)) if (!Acore::IsValidMapCoord(destx, desty))
{ {
LOG_FATAL("entities.object", "WorldObject::MovePosition invalid coordinates X: {} and Y: {} were passed!", destx, desty); if (!disableWarning)
LOG_FATAL("entities.object", "WorldObject::MovePosition invalid coordinates X: {} and Y: {} were passed!", destx, desty);
return; return;
} }
+3 -3
View File
@@ -420,13 +420,13 @@ public:
void GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_size, float distance2d, float absAngle, float controlZ = 0, Position const* startPos = nullptr) const; void GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_size, float distance2d, float absAngle, float controlZ = 0, Position const* startPos = nullptr) const;
void GetVoidClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float relAngle = 0, float controlZ = 0) const; void GetVoidClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float relAngle = 0, float controlZ = 0) const;
bool GetClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float angle = 0, WorldObject const* forWho = nullptr, bool force = false) const; bool GetClosePoint(float& x, float& y, float& z, float size, float distance2d = 0, float angle = 0, WorldObject const* forWho = nullptr, bool force = false) const;
void MovePosition(Position& pos, float dist, float angle); void MovePosition(Position& pos, float dist, float angle, bool disableWarning = false);
Position GetNearPosition(float dist, float angle); Position GetNearPosition(float dist, float angle, bool disableWarning = false);
void MovePositionToFirstCollision(Position& pos, float dist, float angle); void MovePositionToFirstCollision(Position& pos, float dist, float angle);
Position GetFirstCollisionPosition(float startX, float startY, float startZ, float destX, float destY); Position GetFirstCollisionPosition(float startX, float startY, float startZ, float destX, float destY);
Position GetFirstCollisionPosition(float destX, float destY, float destZ); Position GetFirstCollisionPosition(float destX, float destY, float destZ);
Position GetFirstCollisionPosition(float dist, float angle); Position GetFirstCollisionPosition(float dist, float angle);
Position GetRandomNearPosition(float radius); Position GetRandomNearPosition(float radius, bool disableWarning = false);
void GetContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const; void GetContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const;
void GetChargeContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const; void GetChargeContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const;
@@ -11347,6 +11347,9 @@ void Player::LeaveBattleground(Battleground* bg)
sScriptMgr->OnBattlegroundDesertion(this, BG_DESERTION_TYPE_LEAVE_BG); sScriptMgr->OnBattlegroundDesertion(this, BG_DESERTION_TYPE_LEAVE_BG);
} }
if (bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
sScriptMgr->OnBattlegroundDesertion(this, ARENA_DESERTION_TYPE_LEAVE_BG);
bg->RemovePlayerAtLeave(this); bg->RemovePlayerAtLeave(this);
// xinef: reset corpse reclaim time // xinef: reset corpse reclaim time
+2
View File
@@ -1238,6 +1238,8 @@ public:
return GetItemByPos(bag, slot); return GetItemByPos(bag, slot);
} }
[[nodiscard]] Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; [[nodiscard]] Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const;
bool HasWeapon(WeaponAttackType type) const override { return GetWeaponForAttack(type, false); }
bool HasWeaponForAttack(WeaponAttackType type) const override { return (Unit::HasWeaponForAttack(type) && GetWeaponForAttack(type, true)); }
[[nodiscard]] Item* GetShield(bool useable = false) const; [[nodiscard]] Item* GetShield(bool useable = false) const;
static uint8 GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot static uint8 GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot
std::vector<Item*>& GetItemUpdateQueue() { return m_itemUpdateQueue; } std::vector<Item*>& GetItemUpdateQueue() { return m_itemUpdateQueue; }
@@ -195,7 +195,7 @@ void Player::Update(uint32 p_time)
// prevent base and off attack in same time, delay attack at // prevent base and off attack in same time, delay attack at
// 0.2 sec // 0.2 sec
if (haveOffhandWeapon()) if (HasOffhandWeaponForAttack())
if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
@@ -205,7 +205,7 @@ void Player::Update(uint32 p_time)
} }
} }
if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
{ {
if (!IsWithinMeleeRange(victim)) if (!IsWithinMeleeRange(victim))
setAttackTimer(OFF_ATTACK, 100); setAttackTimer(OFF_ATTACK, 100);
+7 -6
View File
@@ -512,7 +512,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
else else
{ {
UpdateDamagePhysical(BASE_ATTACK); UpdateDamagePhysical(BASE_ATTACK);
if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon if (CanDualWield() && HasOffhandWeaponForAttack()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon
UpdateDamagePhysical(OFF_ATTACK); UpdateDamagePhysical(OFF_ATTACK);
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS)) // mental quickness if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_STATS) || IsClass(CLASS_PALADIN, CLASS_CONTEXT_STATS)) // mental quickness
UpdateSpellDamageAndHealingBonus(); UpdateSpellDamageAndHealingBonus();
@@ -567,7 +567,7 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE); float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE); float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
if (IsInFeralForm()) // check if player is druid and in cat or bear forms if (IsAttackSpeedOverridenShapeShift()) // forms with no override on attack speed use normal weapon damage
{ {
uint8 lvl = GetLevel(); uint8 lvl = GetLevel();
if (lvl > 60) if (lvl > 60)
@@ -1118,7 +1118,7 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
break; break;
} }
if (attType == OFF_ATTACK && !haveOffhandWeapon()) if (attType == OFF_ATTACK && !HasOffhandWeaponForAttack())
{ {
minDamage = 0.0f; minDamage = 0.0f;
maxDamage = 0.0f; maxDamage = 0.0f;
@@ -1128,10 +1128,11 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE); float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE); float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
if (!CanUseAttackType(attType)) // disarm case // Disarm for creatures
if (HasWeapon(attType) && !HasWeaponForAttack(attType))
{ {
weaponMinDamage = 0.0f; minDamage *= 0.5f;
weaponMaxDamage = 0.0f; maxDamage *= 0.5f;
} }
float attackPower = GetTotalAttackPowerValue(attType); float attackPower = GetTotalAttackPowerValue(attType);
+34 -8
View File
@@ -1856,7 +1856,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
float offtime = float(victim->getAttackTimer(OFF_ATTACK)); float offtime = float(victim->getAttackTimer(OFF_ATTACK));
float basetime = float(victim->getAttackTimer(BASE_ATTACK)); float basetime = float(victim->getAttackTimer(BASE_ATTACK));
// Reduce attack time // Reduce attack time
if (victim->haveOffhandWeapon() && offtime < basetime) if (victim->HasOffhandWeaponForAttack() && offtime < basetime)
{ {
float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f; float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20; float percent60 = 3.0f * percent20;
@@ -8430,7 +8430,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
if (dummySpell->SpellIconID == 2023) if (dummySpell->SpellIconID == 2023)
{ {
// Must Dual Wield // Must Dual Wield
if (!procSpell || !haveOffhandWeapon()) if (!procSpell || !HasOffhandWeaponForAttack())
return false; return false;
// Chance as basepoints for dummy aura // Chance as basepoints for dummy aura
if (!roll_chance_i(triggerAmount)) if (!roll_chance_i(triggerAmount))
@@ -10365,9 +10365,9 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
} }
// delay offhand weapon attack to next attack time // delay offhand weapon attack by 50% of the base attack time
if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); setAttackTimer(OFF_ATTACK, std::max(getAttackTimer(OFF_ATTACK), getAttackTimer(BASE_ATTACK) + int32(CalculatePct(GetFloatValue(UNIT_FIELD_BASEATTACKTIME), 50))));
if (meleeAttack) if (meleeAttack)
SendMeleeAttackStart(victim); SendMeleeAttackStart(victim);
@@ -13417,7 +13417,7 @@ float Unit::GetWeaponProcChance() const
// (odd formula...) // (odd formula...)
if (isAttackReady(BASE_ATTACK)) if (isAttackReady(BASE_ATTACK))
return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f); return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) else if (HasOffhandWeaponForAttack() && isAttackReady(OFF_ATTACK))
return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f); return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
return 0; return 0;
} }
@@ -15423,7 +15423,7 @@ float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, Unit* victim) con
float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const
{ {
if (attType == OFF_ATTACK && !haveOffhandWeapon()) if (attType == OFF_ATTACK && !HasOffhandWeaponForAttack())
return 0.0f; return 0.0f;
return m_weaponDamage[attType][type][damageIndex]; return m_weaponDamage[attType][type][damageIndex];
@@ -18984,7 +18984,7 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, i
float missChance = victim->GetUnitMissChance(attType); float missChance = victim->GetUnitMissChance(attType);
// Check if dual wielding, add additional miss penalty - when mainhand has on next swing spell, offhand doesnt suffer penalty // Check if dual wielding, add additional miss penalty - when mainhand has on next swing spell, offhand doesnt suffer penalty
if (!spellId && (attType != RANGED_ATTACK) && haveOffhandWeapon() && (!m_currentSpells[CURRENT_MELEE_SPELL] || !m_currentSpells[CURRENT_MELEE_SPELL]->IsNextMeleeSwingSpell())) if (!spellId && (attType != RANGED_ATTACK) && HasOffhandWeaponForAttack() && (!m_currentSpells[CURRENT_MELEE_SPELL] || !m_currentSpells[CURRENT_MELEE_SPELL]->IsNextMeleeSwingSpell()))
{ {
missChance += 19; missChance += 19;
} }
@@ -19498,6 +19498,16 @@ Unit* Unit::GetRedirectThreatTarget() const
return _redirectThreatInfo.GetTargetGUID() ? ObjectAccessor::GetUnit(*this, _redirectThreatInfo.GetTargetGUID()) : nullptr; return _redirectThreatInfo.GetTargetGUID() ? ObjectAccessor::GetUnit(*this, _redirectThreatInfo.GetTargetGUID()) : nullptr;
} }
bool Unit::IsAttackSpeedOverridenShapeShift() const
{
// Mirroring clientside gameplay logic
if (ShapeshiftForm form = GetShapeshiftForm())
if (SpellShapeshiftFormEntry const* entry = sSpellShapeshiftFormStore.LookupEntry(form))
return entry->attackSpeed > 0;
return false;
}
void Unit::JumpTo(float speedXY, float speedZ, bool forward) void Unit::JumpTo(float speedXY, float speedZ, bool forward)
{ {
float angle = forward ? 0 : M_PI; float angle = forward ? 0 : M_PI;
@@ -21151,6 +21161,22 @@ void Unit::Whisper(std::string_view text, Language language, Player* target, boo
target->SendDirectMessage(&data); target->SendDirectMessage(&data);
} }
uint32 Unit::GetVirtualItemId(uint32 slot) const
{
if (slot >= MAX_EQUIPMENT_ITEMS)
return 0;
return GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot);
}
void Unit::SetVirtualItem(uint32 slot, uint32 itemId)
{
if (slot >= MAX_EQUIPMENT_ITEMS)
return;
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot, itemId);
}
void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target) void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
{ {
if (!sObjectMgr->GetBroadcastText(textId)) if (!sObjectMgr->GetBroadcastText(textId))
+18 -1
View File
@@ -1053,6 +1053,17 @@ public:
[[nodiscard]] float GetUnitMissChance(WeaponAttackType attType) const; [[nodiscard]] float GetUnitMissChance(WeaponAttackType attType) const;
float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const; float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const;
int32 GetMechanicResistChance(SpellInfo const* spell); int32 GetMechanicResistChance(SpellInfo const* spell);
virtual bool HasWeapon(WeaponAttackType type) const = 0;
inline bool HasMainhandWeapon() const { return HasWeapon(BASE_ATTACK); }
inline bool HasOffhandWeapon() const { return HasWeapon(OFF_ATTACK); }
inline bool HasRangedWeapon() const { return HasWeapon(RANGED_ATTACK); }
inline bool hasMainhandWeaponForAttack() const { return HasWeaponForAttack(BASE_ATTACK); }
virtual bool HasWeaponForAttack(WeaponAttackType type) const { return CanUseAttackType(type); }
inline bool HasMainhandWeaponForAttack() const { return HasWeaponForAttack(BASE_ATTACK); }
inline bool HasOffhandWeaponForAttack() const { return HasWeaponForAttack(OFF_ATTACK); }
inline bool HasRangedWeaponForAttack() const { return HasWeaponForAttack(RANGED_ATTACK); }
[[nodiscard]] bool CanUseAttackType(uint8 attacktype) const [[nodiscard]] bool CanUseAttackType(uint8 attacktype) const
{ {
switch (attacktype) switch (attacktype)
@@ -1063,8 +1074,9 @@ public:
return !HasUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); return !HasUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND);
case RANGED_ATTACK: case RANGED_ATTACK:
return !HasUnitFlag2(UNIT_FLAG2_DISARM_RANGED); return !HasUnitFlag2(UNIT_FLAG2_DISARM_RANGED);
default:
return true;
} }
return true;
} }
[[nodiscard]] virtual uint32 GetShieldBlockValue() const = 0; [[nodiscard]] virtual uint32 GetShieldBlockValue() const = 0;
@@ -1468,6 +1480,8 @@ public:
SetByteValue(UNIT_FIELD_BYTES_2, 3, form); SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
} }
bool IsAttackSpeedOverridenShapeShift() const;
[[nodiscard]] bool IsInFeralForm() const [[nodiscard]] bool IsInFeralForm() const
{ {
ShapeshiftForm form = GetShapeshiftForm(); ShapeshiftForm form = GetShapeshiftForm();
@@ -1762,6 +1776,9 @@ public:
[[nodiscard]] float GetCollisionWidth() const override; [[nodiscard]] float GetCollisionWidth() const override;
[[nodiscard]] float GetCollisionRadius() const override; [[nodiscard]] float GetCollisionRadius() const override;
uint32 GetVirtualItemId(uint32 slot) const;
void SetVirtualItem(uint32 slot, uint32 itemId);
void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override; void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override;
virtual void ProcessTerrainStatusUpdate(); virtual void ProcessTerrainStatusUpdate();
-2
View File
@@ -18,8 +18,6 @@
#ifndef __ADDONHANDLER_H #ifndef __ADDONHANDLER_H
#define __ADDONHANDLER_H #define __ADDONHANDLER_H
#include "Common.h"
#include "Config.h"
#include "WorldPacket.h" #include "WorldPacket.h"
class AddonHandler class AddonHandler
@@ -25,7 +25,6 @@
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "UpdateMask.h"
#include "World.h" #include "World.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
-1
View File
@@ -19,7 +19,6 @@
#include "DBCStores.h" #include "DBCStores.h"
#include "Item.h" #include "Item.h"
#include "Log.h" #include "Log.h"
#include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
@@ -580,6 +580,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE); sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_LEAVE_QUEUE);
} }
if (bg->isArena() && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
sScriptMgr->OnBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_LEAVE_QUEUE);
} }
} }
@@ -53,7 +53,6 @@
#include "StringConvert.h" #include "StringConvert.h"
#include "Tokenize.h" #include "Tokenize.h"
#include "Transport.h" #include "Transport.h"
#include "UpdateMask.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
#include "WorldPacket.h" #include "WorldPacket.h"
@@ -19,7 +19,6 @@
#include "CreatureAI.h" #include "CreatureAI.h"
#include "Log.h" #include "Log.h"
#include "ObjectAccessor.h" #include "ObjectAccessor.h"
#include "ObjectDefines.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "Vehicle.h" #include "Vehicle.h"
-1
View File
@@ -19,7 +19,6 @@
#include "Log.h" #include "Log.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "UpdateData.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
@@ -20,10 +20,7 @@
#include "GuildPackets.h" #include "GuildPackets.h"
#include "Log.h" #include "Log.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Opcodes.h"
#include "SocialMgr.h" #include "SocialMgr.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
void WorldSession::HandleGuildQueryOpcode(WorldPackets::Guild::QueryGuildInfo& query) void WorldSession::HandleGuildQueryOpcode(WorldPackets::Guild::QueryGuildInfo& query)
-1
View File
@@ -29,7 +29,6 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "UpdateMask.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
#include <cmath> #include <cmath>
-1
View File
@@ -28,7 +28,6 @@
#include "Pet.h" #include "Pet.h"
#include "PetPackets.h" #include "PetPackets.h"
#include "Player.h" #include "Player.h"
#include "QueryHolder.h"
#include "Spell.h" #include "Spell.h"
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellMgr.h" #include "SpellMgr.h"
@@ -17,7 +17,6 @@
#include "Log.h" #include "Log.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "Pet.h"
#include "Player.h" #include "Player.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "WorldPacket.h" #include "WorldPacket.h"
@@ -26,7 +26,6 @@
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
#include "SpellAuras.h" #include "SpellAuras.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "TemporarySummon.h"
#include "Totem.h" #include "Totem.h"
#include "TotemPackets.h" #include "TotemPackets.h"
#include "Vehicle.h" #include "Vehicle.h"
-1
View File
@@ -20,7 +20,6 @@
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "UpdateMask.h"
#include "WaypointMovementGenerator.h" #include "WaypointMovementGenerator.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "WorldSession.h" #include "WorldSession.h"
+3 -1
View File
@@ -700,7 +700,9 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
} }
// Player is not the loot owner, and loot owner still needs this quest item // Player is not the loot owner, and loot owner still needs this quest item
if (!item.freeforall && lootOwner != player && item.AllowedForPlayer(lootOwner, sourceWorldObjectGUID)) if (!item.freeforall &&
lootOwner && lootOwner != player &&
item.AllowedForPlayer(lootOwner, sourceWorldObjectGUID))
{ {
continue; continue;
} }
+7 -4
View File
@@ -520,7 +520,7 @@ void MotionMaster::MoveLand(uint32 id, float x, float y, float z, float speed /*
/** /**
* @brief Use to move the unit from the ground to the air. Doesn't work with UNIT_FLAG_DISABLE_MOVE * @brief Use to move the unit from the ground to the air. Doesn't work with UNIT_FLAG_DISABLE_MOVE
*/ */
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* = 0.0f*/) void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* = 0.0f*/, bool skipAnimation)
{ {
if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
return; return;
@@ -538,7 +538,10 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* =
init.SetVelocity(speed); init.SetVelocity(speed);
} }
init.SetAnimation(Movement::ToFly); if (!skipAnimation)
{
init.SetAnimation(Movement::ToFly);
}
init.Launch(); init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE);
} }
@@ -546,10 +549,10 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed /* =
/** /**
* @brief Use to move the unit from the air to the ground. Doesn't work with UNIT_FLAG_DISABLE_MOVE * @brief Use to move the unit from the air to the ground. Doesn't work with UNIT_FLAG_DISABLE_MOVE
*/ */
void MotionMaster::MoveTakeoff(uint32 id, float x, float y, float z, float speed /* = 0.0f*/) void MotionMaster::MoveTakeoff(uint32 id, float x, float y, float z, float speed /* = 0.0f*/, bool skipAnimation)
{ {
Position pos = {x, y, z, 0.0f}; Position pos = {x, y, z, 0.0f};
MoveTakeoff(id, pos, speed); MoveTakeoff(id, pos, speed, skipAnimation);
} }
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ) void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
+2 -2
View File
@@ -217,8 +217,8 @@ public:
// These two movement types should only be used with creatures having landing/takeoff animations // These two movement types should only be used with creatures having landing/takeoff animations
void MoveLand(uint32 id, Position const& pos, float speed = 0.0f); void MoveLand(uint32 id, Position const& pos, float speed = 0.0f);
void MoveLand(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z void MoveLand(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z
void MoveTakeoff(uint32 id, Position const& pos, float speed = 0.0f); void MoveTakeoff(uint32 id, Position const& pos, float speed = 0.0f, bool skipAnimation = false);
void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f); // pussywizard: added for easy calling by passing 3 floats x, y, z void MoveTakeoff(uint32 id, float x, float y, float z, float speed = 0.0f, bool skipAnimation = false); // pussywizard: added for easy calling by passing 3 floats x, y, z
void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty); void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, const Movement::PointsArray* path = nullptr, bool generatePath = false, float orientation = 0.0f, ObjectGuid targetGUID = ObjectGuid::Empty);
void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, ObjectGuid targetGUID = ObjectGuid::Empty); void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE, ObjectGuid targetGUID = ObjectGuid::Empty);
+3
View File
@@ -661,6 +661,9 @@ void WorldSession::LogoutPlayer(bool save)
sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_INVITE_LOGOUT); sScriptMgr->OnBattlegroundDesertion(_player, BG_DESERTION_TYPE_INVITE_LOGOUT);
} }
if (bgQueueTypeId >= BATTLEGROUND_QUEUE_2v2 && bgQueueTypeId < MAX_BATTLEGROUND_QUEUE_TYPES && _player->IsInvitedForBattlegroundQueueType(bgQueueTypeId))
sScriptMgr->OnBattlegroundDesertion(_player, ARENA_DESERTION_TYPE_INVITE_LOGOUT);
_player->RemoveBattlegroundQueueId(bgQueueTypeId); _player->RemoveBattlegroundQueueId(bgQueueTypeId);
sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), true); sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId).RemovePlayer(_player->GetGUID(), true);
} }
+8 -1
View File
@@ -3160,6 +3160,13 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
if (m_spellAura) if (m_spellAura)
{ {
// Prevent aura application if target is immuned
if (m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->IsImmunedToDamageOrSchool(m_spellAura->GetSpellInfo()))
{
m_spellAura->Remove();
return SPELL_MISS_IMMUNE;
}
// Set aura stack amount to desired value // Set aura stack amount to desired value
if (m_spellValue->AuraStackAmount > 1) if (m_spellValue->AuraStackAmount > 1)
{ {
@@ -4061,7 +4068,7 @@ void Spell::_cast(bool skipCheck)
{ {
m_caster->resetAttackTimer(BASE_ATTACK); m_caster->resetAttackTimer(BASE_ATTACK);
if (m_caster->haveOffhandWeapon()) if (m_caster->HasOffhandWeaponForAttack())
{ {
m_caster->resetAttackTimer(OFF_ATTACK); m_caster->resetAttackTimer(OFF_ATTACK);
} }
@@ -4837,6 +4837,19 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL; spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL;
}); });
// Fatal Attraction
ApplySpellFix({ 40870 }, [](SpellInfo* spellInfo)
{
spellInfo->MaxAffectedTargets = 1;
});
// Removing Dragonflayer Harpoon
ApplySpellFix({ 42968 }, [](SpellInfo* spellInfo)
{
spellInfo->MaxAffectedTargets = 1;
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(7);
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{ {
SpellInfo* spellInfo = mSpellInfoMap[i]; SpellInfo* spellInfo = mSpellInfoMap[i];
+1
View File
@@ -309,6 +309,7 @@ enum WorldIntConfigs
CONFIG_DEATH_SICKNESS_LEVEL, CONFIG_DEATH_SICKNESS_LEVEL,
CONFIG_INSTANT_LOGOUT, CONFIG_INSTANT_LOGOUT,
CONFIG_DISABLE_BREATHING, CONFIG_DISABLE_BREATHING,
CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY,
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMER, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMER,
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER, CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
+1
View File
@@ -1113,6 +1113,7 @@ void World::LoadConfigSettings(bool reload)
_float_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfigMgr->GetOption<float>("ListenRange.TextEmote", 25.0f); _float_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfigMgr->GetOption<float>("ListenRange.TextEmote", 25.0f);
_float_configs[CONFIG_LISTEN_RANGE_YELL] = sConfigMgr->GetOption<float>("ListenRange.Yell", 300.0f); _float_configs[CONFIG_LISTEN_RANGE_YELL] = sConfigMgr->GetOption<float>("ListenRange.Yell", 300.0f);
_int_configs[CONFIG_BATTLEGROUND_OVERRIDE_LOWLEVELS_MINPLAYERS] = sConfigMgr->GetOption<uint32>("Battleground.Override.LowLevels.MinPlayers", 0);
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_QUEST_SHARE_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableQuestShareInBG", false); _bool_configs[CONFIG_BATTLEGROUND_DISABLE_QUEST_SHARE_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableQuestShareInBG", false);
_bool_configs[CONFIG_BATTLEGROUND_DISABLE_READY_CHECK_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableReadyCheckInBG", false); _bool_configs[CONFIG_BATTLEGROUND_DISABLE_READY_CHECK_IN_BG] = sConfigMgr->GetOption<bool>("Battleground.DisableReadyCheckInBG", false);
_bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetOption<bool>("Battleground.CastDeserter", true); _bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetOption<bool>("Battleground.CastDeserter", true);
@@ -28,7 +28,6 @@ EndScriptData */
#include "CommandScript.h" #include "CommandScript.h"
#include "DBCStores.h" #include "DBCStores.h"
#include "DatabaseEnv.h" #include "DatabaseEnv.h"
#include "Log.h"
#include "ObjectAccessor.h" #include "ObjectAccessor.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
@@ -29,7 +29,6 @@
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellScript.h" #include "SpellScript.h"
#include "SpellScriptLoader.h" #include "SpellScriptLoader.h"
#include "Vehicle.h"
/*###### /*######
## npc_eye_of_acherus ## npc_eye_of_acherus
@@ -2417,6 +2417,8 @@ public:
ObjectGuid _grabbedPlayer; ObjectGuid _grabbedPlayer;
bool didbelow50pct; bool didbelow50pct;
bool dropped; bool dropped;
bool grabbed;
float _lastSpeed;
InstanceScript* _instance; InstanceScript* _instance;
bool IsHeroic() { return me->GetMap()->IsHeroic(); } bool IsHeroic() { return me->GetMap()->IsHeroic(); }
@@ -2547,6 +2549,8 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED)) if (me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED))
return; return;
HandleSpeedChangeIfNeeded();
switch (_events.ExecuteEvent()) switch (_events.ExecuteEvent())
{ {
case EVENT_GRAB_PLAYER: case EVENT_GRAB_PLAYER:
@@ -2557,6 +2561,8 @@ public:
} }
break; break;
case EVENT_MOVE_TO_DROP_POS: case EVENT_MOVE_TO_DROP_POS:
grabbed = true;
_lastSpeed = me->GetSpeed(MOVE_WALK);
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
me->SetCanFly(false); me->SetCanFly(false);
me->SetDisableGravity(false); me->SetDisableGravity(false);
@@ -2596,6 +2602,24 @@ public:
break; break;
} }
} }
// For some reason, when the Valkyr has a slowdown effect, the speed of PointMovementGenerator
// and the speed on the client side differ, which leads to a "teleportation" effect when a stun aura is applied.
// Restarting the motion master on speed change ensures the movement is synced between the server and client.
void HandleSpeedChangeIfNeeded()
{
if (!grabbed || dropped)
return;
if (me->GetSpeed(MOVE_WALK) == _lastSpeed)
return;
_lastSpeed = me->GetSpeed(MOVE_WALK);
me->GetMotionMaster()->Clear();
me->StopMovingOnCurrentPos();
_events.ScheduleEvent(EVENT_MOVE_TO_DROP_POS, 0);
}
}; };
CreatureAI* GetAI(Creature* creature) const override CreatureAI* GetAI(Creature* creature) const override
@@ -27,6 +27,7 @@
#include "PassiveAI.h" #include "PassiveAI.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "ScriptedEscortAI.h" #include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SmartAI.h" #include "SmartAI.h"
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
#include "SpellScriptLoader.h" #include "SpellScriptLoader.h"
@@ -26,7 +26,6 @@
#include "PassiveAI.h" #include "PassiveAI.h"
#include "Player.h" #include "Player.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
#include "SpellScript.h" #include "SpellScript.h"
#include "SpellScriptLoader.h" #include "SpellScriptLoader.h"
@@ -24,7 +24,6 @@
#include "SpellAuras.h" #include "SpellAuras.h"
#include "SpellScript.h" #include "SpellScript.h"
#include "SpellScriptLoader.h" #include "SpellScriptLoader.h"
#include "Vehicle.h"
#include "ulduar.h" #include "ulduar.h"
#define SPELL_FLAME_JETS_10 62680 #define SPELL_FLAME_JETS_10 62680
@@ -21,7 +21,6 @@
#include "Player.h" #include "Player.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "Transport.h" #include "Transport.h"
#include "Vehicle.h"
#include "WorldPacket.h" #include "WorldPacket.h"
#include "ulduar.h" #include "ulduar.h"
@@ -136,7 +136,7 @@ struct boss_gurtogg_bloodboil : public BossAI
bool CanAIAttack(Unit const* who) const override bool CanAIAttack(Unit const* who) const override
{ {
return !who->IsImmunedToDamage(SPELL_SCHOOL_MASK_ALL); return !who->IsImmunedToDamage(SPELL_SCHOOL_MASK_ALL) && !who->HasUnitState(UNIT_STATE_CONFUSED);
} }
void KilledUnit(Unit* /*victim*/) override void KilledUnit(Unit* /*victim*/) override
@@ -196,6 +196,17 @@ class spell_mother_shahraz_saber_lash_aura : public AuraScript
} }
}; };
const Position validTeleportStairsPos[4] =
{
{966.87f, 184.45f, 192.84f},
{927.22f, 187.04f, 192.84f},
{922.54f, 110.09f, 192.84f},
{958.01f, 110.47f, 192.84f}
};
constexpr float minTeleportDist = 30.f;
constexpr float maxTeleportDist = 50.f;
class spell_mother_shahraz_fatal_attraction : public SpellScript class spell_mother_shahraz_fatal_attraction : public SpellScript
{ {
PrepareSpellScript(spell_mother_shahraz_fatal_attraction); PrepareSpellScript(spell_mother_shahraz_fatal_attraction);
@@ -212,7 +223,44 @@ class spell_mother_shahraz_fatal_attraction : public SpellScript
void SetDest(SpellDestination& dest) void SetDest(SpellDestination& dest)
{ {
dest.Relocate(GetCaster()->GetRandomNearPosition(50.0f)); Position finalDest;
// Check if the boss is near stairs to avoid players falling through the platform with random teleports.
if (GetCaster()->GetPositionY() < 194.f)
finalDest = validTeleportStairsPos[urand(0, 3)];
else
{
finalDest = GetCaster()->GetNearPosition(frand(minTeleportDist, maxTeleportDist), static_cast<float>(rand_norm()) * static_cast<float>(2 * M_PI), true);
// Maybe not necessary but just in case to avoid LOS issues with an object
if (!GetCaster()->IsWithinLOS(finalDest.GetPositionX(), finalDest.GetPositionY(), finalDest.GetPositionZ()))
finalDest = GetCaster()->GetNearPosition(frand(minTeleportDist, maxTeleportDist), static_cast<float>(rand_norm()) * static_cast<float>(2 * M_PI), true);
/* @note: To avoid teleporting players near a walls, we will define a safe area.
* As the boss have an area boudary around y: 320.f. We will limit the safe area to this value, avoiding wird issues.
* x limit: 932.f/960.f | y limit: 224.f/320.f
*/
if (finalDest.m_positionX < 932.f)
finalDest.m_positionX = 932.f;
else if (finalDest.m_positionX > 960.f)
finalDest.m_positionX = 960.f;
if (finalDest.m_positionY < 224.f)
finalDest.m_positionY = 224.f;
else if (finalDest.m_positionY > 320.f)
finalDest.m_positionY = 320.f;
// After relocate a finalDest outside the safe area, we need to recheck the distance with the boss
if (GetCaster()->GetExactDist2d(finalDest) < minTeleportDist)
{
if (finalDest.m_positionX == 932.f || finalDest.m_positionX == 960.f)
finalDest.m_positionY = finalDest.m_positionY + (minTeleportDist - GetCaster()->GetExactDist2d(finalDest));
else if (finalDest.m_positionY == 224.f || finalDest.m_positionY == 320.f)
finalDest.m_positionX = finalDest.m_positionX + (minTeleportDist - GetCaster()->GetExactDist2d(finalDest));
}
}
dest.Relocate(finalDest);
} }
void HandleTeleportUnits(SpellEffIndex /*effIndex*/) void HandleTeleportUnits(SpellEffIndex /*effIndex*/)
@@ -235,7 +283,13 @@ class spell_mother_shahraz_fatal_attraction_dummy : public SpellScript
bool Validate(SpellInfo const* /*spellInfo*/) override bool Validate(SpellInfo const* /*spellInfo*/) override
{ {
return ValidateSpellInfo({ SPELL_FATAL_ATTRACTION_DAMAGE }); return ValidateSpellInfo({ SPELL_FATAL_ATTRACTION_DAMAGE, SPELL_FATAL_ATTRACTION_AURA });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
GetCaster()->RemoveAurasDueToSpell(SPELL_FATAL_ATTRACTION_AURA);
} }
void HandleDummy(SpellEffIndex /*effIndex*/) void HandleDummy(SpellEffIndex /*effIndex*/)
@@ -255,6 +309,7 @@ class spell_mother_shahraz_fatal_attraction_dummy : public SpellScript
void Register() override void Register() override
{ {
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mother_shahraz_fatal_attraction_dummy::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ALLY);
OnEffectHitTarget += SpellEffectFn(spell_mother_shahraz_fatal_attraction_dummy::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); OnEffectHitTarget += SpellEffectFn(spell_mother_shahraz_fatal_attraction_dummy::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
} }
}; };
@@ -178,6 +178,13 @@ public:
for (ObjectGuid const& guid : ashtongueGUIDs) for (ObjectGuid const& guid : ashtongueGUIDs)
if (Creature* ashtongue = instance->GetCreature(guid)) if (Creature* ashtongue = instance->GetCreature(guid))
ashtongue->SetFaction(FACTION_ASHTONGUE_DEATHSWORN); ashtongue->SetFaction(FACTION_ASHTONGUE_DEATHSWORN);
[[fallthrough]];
case DATA_TERON_GOREFIEND:
case DATA_GURTOGG_BLOODBOIL:
case DATA_RELIQUARY_OF_SOULS:
if (AllBossesDone({ DATA_SHADE_OF_AKAMA, DATA_TERON_GOREFIEND, DATA_GURTOGG_BLOODBOIL, DATA_RELIQUARY_OF_SOULS }))
if (Creature* trigger = GetCreature(DATA_BLACK_TEMPLE_TRIGGER))
trigger->AI()->Talk(EMOTE_LOWER_TEMPLE_DEFEATED);
break; break;
case DATA_ILLIDARI_COUNCIL: case DATA_ILLIDARI_COUNCIL:
if (Creature* akama = GetCreature(DATA_AKAMA_ILLIDAN)) if (Creature* akama = GetCreature(DATA_AKAMA_ILLIDAN))
@@ -186,10 +193,6 @@ public:
default: default:
break; break;
} }
if (AllBossesDone({ DATA_SHADE_OF_AKAMA, DATA_TERON_GOREFIEND, DATA_GURTOGG_BLOODBOIL, DATA_RELIQUARY_OF_SOULS }))
if (Creature* trigger = GetCreature(DATA_BLACK_TEMPLE_TRIGGER))
trigger->AI()->Talk(EMOTE_LOWER_TEMPLE_DEFEATED);
} }
return true; return true;
} }
@@ -19,7 +19,6 @@
#define DEF_BLOOD_FURNACE_H #define DEF_BLOOD_FURNACE_H
#include "CreatureAIImpl.h" #include "CreatureAIImpl.h"
#include "Player.h"
#define DataHeader "BF" #define DataHeader "BF"
@@ -92,7 +92,7 @@ enum KTSpells
SPELL_KAEL_EXPLODES4 = 36354, SPELL_KAEL_EXPLODES4 = 36354,
SPELL_KAEL_EXPLODES5 = 36092, SPELL_KAEL_EXPLODES5 = 36092,
SPELL_GROW = 36184, SPELL_GROW = 36184,
SPELL_KEAL_STUNNED = 36185, SPELL_KAEL_STUNNED = 36185,
SPELL_KAEL_FULL_POWER = 36187, SPELL_KAEL_FULL_POWER = 36187,
SPELL_FLOATING_DROWNED = 36550, SPELL_FLOATING_DROWNED = 36550,
SPELL_DARK_BANISH_STATE = 52241, // wrong visual apparently SPELL_DARK_BANISH_STATE = 52241, // wrong visual apparently
@@ -153,8 +153,7 @@ enum KTMisc
{ {
POINT_MIDDLE = 1, POINT_MIDDLE = 1,
POINT_AIR = 2, POINT_AIR = 2,
POINT_LAND = 3, POINT_START_LAST_PHASE = 3,
POINT_START_LAST_PHASE = 4,
DATA_RESURRECT_CAST = 1, DATA_RESURRECT_CAST = 1,
@@ -191,7 +190,9 @@ enum KTTransitionScene
EVENT_SCENE_13 = 62, EVENT_SCENE_13 = 62,
EVENT_SCENE_14 = 63, EVENT_SCENE_14 = 63,
EVENT_SCENE_15 = 64, EVENT_SCENE_15 = 64,
EVENT_SCENE_16 = 65 EVENT_SCENE_16 = 65,
EVENT_SCENE_17 = 66,
EVENT_SCENE_18 = 67
}; };
enum KTActions enum KTActions
@@ -280,7 +281,7 @@ struct boss_kaelthas : public BossAI
_phase = PHASE_NONE; _phase = PHASE_NONE;
_transitionSceneReached = false; _transitionSceneReached = false;
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_HOVER, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_HOVER, true); // hover effect 36550 - Floating Drowned
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
SetRoomState(GO_STATE_READY); SetRoomState(GO_STATE_READY);
@@ -405,13 +406,17 @@ struct boss_kaelthas : public BossAI
void MovementInform(uint32 type, uint32 point) override void MovementInform(uint32 type, uint32 point) override
{ {
if (type != POINT_MOTION_TYPE) if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
return; return;
if (point == POINT_MIDDLE) if (point == POINT_MIDDLE)
{ {
ExecuteMiddleEvent(); ExecuteMiddleEvent();
} }
else if (point == POINT_AIR)
{
me->SetDisableGravity(true, false, false); // updating AnimationTier will break drowning animation later
}
else if (point == POINT_START_LAST_PHASE) else if (point == POINT_START_LAST_PHASE)
{ {
me->SetDisableGravity(false); me->SetDisableGravity(false);
@@ -479,6 +484,8 @@ struct boss_kaelthas : public BossAI
void ExecuteMiddleEvent() void ExecuteMiddleEvent()
{ {
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->RemoveAllAttackers();
scheduler.ClearValidator(); scheduler.ClearValidator();
me->SetTarget(); me->SetTarget();
me->SetFacingTo(M_PI); me->SetFacingTo(M_PI);
@@ -498,7 +505,7 @@ struct boss_kaelthas : public BossAI
trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false);
me->SetDisableGravity(true); me->SetDisableGravity(true);
me->SendMovementFlagUpdate(); me->SendMovementFlagUpdate();
me->GetMotionMaster()->MoveTakeoff(POINT_AIR, me->GetPositionX(), me->GetPositionY(), 75.0f, 2.99); me->GetMotionMaster()->MoveTakeoff(POINT_AIR, me->GetPositionX(), me->GetPositionY(), 75.0f, 2.99, true); // AnimType Movement::ToFly does not exist for Kael
DoCastSelf(SPELL_GROW, true); DoCastSelf(SPELL_GROW, true);
}, EVENT_SCENE_3); }, EVENT_SCENE_3);
ScheduleUniqueTimedEvent(7000ms, [&] ScheduleUniqueTimedEvent(7000ms, [&]
@@ -538,8 +545,6 @@ struct boss_kaelthas : public BossAI
me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA2); me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA2);
me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA3); me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA3);
DoCastSelf(SPELL_KAEL_EXPLODES5, true); DoCastSelf(SPELL_KAEL_EXPLODES5, true);
DoCastSelf(SPELL_FLOATING_DROWNED);
//me->CastSpell(me, SPELL_KEAL_STUNNED, true);
}, EVENT_SCENE_8); }, EVENT_SCENE_8);
ScheduleUniqueTimedEvent(22000ms, [&] ScheduleUniqueTimedEvent(22000ms, [&]
{ {
@@ -580,25 +585,34 @@ struct boss_kaelthas : public BossAI
if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX()-5, me->GetPositionY()+5, me->GetPositionZ()+15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX()-5, me->GetPositionY()+5, me->GetPositionZ()+15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000))
trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true);
}, EVENT_SCENE_14); }, EVENT_SCENE_14);
ScheduleUniqueTimedEvent(30500ms, [&]
{
me->SetFacingTo(M_PI);
me->RemoveAurasDueToSpell(SPELL_FLOATING_DROWNED);
me->CastStop();
}, EVENT_SCENE_15);
ScheduleUniqueTimedEvent(30700ms, [&]
{
me->CastStop();
DoCastSelf(SPELL_KAEL_FULL_POWER);
}, EVENT_SCENE_16);
ScheduleUniqueTimedEvent(32000ms, [&] ScheduleUniqueTimedEvent(32000ms, [&]
{ {
me->RemoveAurasDueToSpell(SPELL_FLOATING_DROWNED);
me->RemoveAurasDueToSpell(SPELL_KEAL_STUNNED);
DoCastSelf(SPELL_KAEL_FULL_POWER);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true); DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
DoCastSelf(SPELL_PURE_NETHER_BEAM4, true); DoCastSelf(SPELL_PURE_NETHER_BEAM4, true);
DoCastSelf(SPELL_PURE_NETHER_BEAM5, true); DoCastSelf(SPELL_PURE_NETHER_BEAM5, true);
DoCastSelf(SPELL_PURE_NETHER_BEAM6, true); DoCastSelf(SPELL_PURE_NETHER_BEAM6, true);
}, EVENT_SCENE_15); }, EVENT_SCENE_17);
ScheduleUniqueTimedEvent(36000ms, [&] ScheduleUniqueTimedEvent(36000ms, [&]
{ {
summons.DespawnEntry(WORLD_TRIGGER); summons.DespawnEntry(WORLD_TRIGGER);
me->CastStop(); me->CastStop();
me->GetMotionMaster()->Clear(); me->GetMotionMaster()->Clear();
me->RemoveAurasDueToSpell(SPELL_DARK_BANISH_STATE); // WRONG VISUAL me->RemoveAurasDueToSpell(SPELL_DARK_BANISH_STATE); // WRONG VISUAL
me->GetMotionMaster()->MoveLand(POINT_LAND, me->GetPositionX(), me->GetPositionY(), 48.0f, 2.99f); // Moveland doesn't handle POINT_START_LAST_PHASE so we need to use MovePoint me->SetDisableGravity(true);
me->GetMotionMaster()->MovePoint(POINT_START_LAST_PHASE, me->GetHomePosition(), false, true); me->SendMovementFlagUpdate();
}, EVENT_SCENE_16); me->GetMotionMaster()->MoveLand(POINT_START_LAST_PHASE, me->GetHomePosition(), 2.99f);
}, EVENT_SCENE_18);
} }
void IntroduceNewAdvisor(KTYells talkIntroduction, KTActions kaelAction) void IntroduceNewAdvisor(KTYells talkIntroduction, KTActions kaelAction)
@@ -689,21 +703,10 @@ struct boss_kaelthas : public BossAI
{ {
_transitionSceneReached = true; _transitionSceneReached = true;
scheduler.CancelAll(); scheduler.CancelAll();
me->AttackStop();
me->CastStop(); me->CastStop();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_PASSIVE); me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, me->GetHomePosition(), true, true); me->GetMotionMaster()->MovePoint(POINT_MIDDLE, me->GetHomePosition(), true, true);
me->ClearUnitState(UNIT_STATE_MELEE_ATTACKING);
me->SendMeleeAttackStop();
ThreatContainer::StorageType threatList = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
{
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
{
target->AttackStop();
}
}
} }
}); });
ScheduleTimedEvent(1000ms, [&] ScheduleTimedEvent(1000ms, [&]
@@ -1349,6 +1352,27 @@ class spell_kaelthas_remove_enchanted_weapons : public SpellScript
} }
}; };
// 36092 - Kael Explodes
class spell_kaelthas_kael_explodes : public SpellScript
{
PrepareSpellScript(spell_kaelthas_kael_explodes);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
caster->CastSpell((Unit*)nullptr, SPELL_FLOATING_DROWNED, true);
// caster->CastSpell((Unit*)nullptr, SPELL_KAEL_STUNNED, true);
caster->PlayDirectSound(3320);
caster->PlayDirectSound(10845);
caster->PlayDirectSound(6539);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_kael_explodes::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_kaelthas() void AddSC_boss_kaelthas()
{ {
RegisterTheEyeAI(boss_kaelthas); RegisterTheEyeAI(boss_kaelthas);
@@ -1368,4 +1392,5 @@ void AddSC_boss_kaelthas()
RegisterSpellScript(spell_kaelthas_summon_nether_vapor); RegisterSpellScript(spell_kaelthas_summon_nether_vapor);
RegisterSpellScript(spell_kael_pyroblast); RegisterSpellScript(spell_kael_pyroblast);
RegisterSpellScript(spell_kaelthas_remove_enchanted_weapons); RegisterSpellScript(spell_kaelthas_remove_enchanted_weapons);
RegisterSpellScript(spell_kaelthas_kael_explodes);
} }
@@ -375,16 +375,6 @@ class spell_gen_bg_preparation : public AuraScript
{ {
PrepareAuraScript(spell_gen_bg_preparation) PrepareAuraScript(spell_gen_bg_preparation)
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, true);
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false);
}
void CalcPeriodic(AuraEffect const* /*effect*/, bool& isPeriodic, int32& amplitude) void CalcPeriodic(AuraEffect const* /*effect*/, bool& isPeriodic, int32& amplitude)
{ {
isPeriodic = true; isPeriodic = true;
@@ -405,9 +395,6 @@ class spell_gen_bg_preparation : public AuraScript
void Register() override void Register() override
{ {
OnEffectApply += AuraEffectApplyFn(spell_gen_bg_preparation::HandleEffectApply, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_gen_bg_preparation::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT, AURA_EFFECT_HANDLE_REAL);
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_gen_bg_preparation::CalcPeriodic, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_gen_bg_preparation::CalcPeriodic, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_bg_preparation::Update, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_bg_preparation::Update, EFFECT_0, SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT);
} }
+41
View File
@@ -4051,6 +4051,46 @@ class spell_item_gor_dreks_ointment : public SpellScript
} }
}; };
enum Skettis
{
QUEST_FIRES_OVER_SKETTIS = 11008
};
class spell_item_skyguard_blasting_charges : public SpellScript
{
PrepareSpellScript(spell_item_skyguard_blasting_charges);
void HandleOpenObject(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
if (GameObject* go = GetHitGObj())
go->UseDoorOrButton();
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Unit* kaliri = GetHitUnit())
kaliri->ToCreature()->DespawnOrUnsummon(0s, 30s);
}
SpellCastResult CheckQuest()
{
if (Player* playerCaster = GetCaster()->ToPlayer())
{
if (playerCaster->GetQuestStatus(QUEST_FIRES_OVER_SKETTIS) == QUEST_STATUS_INCOMPLETE)
return SPELL_CAST_OK;
}
return SPELL_FAILED_DONT_REPORT;
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_item_skyguard_blasting_charges::HandleOpenObject, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT);
OnEffectHitTarget += SpellEffectFn(spell_item_skyguard_blasting_charges::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
OnCheckCast += SpellCheckCastFn(spell_item_skyguard_blasting_charges::CheckQuest);
}
};
void AddSC_item_spell_scripts() void AddSC_item_spell_scripts()
{ {
RegisterSpellScript(spell_item_massive_seaforium_charge); RegisterSpellScript(spell_item_massive_seaforium_charge);
@@ -4175,4 +4215,5 @@ void AddSC_item_spell_scripts()
RegisterSpellAndAuraScriptPair(spell_item_eye_of_grillok, spell_item_eye_of_grillok_aura); RegisterSpellAndAuraScriptPair(spell_item_eye_of_grillok, spell_item_eye_of_grillok_aura);
RegisterSpellScript(spell_item_fel_mana_potion); RegisterSpellScript(spell_item_fel_mana_potion);
RegisterSpellScript(spell_item_gor_dreks_ointment); RegisterSpellScript(spell_item_gor_dreks_ointment);
RegisterSpellScript(spell_item_skyguard_blasting_charges);
} }
-1
View File
@@ -26,7 +26,6 @@
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "ScriptedGossip.h" #include "ScriptedGossip.h"
#include "Spell.h" #include "Spell.h"
#include "WorldSession.h"
// Ours // Ours
/*###### /*######