Merge branch 'master' into test-staging

This commit is contained in:
Keleborn
2026-04-10 22:41:55 -07:00
49 changed files with 460 additions and 206 deletions
@@ -0,0 +1,31 @@
-- DB update 2026_04_03_03 -> 2026_04_04_00
-- Fix Scarlet Monastery Cathedral Mograine/Whitemane encounter resetting during scripted phase
-- Disable evade during the scripted "fake death" / "Deep Sleep" / "resurrection" phase
-- to prevent JustExitedCombat auto-evade from triggering SMART_EVENT_EVADE and setting FAIL
-- Mograine: Disable evade when fake-dying (actionlist 397600)
DELETE FROM `smart_scripts` WHERE `entryorguid` = 397600 AND `source_type` = 9 AND `id` = 10;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`)
VALUES
(397600, 9, 10, 0, 0, 0, 100, 0, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Commander Mograine - Actionlist - Disable Evade');
-- Mograine: Re-enable evade when reaching Whitemane after resurrection (On Reached Point 1 chain)
-- Update id 24 to link to new id 29
UPDATE `smart_scripts` SET `link` = 29 WHERE `entryorguid` = 3976 AND `source_type` = 0 AND `id` = 24;
DELETE FROM `smart_scripts` WHERE `entryorguid` = 3976 AND `source_type` = 0 AND `id` = 29;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`)
VALUES
(3976, 0, 29, 0, 61, 0, 100, 0, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Commander Mograine - On Reached Point 1 - Enable Evade');
-- Whitemane: Disable evade when casting Deep Sleep (actionlist 397700)
DELETE FROM `smart_scripts` WHERE `entryorguid` = 397700 AND `source_type` = 9 AND `id` = 5;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`)
VALUES
(397700, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Whitemane - Actionlist - Disable Evade');
-- Whitemane: Re-enable evade when re-engaging after resurrection (actionlist 397701)
DELETE FROM `smart_scripts` WHERE `entryorguid` = 397701 AND `source_type` = 9 AND `id` = 8;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`)
VALUES
(397701, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'High Inquisitor Whitemane - Actionlist - Enable Evade');
@@ -0,0 +1,5 @@
-- DB update 2026_04_04_00 -> 2026_04_04_01
--
DELETE FROM `item_loot_template` WHERE (`Entry` = 52676) AND (`Item` IN (47241));
INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(52676, 47241, 0, 100, 0, 1, 0, 2, 2, '');
@@ -0,0 +1,2 @@
-- DB update 2026_04_04_01 -> 2026_04_05_00
UPDATE `smart_scripts` SET `event_phase_mask` = 0 WHERE `entryorguid` = 27653 AND `id` IN (2, 3);
@@ -0,0 +1,17 @@
-- DB update 2026_04_05_00 -> 2026_04_05_01
--
-- Alexstrasza the Life-Binder (Dragonblight) - Add Focusing Iris key menu_option. (Previously empty)
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 10192;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(10192, 0, 0, 'Oh great Queen of the Dragons, I have somehow misplaced my Key to the Focusing Iris. Can you find it for me?', 32832, 1, 1, 0, 0, 0, 0, '', 0, 0),
(10192, 1, 0, 'Oh great Queen of the Dragons, I have somehow misplaced my Heroic Key to the Focusing Iris. Can you find it for me?', 32836, 1, 1, 0, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 10192) AND (`SourceEntry` IN (0, 1)) AND (`SourceId` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 10192, 0, 0, 0, 8, 0, 13372, 0, 0, 0, 0, 0, '', 'must have completed Quest \'The Key to the Focusing Iris\''),
(15, 10192, 0, 0, 0, 2, 0, 44582, 1, 1, 1, 0, 0, '', 'must not have item \'Key to the Focusing Iris\''),
(15, 10192, 1, 0, 0, 8, 0, 13375, 0, 0, 0, 0, 0, '', 'must have completed Quest \'The Heroic Key to the Focusing Iris\''),
(15, 10192, 1, 0, 0, 2, 0, 44581, 1, 1, 1, 0, 0, '', 'must not have item \'Heroic Key to the Focusing Iris\'');
UPDATE `spell_dbc` SET `Targets` = 1, `Effect_1` = 24, `EffectBasePoints_1` = 1, `EffectItemType_1` = 44582 WHERE (`ID` = 60989);
UPDATE `spell_dbc` SET `Targets` = 1, `Effect_1` = 24, `EffectBasePoints_1` = 1, `EffectItemType_1` = 44581 WHERE (`ID` = 60992);
@@ -0,0 +1,9 @@
-- DB update 2026_04_05_01 -> 2026_04_05_02
-- Fix quest The Dread Relic
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 22369) 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
(22369, 0, 0, 1, 54, 0, 100, 1, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dread Relic Thrall - On Just Summoned - Set Passive'),
(22369, 0, 1, 0, 61, 0, 100, 1, 0, 0, 0, 0, 0, 0, 67, 1, 10000, 10000, 0, 0, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dread Relic Thrall - On Just Summoned - Create Timed Event'),
(22369, 0, 2, 3, 59, 0, 100, 1, 1, 0, 0, 0, 0, 0, 8, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dread Relic Thrall - Timed Event - Set Aggressive'),
(22369, 0, 3, 0, 61, 0, 100, 1, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Dread Relic Thrall - Timed Event - Attack Summoner'),
(22369, 0, 4, 0, 4, 0, 100, 4, 0, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 11, 22369, 10, 0, 0, 0, 0, 0, 0, 'Dread Relic Thrall - On Aggro - Set Data');
@@ -0,0 +1,19 @@
-- DB update 2026_04_05_02 -> 2026_04_05_03
-- Primal Ooze (6557)
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 6557) 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
(6557, 0, 0, 0, 8, 0, 100, 512, 16031, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - On Spellhit 16031 (Releasing Corrupt Ooze) - Set Event Phase 2'),
(6557, 0, 1, 0, 8, 0, 100, 513, 15702, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - On Spellhit 15702 (Filling Empty Jar) - Despawn'),
(6557, 0, 2, 0, 2, 0, 100, 1, 0, 30, 0, 0, 0, 0, 11, 14146, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - Between 0-30% Health - Cast Clone (No Repeat)'),
(6557, 0, 3, 0, 2, 0, 100, 1, 0, 30, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - Between 0-30% Health - Say Line 0 (No Repeat)'),
(6557, 0, 4, 5, 75, 2, 100, 513, 0, 10290, 3, 1000, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - Phase 2 - On Distance Creature 10290 within 3yd - Set Visibility Off'),
(6557, 0, 5, 6, 61, 2, 100, 513, 0, 0, 0, 0, 0, 0, 12, 9621, 6, 20000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - Phase 2 (Link) - Summon Gargantuan Ooze'),
(6557, 0, 6, 7, 61, 2, 100, 513, 0, 0, 0, 0, 0, 0, 11, 16032, 0, 0, 0, 0, 0, 9, 9621, 0, 10, 0, 0, 0, 0, 0, 'Primal Ooze - Phase 2 (Link) - Cast Merging Oozes on Gargantuan Ooze'),
(6557, 0, 7, 0, 61, 2, 100, 513, 0, 0, 0, 0, 0, 0, 41, 50, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Primal Ooze - Phase 2 (Link) - Despawn In 50ms');
-- Captured Felwood Ooze (10290)
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 10290) 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
(10290, 0, 0, 0, 54, 0, 100, 513, 0, 0, 0, 0, 0, 0, 29, 0, 0, 1, 0, 1, 0, 9, 6557, 0, 50, 0, 0, 0, 0, 0, 'Captured Felwood Ooze - On Just Summoned - Start Follow Closest Primal Ooze'),
(10290, 0, 1, 2, 75, 0, 100, 513, 0, 6557, 3, 500, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captured Felwood Ooze - Within 3yd of Primal Ooze - Set Visibility Off'),
(10290, 0, 2, 0, 61, 0, 100, 513, 0, 0, 0, 0, 0, 0, 41, 500, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Captured Felwood Ooze - Within 3yd (Link) - Despawn In 500ms');
@@ -0,0 +1,27 @@
-- DB update 2026_04_05_03 -> 2026_04_10_00
-- Edit Actionlists
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2840600) AND (`source_type` = 9) AND (`id` IN (0, 1, 2, 4, 5, 8, 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
(2840600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 54238, 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Cast \'Duel Aura Check 01\''),
(2840600, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 52991, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Cast \'Duel Flag\''),
(2840600, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Say Line 0'),
(2840600, 9, 4, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Say Line 1'),
(2840600, 9, 5, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Say Line 2'),
(2840600, 9, 8, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Set Event Phase 2'),
(2840600, 9, 9, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 42, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Set Invincibility Hp 1%');
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2840601) AND (`source_type` = 9) AND (`id` IN (7, 8));
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
(2840601, 9, 7, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Enable Evade'),
(2840601, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Despawn Instant');
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2840602) AND (`source_type` = 9) AND (`id` IN (5, 6));
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
(2840602, 9, 5, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Enable Evade'),
(2840602, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Despawn Instant');
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2840611) AND (`source_type` = 9) AND (`id` IN (7, 8));
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
(2840611, 9, 7, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Enable Evade'),
(2840611, 9, 8, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Initiate - Actionlist - Despawn Instant');
@@ -0,0 +1,3 @@
-- DB update 2026_04_10_00 -> 2026_04_10_01
--
UPDATE `creature_template_addon` SET `auras` = '70203' WHERE `entry` IN (37126, 38258);
@@ -0,0 +1,4 @@
-- DB update 2026_04_10_01 -> 2026_04_10_02
-- Update Conditions (Death Knight Initiate)
UPDATE `conditions` SET `SourceTypeOrReferenceId` = 20, `SourceGroup` = 0, `SourceEntry` = 28406 WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 9765) AND (`SourceEntry` = 0) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` IN (1, 47)) AND (`ConditionTarget` = 0) AND (`ConditionValue1` IN (12733, 54238)) AND (`ConditionValue2` IN (0, 8)) AND (`ConditionValue3` = 0);
+3 -26
View File
@@ -99,6 +99,7 @@ bool DBUpdater<LoginDatabaseConnection>::IsEnabled(uint32 const updateMask)
template<>
std::string DBUpdater<LoginDatabaseConnection>::GetDBModuleName()
{
// must be lowercase
return "auth";
}
@@ -137,6 +138,7 @@ bool DBUpdater<WorldDatabaseConnection>::IsEnabled(uint32 const updateMask)
template<>
std::string DBUpdater<WorldDatabaseConnection>::GetDBModuleName()
{
// must be lowercase
return "world";
}
@@ -175,35 +177,10 @@ bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask)
template<>
std::string DBUpdater<CharacterDatabaseConnection>::GetDBModuleName()
{
// must be lowercase
return "characters";
}
#ifdef MOD_PLAYERBOTS
// Playerbots Database
template<>
std::string DBUpdater<PlayerbotsDatabaseConnection>::GetConfigEntry()
{
return "Updates.Playerbots";
}
template<>
std::string DBUpdater<PlayerbotsDatabaseConnection>::GetTableName()
{
return "Playerbots";
}
template<>
std::string DBUpdater<PlayerbotsDatabaseConnection>::GetSourceDirectory()
{
return BuiltInConfig::GetSourceDirectory() + "/modules/mod-playerbots";
}
template<>
std::string DBUpdater<PlayerbotsDatabaseConnection>::GetBaseFilesDirectory()
{
return DBUpdater<PlayerbotsDatabaseConnection>::GetSourceDirectory() + "/data/sql/playerbots/base/";
}
template<>
bool DBUpdater<PlayerbotsDatabaseConnection>::IsEnabled(uint32 const updateMask)
{
+19 -7
View File
@@ -160,18 +160,30 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons
moduleList.emplace_back(itr);
// data/sql
for (auto const& itr : moduleList)
for (auto const& moduleName : moduleList)
{
std::string path = _sourceDirectory->generic_string() + "/modules/" + itr + "/data/sql/" + _dbModuleName; // modules/mod-name/data/sql/db-world
Path const p(path);
std::string path = _sourceDirectory->generic_string() + "/modules/" + moduleName + "/data/sql/"; // modules/mod-name/data/sql/
Path const p{path};
if (!is_directory(p))
continue;
DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert("MODULE") };
directories.push_back(entry);
directory_iterator const end;
for (directory_iterator itr{p}; itr != end; ++itr)
{
if (!is_directory(itr->path()))
continue;
LOG_TRACE("sql.updates", "Added applied modules file \"{}\" from remote.", p.filename().generic_string());
std::filesystem::path dirPath = itr->path(); // modules/mod-name/data/sql/db-world
std::string dirName = dirPath.filename().string(); // db-world
if (dirName.find(_dbModuleName) == std::string::npos)
continue;
DirectoryEntry const entry = { dirPath, AppliedFileEntry::StateConvert("MODULE") };
directories.push_back(entry);
LOG_TRACE("sql.updates", "Added applied modules file \"{}\" from remote.", dirPath.filename().generic_string());
}
}
}
@@ -697,6 +697,20 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
MovepointReached(Data);
}
void SmartAI::JustExitedCombat()
{
// When evade is suppressed or disabled, don't auto-evade on combat exit.
// This prevents scripted encounters (e.g. Mograine/Whitemane) from resetting
// when bosses temporarily stop fighting during scripted phases.
if (mSuppressEvade || mEvadeDisabled)
{
EngagementOver();
return;
}
CreatureAI::JustExitedCombat();
}
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
{
if (mSuppressEvade)
@@ -85,6 +85,9 @@ public:
// Called for reaction at enter to combat if not in combat yet (enemy can be nullptr)
void JustEngagedWith(Unit* enemy) override;
// Called when creature exits combat (all combat refs gone)
void JustExitedCombat() override;
// Called for reaction at stopping attack at no attackers or targets
void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override;
+9 -3
View File
@@ -974,7 +974,7 @@ bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, Con
bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const
{
return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE ||
sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL ||
sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION || sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || sourceType == CONDITION_SOURCE_TYPE_GOSSIP_HELLO ||
sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR || sourceType == CONDITION_SOURCE_TYPE_PLAYER_LOOT_TEMPLATE);
}
@@ -1808,9 +1808,15 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
return false;
}
break;
case CONDITION_SOURCE_TYPE_UNUSED_20:
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_UNUSED_20 is not in use. SourceEntry = ({}), skipped", cond->SourceEntry);
case CONDITION_SOURCE_TYPE_GOSSIP_HELLO:
{
if (!sObjectMgr->GetCreatureTemplate(cond->SourceEntry))
{
LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_GOSSIP_HELLO: creature entry {} in `condition` table does not exist in `creature_template`, ignoring.", cond->SourceEntry);
return false;
}
break;
}
case CONDITION_SOURCE_TYPE_VEHICLE_SPELL:
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup))
+1 -1
View File
@@ -142,7 +142,7 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_SPELL = 17,
CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT = 18,
CONDITION_SOURCE_TYPE_QUEST_AVAILABLE = 19,
CONDITION_SOURCE_TYPE_UNUSED_20 = 20, // placeholder
CONDITION_SOURCE_TYPE_GOSSIP_HELLO = 20,
CONDITION_SOURCE_TYPE_VEHICLE_SPELL = 21,
CONDITION_SOURCE_TYPE_SMART_EVENT = 22,
CONDITION_SOURCE_TYPE_NPC_VENDOR = 23,
@@ -2224,7 +2224,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
// Xinef: this should exclude self casts...
// Spells that don't have effectMechanics.
if (spellInfo->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(UI64LIT(1) << spellInfo->Mechanic))
if (spellInfo->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1ULL << spellInfo->Mechanic))
return true;
// The above helper uses the creature_immunities table rather than a
@@ -2247,7 +2247,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster /*= nullptr*/) const
{
// Xinef: this should exclude self casts...
if (spellInfo->Effects[index].Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(UI64LIT(1) << spellInfo->Effects[index].Mechanic))
if (spellInfo->Effects[index].Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1ULL << spellInfo->Effects[index].Mechanic))
return true;
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effects[index].Effect == SPELL_EFFECT_HEAL)
+25 -10
View File
@@ -10398,24 +10398,39 @@ void Player::ContinueTaxiFlight()
TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
float bestDist = SIZE_OF_GRIDS * SIZE_OF_GRIDS; // xinef: large value
float currDist = 0.0f;
// Use triangle inequality to find the segment the player is on.
// When distPrev + distNext < distNodes, the player projects between
// the two nodes of the segment. Resume from the end node (i).
float distPrev;
float distNext =
(nodeList[0]->x - GetPositionX()) * (nodeList[0]->x - GetPositionX()) +
(nodeList[0]->y - GetPositionY()) * (nodeList[0]->y - GetPositionY()) +
(nodeList[0]->z - GetPositionZ()) * (nodeList[0]->z - GetPositionZ());
// xinef: changed to -1, we dont want to catch last node
for (uint32 i = 0; i < nodeList.size() - 1; ++i)
for (uint32 i = 1; i < nodeList.size(); ++i)
{
TaxiPathNodeEntry const* node = nodeList[i];
TaxiPathNodeEntry const* nextNode = nodeList[i + 1];
TaxiPathNodeEntry const* prevNode = nodeList[i - 1];
// xinef: skip nodes at another map, get last valid node on current map
if (nextNode->mapid != GetMapId() || node->mapid != GetMapId())
// skip nodes at another map
if (node->mapid != GetMapId())
continue;
currDist = (node->x - GetPositionX()) * (node->x - GetPositionX()) + (node->y - GetPositionY()) * (node->y - GetPositionY()) + (node->z - GetPositionZ()) * (node->z - GetPositionZ());
if (currDist < bestDist)
distPrev = distNext;
distNext =
(node->x - GetPositionX()) * (node->x - GetPositionX()) +
(node->y - GetPositionY()) * (node->y - GetPositionY()) +
(node->z - GetPositionZ()) * (node->z - GetPositionZ());
float distNodes =
(node->x - prevNode->x) * (node->x - prevNode->x) +
(node->y - prevNode->y) * (node->y - prevNode->y) +
(node->z - prevNode->z) * (node->z - prevNode->z);
if (distPrev + distNext < distNodes)
{
startNode = i;
bestDist = currDist;
break;
}
}
@@ -1436,7 +1436,7 @@ void Player::UpdatePvPState()
if (pvpInfo.IsHostile) // in hostile area
{
if (IsInFlight()) // on taxi
if (IsInFlight() || !m_taxi.empty()) // on taxi or taxi pending resume after login
return;
if (!IsPvP() || pvpInfo.EndTimer != 0)
+72 -35
View File
@@ -74,6 +74,7 @@
#include "WorldPacket.h"
#include <algorithm>
#include <cmath>
#include <limits>
float baseMoveSpeed[MAX_MOVE_TYPE] =
{
@@ -910,6 +911,9 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit
if (!spellInfo)
return false;
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
return false;
bool immuneToAllEffects = true;
bool hasCheckedEffect = false;
@@ -940,8 +944,28 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
if (IsImmunedToSchool(spellInfo))
return true;
if (spellInfo->Id == 42292 || spellInfo->Id == 59752 || spellInfo->Id == 19574 || spellInfo->Id == 34471)
return false;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
if (schoolMask != SPELL_SCHOOL_MASK_NONE)
{
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto const& [immunitySchoolMask, immunityAuraId] : schoolList)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if ((immunitySchoolMask & schoolMask) != schoolMask)
continue;
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, immunityAuraId, immuneSpellInfo))
continue;
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
return true;
}
}
}
return false;
@@ -1204,7 +1228,8 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
if (!attacker || attacker->IsControlledByPlayer() || attacker->IsCreatedByPlayer())
{
uint32 unDamage = health < damage ? health : damage;
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr);
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr
|| attacker->GetCharmerOrOwnerGUID().IsPlayer());
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer);
}
}
@@ -2193,7 +2218,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
{
if (spellInfo->Effects[effIndex].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_SCHOOL_DAMAGE)
if (spellInfo->GetEffectMechanicMask(effIndex) & (1 << MECHANIC_BLEED))
if (spellInfo->GetEffectMechanicMask(effIndex) & (1ULL << MECHANIC_BLEED))
return false;
}
}
@@ -5489,7 +5514,7 @@ void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, ui
void Unit::RemoveMovementImpairingAuras(bool withRoot)
{
if (withRoot)
RemoveAurasWithMechanic(1 << MECHANIC_ROOT);
RemoveAurasWithMechanic(1ULL << MECHANIC_ROOT);
// Snares
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
@@ -5524,7 +5549,7 @@ void Unit::RemoveAurasWithMechanic(uint64 mechanic_mask, AuraRemoveMode removemo
void Unit::RemoveAurasByShapeShift()
{
uint64 mechanic_mask = (UI64LIT(1) << MECHANIC_SNARE) | (UI64LIT(1) << MECHANIC_ROOT);
uint64 mechanic_mask = (1ULL << MECHANIC_SNARE) | (1ULL << MECHANIC_ROOT);
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
Aura const* aura = iter->second->GetBase();
@@ -6081,12 +6106,12 @@ bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
{
SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
if (spellInfo->Mechanic && (mechanicMask & (1ULL << spellInfo->Mechanic)))
return true;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (iter->second->HasEffect(i) && spellInfo->Effects[i].Effect && spellInfo->Effects[i].Mechanic)
if (mechanicMask & (UI64LIT(1) << spellInfo->Effects[i].Mechanic))
if (mechanicMask & (1ULL << spellInfo->Effects[i].Mechanic))
return true;
}
@@ -8596,7 +8621,7 @@ float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, Da
// Torment the weak
if (spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000)
if (victim->HasAuraWithMechanic((1 << MECHANIC_SNARE) | (1 << MECHANIC_SLOW_ATTACK)))
if (victim->HasAuraWithMechanic((1ULL << MECHANIC_SNARE) | (1ULL << MECHANIC_SLOW_ATTACK)))
if (AuraEffect* aurEff = GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_GENERIC, 3263, EFFECT_0))
AddPct(DoneTotalMod, aurEff->GetAmount());
break;
@@ -8915,7 +8940,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
if (!caster || caster->GetGUID() != (*i)->GetCasterGUID())
continue;
if (mechanicMask & uint64(UI64LIT(1) << (*i)->GetMiscValue()))
if (mechanicMask & (1ULL << (*i)->GetMiscValue()))
{
if ((*i)->GetAmount() > 0)
{
@@ -9223,7 +9248,7 @@ float Unit::SpellTakenCritChance(Unit const* caster, SpellInfo const* spellProto
case SPELLFAMILY_MAGE:
// Glyph of Fire Blast
if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12)
if (HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT)))
if (HasAuraWithMechanic((1ULL << MECHANIC_STUN) | (1ULL << MECHANIC_KNOCKOUT)))
if (AuraEffect const* aurEff = caster->GetAuraEffect(56369, EFFECT_0))
crit_chance += aurEff->GetAmount();
break;
@@ -9815,6 +9840,18 @@ uint32 Unit::GetDamageImmunityMask() const
return mask;
}
bool Unit::IgnoresSchoolImmunityFromFriendlyCaster(Unit const* caster, uint32 immunityAuraId, SpellInfo const* immunitySpellInfo) const
{
if (!caster || !caster->IsFriendlyTo(this))
return false;
if (immunitySpellInfo)
return !immunitySpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS);
// Creature template immunities are loaded with a placeholder spell id.
return immunityAuraId == std::numeric_limits<uint32>::max();
}
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
@@ -9852,7 +9889,7 @@ bool Unit::IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) con
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
{
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, immunityAuraId, immuneAuraInfo))
continue;
if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
@@ -9933,7 +9970,10 @@ bool Unit::IsImmunedToSchool(Spell const* spell) const
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
if ((itr->first & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if ((itr->first & schoolMask) == schoolMask
&& !IgnoresSchoolImmunityFromFriendlyCaster(spell->GetCaster(), itr->second, immuneSpellInfo)
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
{
return true;
}
@@ -9971,7 +10011,7 @@ bool Unit::IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spel
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
{
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, immunityAuraId, immuneAuraInfo))
continue;
schoolImmunityMask |= immunitySchoolMask;
@@ -10050,6 +10090,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
Unit const* spellCaster = spell ? spell->GetCaster() : nullptr;
if (spell)
{
spellSchoolMask = spell->GetSpellSchoolMask();
@@ -10064,12 +10105,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
if (!(itr->first & spellSchoolMask))
continue;
if (immuneSpellInfo && !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS))
{
Unit const* spellCaster = spell ? spell->GetCaster() : nullptr;
if (spellCaster && spellCaster->IsFriendlyTo(this))
continue;
}
if (IgnoresSchoolImmunityFromFriendlyCaster(spellCaster, itr->second, immuneSpellInfo))
continue;
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
@@ -10369,13 +10406,13 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
// Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
mechanicMask |= (UI64LIT(1) << MECHANIC_BLEED);
mechanicMask |= (1ULL << MECHANIC_BLEED);
if (mechanicMask)
{
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
{
if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
if (mechanicMask & (1ULL << (aurEff->GetMiscValue())))
return true;
return false;
});
@@ -11220,8 +11257,8 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
if (Creature* creature = ToCreature())
{
// use creature helper which now consults creature_immunities table
if (creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE) ||
creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_DAZE))
if (creature->HasMechanicTemplateImmunity(1ULL << MECHANIC_SNARE) ||
creature->HasMechanicTemplateImmunity(1ULL << MECHANIC_DAZE))
break;
}
@@ -11242,7 +11279,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
if (creature
&& !IsPet()
&& !(IsControlledByPlayer() && IsVehicle())
&& !(creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE))
&& !(creature->HasMechanicTemplateImmunity(1ULL << MECHANIC_SNARE))
&& !(creature->IsDungeonBoss()))
{
// 1.6% for each % under 30.
@@ -11498,12 +11535,12 @@ Unit* Creature::SelectVictim()
return target;
}
// last case when creature must not go to evade mode:
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
// Note: creature does not have targeted movement generator but has attacker in this case
for (AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
if ((*itr) && CanCreatureAttack(*itr) && !(*itr)->IsPlayer() && !(*itr)->ToCreature()->HasUnitTypeMask(UNIT_MASK_CONTROLLABLE_GUARDIAN))
return nullptr;
// Don't evade if another unit has us on their threat list — evading would
// end the bidirectional combat reference and remove us from their threat list,
// causing them to lose their target (e.g. an NPC fighting a guardian whose
// CanAIAttack rejects the NPC).
if (!m_threatManager.GetThreatenedByMeList().empty())
return nullptr;
if (GetVehicle())
return nullptr;
@@ -11600,7 +11637,7 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in
// xinef: also calculate self casts, spell can be reflected for example
if (!positive)
{
int32 mechanic = spellProto->GetSpellMechanicMaskByEffectMask(effectMask);
uint64 mechanic = spellProto->GetSpellMechanicMaskByEffectMask(effectMask);
int32 durationMod;
int32 durationMod_always = 0;
@@ -11608,11 +11645,11 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in
for (uint8 i = 1; i <= MECHANIC_ENRAGED; ++i)
{
if (!(mechanic & 1 << i))
if (!(mechanic & (1ULL << i)))
continue;
// Xinef: spells affecting movement imparing effects should not reduce duration if disoriented mechanic is present
if (i == MECHANIC_SNARE && (mechanic & (1 << MECHANIC_DISORIENTED)))
if (i == MECHANIC_SNARE && (mechanic & (1ULL << MECHANIC_DISORIENTED)))
continue;
// Find total mod value (negative bonus)
@@ -15121,7 +15158,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target)
if (!spellInfo)
return nullptr;
if (target->IsImmunedToSpell(spellInfo))
if (target->IsImmunedToSpell(spellInfo, effMask, this))
return nullptr;
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+1
View File
@@ -1638,6 +1638,7 @@ public:
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType = SPELL_BLOCK_TYPE_ALL);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr);
bool IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit const* caster = nullptr);
bool IgnoresSchoolImmunityFromFriendlyCaster(Unit const* caster, uint32 immunityAuraId, SpellInfo const* immunitySpellInfo) const;
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask schoolMask) const;
[[nodiscard]] bool IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask schoolMask) const;
+2 -2
View File
@@ -1492,7 +1492,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
if (_item)
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll);
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, item->count, NEED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
@@ -1562,7 +1562,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
AllowedLooterSet looters = item->GetAllowedLooters();
Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters);
if (_item)
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll);
sScriptMgr->OnPlayerGroupRollRewardItem(player, _item, item->count, GREED, roll);
player->UpdateLootAchievements(item, roll->getLoot());
}
else
@@ -1125,6 +1125,13 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
ChatHandler chH = ChatHandler(this);
m_playerLoading = true;
// Exit vehicle on reconnect - the client has fully reset so
// the player can no longer control the vehicle. Without this
// the player is stuck: server-side still seated, but the
// client has no vehicle UI or movement control.
if (pCurrChar->GetVehicle())
pCurrChar->ExitVehicle();
pCurrChar->SendDungeonDifficulty(false);
WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20);
+6
View File
@@ -16,6 +16,7 @@
*/
#include "Battleground.h"
#include "ConditionMgr.h"
#include "BattlegroundMgr.h"
#include "Creature.h"
#include "DatabaseEnv.h"
@@ -150,6 +151,11 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
if (unit->GetNpcFlags() == UNIT_NPC_FLAG_NONE)
return;
// Check GossipHello conditions - block gossip opening if conditions not met
ConditionList gossipConditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_GOSSIP_HELLO, unit->GetEntry());
if (!sConditionMgr->IsObjectMeetToConditions(_player, unit, gossipConditions))
return;
// set faction visible if needed
if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction()))
_player->GetReputationMgr().SetVisible(factionTemplateEntry);
+20 -2
View File
@@ -441,8 +441,26 @@ bool LootItem::AllowedForPlayer(Player const* player, ObjectGuid source) const
return false;
// check quest requirements
if (needs_quest && !pProto->HasFlagCu(ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && !player->HasQuestForItem(itemid))
return false;
if (!pProto->HasFlagCu(ITEM_FLAGS_CU_IGNORE_QUEST_STATUS))
{
if (needs_quest && !player->HasQuestForItem(itemid))
return false;
// Hide quest starter items when quest is already started/rewarded,
// when unique count is already reached, or when prerequisite is missing.
if (pProto->StartQuest)
{
uint32 prevQuestId = 0;
if (Quest const* startQuest = sObjectMgr->GetQuestTemplate(pProto->StartQuest))
prevQuestId = startQuest->GetPrevQuestId();
if (player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE ||
player->GetQuestRewardStatus(pProto->StartQuest) ||
(pProto->MaxCount && player->HasItemCount(itemid, pProto->MaxCount, true)) ||
(prevQuestId && !player->GetQuestRewardStatus(prevQuestId)))
return false;
}
}
if (!sScriptMgr->OnAllowedForPlayerLootCheck(player, source))
return false;
+3 -3
View File
@@ -215,15 +215,15 @@ bool OPvPCapturePoint::DelObject(uint32 type)
bool OPvPCapturePoint::DelCapturePoint()
{
sObjectMgr->DeleteGOData(m_capturePointSpawnId);
m_capturePointSpawnId = 0;
if (_capturePoint)
{
_capturePoint->SetRespawnTime(0); // not save respawn time
_capturePoint->Delete();
}
sObjectMgr->DeleteGOData(m_capturePointSpawnId);
m_capturePointSpawnId = 0;
return true;
}
@@ -1223,7 +1223,7 @@ bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventIn
case SPELL_AURA_MECHANIC_IMMUNITY:
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
// compare mechanic
if (!spellInfo || !(spellInfo->GetAllEffectsMechanicMask() & (UI64LIT(1) << GetMiscValue())))
if (!spellInfo || !(spellInfo->GetAllEffectsMechanicMask() & (1ULL << GetMiscValue())))
return false;
break;
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
+8 -8
View File
@@ -6828,7 +6828,7 @@ SpellCastResult Spell::CheckCasterAuras(bool preventionOnly) const
return SPELL_CAST_OK;
uint8 school_immune = 0;
uint32 mechanic_immune = 0;
uint64 mechanic_immune = 0;
uint32 dispel_immune = 0;
// Check if the spell grants school or mechanic immunity.
@@ -6840,7 +6840,7 @@ SpellCastResult Spell::CheckCasterAuras(bool preventionOnly) const
if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY)
school_immune |= uint32(m_spellInfo->Effects[i].MiscValue);
else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY)
mechanic_immune |= 1 << uint32(m_spellInfo->Effects[i].MiscValue);
mechanic_immune |= 1ULL << uint32(m_spellInfo->Effects[i].MiscValue);
else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY)
dispel_immune |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue));
}
@@ -6871,13 +6871,13 @@ SpellCastResult Spell::CheckCasterAuras(bool preventionOnly) const
if (usableInStun)
{
bool foundNotStun = false;
uint32 mask = (1 << MECHANIC_STUN) | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_HORROR);
uint64 mask = (1ULL << MECHANIC_STUN) | (1ULL << MECHANIC_FREEZE) | (1ULL << MECHANIC_HORROR);
// Barkskin should skip sleep effects, sap and fears
if (m_spellInfo->Id == 22812)
mask |= 1 << MECHANIC_SAPPED | 1 << MECHANIC_HORROR | 1 << MECHANIC_SLEEP;
mask |= 1ULL << MECHANIC_SAPPED | 1ULL << MECHANIC_HORROR | 1ULL << MECHANIC_SLEEP;
// Hand of Freedom, can be used while sapped and while under fear-mechanic stuns (e.g. Intimidating Shout primary target)
if (m_spellInfo->Id == 1044)
mask |= (1 << MECHANIC_SAPPED) | (1 << MECHANIC_FEAR);
mask |= (1ULL << MECHANIC_SAPPED) | (1ULL << MECHANIC_FEAR);
Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN);
for (Unit::AuraEffectList::const_iterator i = stunAuras.begin(); i != stunAuras.end(); ++i)
{
@@ -6936,13 +6936,13 @@ SpellCastResult Spell::CheckCasterAuras(bool preventionOnly) const
{
case SPELL_AURA_MOD_STUN:
{
uint32 mask = 1 << MECHANIC_STUN;
uint64 mask = 1ULL << MECHANIC_STUN;
// Barkskin should skip sleep effects, sap and fears
if (m_spellInfo->Id == 22812)
mask |= 1 << MECHANIC_SAPPED | 1 << MECHANIC_HORROR | 1 << MECHANIC_SLEEP;
mask |= 1ULL << MECHANIC_SAPPED | 1ULL << MECHANIC_HORROR | 1ULL << MECHANIC_SLEEP;
// Hand of Freedom, can be used while sapped and while under fear-mechanic stuns (e.g. Intimidating Shout primary target)
if (m_spellInfo->Id == 1044)
mask |= (1 << MECHANIC_SAPPED) | (1 << MECHANIC_FEAR);
mask |= (1ULL << MECHANIC_SAPPED) | (1ULL << MECHANIC_FEAR);
if (!usableInStun || !(auraInfo->GetAllEffectsMechanicMask() & mask))
return SPELL_FAILED_STUNNED;
+4 -4
View File
@@ -856,7 +856,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
// Pounce Bleed shouldn't be removed by Cloak of Shadows.
if (spell->GetAllEffectsMechanicMask() & (UI64LIT(1) << MECHANIC_BLEED))
if (spell->GetAllEffectsMechanicMask() & (1ULL << MECHANIC_BLEED))
return;
bool dmgClassNone = false;
@@ -2493,8 +2493,8 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
if (properties->Category == SUMMON_CATEGORY_ALLY)
{
summon->SetOwnerGUID(m_originalCaster->GetGUID());
summon->SetFaction(m_originalCaster->GetFaction());
summon->SetOwnerGUID(summoner->GetGUID());
summon->SetFaction(summoner->GetFaction());
}
ExecuteLogEffectSummonObject(effIndex, summon);
@@ -5157,7 +5157,7 @@ void Spell::EffectDispelMechanic(SpellEffIndex effIndex)
continue;
if (roll_chance_i(aura->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster))))
{
if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (UI64LIT(1) << mechanic)))
if (aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1ULL << mechanic))
{
dispel_list.push(std::make_pair(aura->GetId(), aura->GetCasterGUID()));
+7 -7
View File
@@ -1900,10 +1900,10 @@ uint64 SpellInfo::GetAllEffectsMechanicMask() const
{
uint64 mask = 0;
if (Mechanic)
mask |= UI64LIT(1) << Mechanic;
mask |= 1ULL << Mechanic;
for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (Effects[i].IsEffect() && Effects[i].Mechanic)
mask |= UI64LIT(1) << Effects[i].Mechanic;
mask |= 1ULL << Effects[i].Mechanic;
return mask;
}
@@ -1911,9 +1911,9 @@ uint64 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const
{
uint64 mask = 0;
if (Mechanic)
mask |= UI64LIT(1) << Mechanic;
mask |= 1ULL << Mechanic;
if (Effects[effIndex].IsEffect() && Effects[effIndex].Mechanic)
mask |= UI64LIT(1) << Effects[effIndex].Mechanic;
mask |= 1ULL << Effects[effIndex].Mechanic;
return mask;
}
@@ -1921,10 +1921,10 @@ uint64 SpellInfo::GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
{
uint64 mask = 0;
if (Mechanic)
mask |= UI64LIT(1) << Mechanic;
mask |= 1ULL << Mechanic;
for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
if ((effectMask & (1 << i)) && Effects[i].Mechanic)
mask |= UI64LIT(1) << Effects[i].Mechanic;
mask |= 1ULL << Effects[i].Mechanic;
return mask;
}
@@ -2008,7 +2008,7 @@ AuraStateType SpellInfo::LoadAuraState() const
return AURA_STATE_ENRAGE;
// Bleeding aura state
if (GetAllEffectsMechanicMask() & (UI64LIT(1) << MECHANIC_BLEED))
if (GetAllEffectsMechanicMask() & (1ULL << MECHANIC_BLEED))
return AURA_STATE_BLEEDING;
// Banished aura state
+1 -1
View File
@@ -705,7 +705,7 @@ public:
handler->PSendSysMessage(LANG_NPCINFO_MECHANIC_IMMUNE, Acore::StringFormat("0x{:X}", mechanicImmuneMask).c_str());
for (uint8 i = 1; i < MAX_MECHANIC; ++i)
if (mechanicImmuneMask & (UI64LIT(1) << i))
if (mechanicImmuneMask & (1ULL << i))
handler->PSendSysMessage(mechanicImmunes[i].text, mechanicImmunes[i].flag);
handler->PSendSysMessage(LANG_NPCINFO_SPELL_SCHOOL_IMMUNE, spellSchoolImmuneMask);
@@ -80,6 +80,7 @@ enum Events
EVENT_MIGHT_OF_RAGNAROS,
EVENT_LAVA_BURST,
EVENT_MAGMA_BLAST,
EVENT_MELEE_SCAN,
EVENT_SUBMERGE,
EVENT_LAVA_BURST_TRIGGER,
@@ -218,29 +219,6 @@ struct boss_ragnaros : public BossAI
DoStartNoMovement(target);
}
void EnterEvadeMode(EvadeReason why) override
{
if (!me->GetThreatMgr().IsThreatListEmpty())
{
if (!_processingMagmaBurst)
{
// Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED);
}
}
else
{
BossAI::EnterEvadeMode(why);
}
}
bool CanAIAttack(Unit const* victim) const override
{
// Used for Magma Blast handling to force EnterEvadeMode if there are no melee targets
return me->IsWithinMeleeRange(victim);
}
void UpdateAI(uint32 diff) override
{
if (!extraEvents.Empty())
@@ -307,10 +285,7 @@ struct boss_ragnaros : public BossAI
}
if (!UpdateVictim())
{
if (!_processingMagmaBurst)
return;
}
return;
events.Update(diff);
@@ -348,19 +323,47 @@ struct boss_ragnaros : public BossAI
DoCastAOE(SPELL_LAVA_BURST);
break;
}
case EVENT_MELEE_SCAN:
{
// ReselectVictim() in the threat system already prefers
// in-melee-range targets, so if the current victim is out
// of melee range it means *nobody* is in range. Use that
// as the trigger for the Magma Blast fallback.
if (!IsVictimWithinMeleeRange())
{
if (!_processingMagmaBurst)
{
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED);
}
}
else if (_processingMagmaBurst)
{
events.CancelEvent(EVENT_MAGMA_BLAST);
_processingMagmaBurst = false;
}
events.Repeat(500ms);
break;
}
case EVENT_MAGMA_BLAST:
{
_processingMagmaBurst = false;
if (!IsVictimWithinMeleeRange())
if (IsVictimWithinMeleeRange())
break;
if (Unit* victim = me->GetVictim())
{
DoCastRandomTarget(SPELL_MAGMA_BLAST);
DoCast(victim, SPELL_MAGMA_BLAST);
if (!_hasYelledMagmaBurst)
{
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
_processingMagmaBurst = true;
events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED);
}
break;
@@ -454,12 +457,14 @@ private:
events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_SUBMERGE, 180s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11s, PHASE_EMERGED, PHASE_EMERGED);
events.RescheduleEvent(EVENT_MELEE_SCAN, 500ms, PHASE_EMERGED, PHASE_EMERGED);
}
bool IsVictimWithinMeleeRange() const
{
return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim());
}
};
constexpr std::array<uint32, 8> RagnarosLavaBurstSpells = { SPELL_LAVA_BURST_A, SPELL_LAVA_BURST_B, SPELL_LAVA_BURST_C, SPELL_LAVA_BURST_D, SPELL_LAVA_BURST_E, SPELL_LAVA_BURST_F, SPELL_LAVA_BURST_G, SPELL_LAVA_BURST_H };
+30 -3
View File
@@ -19,6 +19,7 @@
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellAuras.h"
enum Orphans
@@ -628,9 +629,33 @@ private:
/*######
## npc_cw_alexstrasza_trigger
######*/
enum eAlexstrasza
{
SPELL_KEY_TO_FOCUSING_IRIS = 60989,
SPELL_HEROIC_KEY_TO_FOCUSING_IRIS = 60992,
};
struct npc_alexstraza_the_lifebinder : public ScriptedAI
{
npc_alexstraza_the_lifebinder(Creature* creature) : ScriptedAI(creature) {}
explicit npc_alexstraza_the_lifebinder(Creature* creature) : ScriptedAI(creature) {}
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case 0:
CloseGossipMenuFor(player);
player->CastSpell(player, SPELL_KEY_TO_FOCUSING_IRIS, false);
break;
case 1:
CloseGossipMenuFor(player);
player->CastSpell(player, SPELL_HEROIC_KEY_TO_FOCUSING_IRIS, false);
break;
default:
break;
}
}
void Reset() override
{
@@ -653,6 +678,8 @@ struct npc_alexstraza_the_lifebinder : public ScriptedAI
case 2:
me->SetOrientation(me->GetHomePosition().GetOrientation());
break;
default:
break;
}
}
}
@@ -767,8 +794,8 @@ struct npc_alexstraza_the_lifebinder : public ScriptedAI
}
private:
int8 phase;
uint32 timer;
int8 phase{};
uint32 timer{};
ObjectGuid playerGUID;
ObjectGuid orphanGUID;
};
@@ -136,7 +136,7 @@ enum Misc
// Movement points
POINT_LANDING = 1,
// Lava directions. Its used to identify to which side lava was moving by last time
// Lava directions
LAVA_LEFT_SIDE = 0,
LAVA_RIGHT_SIDE = 1,
@@ -307,7 +307,6 @@ struct boss_sartharion : public BossAI
{
explicit boss_sartharion(Creature* creature) : BossAI(creature, DATA_SARTHARION),
dragonsCount(0),
lastLavaSide(LAVA_RIGHT_SIDE),
usedBerserk(false),
below11PctReached(false)
{
@@ -628,8 +627,8 @@ private:
extraEvents.ScheduleEvent(EVENT_SARTHARION_START_LAVA, 3600ms);
extraEvents.ScheduleEvent(EVENT_SARTHARION_FINISH_LAVA, 11s);
// Send wave from left
if (lastLavaSide == LAVA_RIGHT_SIDE)
// Randomly choose which side the wave comes from
if (urand(LAVA_LEFT_SIDE, LAVA_RIGHT_SIDE) == LAVA_LEFT_SIDE)
{
for (uint8 i = 0; i < MAX_LEFT_LAVA_TSUNAMIS; ++i)
{
@@ -638,10 +637,7 @@ private:
if (((i - 1) % 3 == 0) && tsunami) // If center of wave
tsunami->CastSpell(tsunami, SPELL_FLAME_TSUNAMI_VISUAL, true);
}
lastLavaSide = LAVA_LEFT_SIDE;
}
// from right
else
{
for (uint8 i = 0; i < MAX_RIGHT_LAVA_TSUNAMIS; ++i)
@@ -651,8 +647,6 @@ private:
if (((i - 1) % 3 == 0) && tsunami) // If center of wave
tsunami->CastSpell(tsunami, SPELL_FLAME_TSUNAMI_VISUAL, true);
}
lastLavaSide = LAVA_RIGHT_SIDE;
}
}
@@ -683,7 +677,6 @@ private:
EventMap extraEvents;
std::list<uint32> volcanoBlows;
uint8 dragonsCount;
uint8 lastLavaSide; // 0 = left, 1 = right
bool usedBerserk;
bool below11PctReached;
};
@@ -224,7 +224,7 @@ class spell_uk_second_wind : public AuraScript
if (!spellInfo)
return false;
return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0;
return (spellInfo->GetAllEffectsMechanicMask() & ((1ULL << MECHANIC_ROOT) | (1ULL << MECHANIC_STUN))) != 0;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
@@ -128,7 +128,7 @@ struct boss_lady_vashj : public BossAI
summon->CastSpell(summon, SPELL_MAGIC_BARRIER);
break;
case NPC_ENCHANTED_ELEMENTAL:
summon->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, false);
summon->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, false, false);
summon->SetWalk(true);
summon->SetReactState(REACT_PASSIVE);
break;
@@ -242,10 +242,11 @@ struct boss_magtheridon : public BossAI
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
scheduler.Update(diff);
_interruptScheduler.Update(diff);
if (_currentPhase != 1 && !_castingQuake)
@@ -385,11 +385,11 @@ public:
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (attacker && attacker->GetCharmerOrOwnerOrOwnGUID().IsPlayer() && damage > 0 && !me->isActiveObject())
if (attacker && attacker->GetCharmerOrOwnerOrOwnGUID().IsPlayer() && damage > 0 && instance->GetBossState(DATA_WARDEN_MELLICHAR) != IN_PROGRESS)
{
me->setActive(true);
me->InterruptNonMeleeSpells(false);
me->SetImmuneToAll(true);
me->SetImmuneToAll(true, true);
events.ScheduleEvent(EVENT_WARDEN_INTRO1, 1500ms);
events.ScheduleEvent(EVENT_WARDEN_CHECK_PLAYERS, 1s);
instance->SetBossState(DATA_WARDEN_MELLICHAR, IN_PROGRESS);
+1 -1
View File
@@ -3001,7 +3001,7 @@ class spell_dk_pvp_4p_bonus : public AuraScript
if (!spellInfo)
return false;
return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0;
return (spellInfo->GetAllEffectsMechanicMask() & ((1ULL << MECHANIC_ROOT) | (1ULL << MECHANIC_SNARE))) != 0;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+2 -2
View File
@@ -770,7 +770,7 @@ class spell_dru_moonkin_form_passive : public AuraScript
void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount)
{
// reduces all damage taken while Stunned in Moonkin Form
if (GetTarget()->GetUnitFlags() & (UNIT_FLAG_STUNNED) && GetTarget()->HasAuraWithMechanic(1 << MECHANIC_STUN))
if (GetTarget()->GetUnitFlags() & (UNIT_FLAG_STUNNED) && GetTarget()->HasAuraWithMechanic(1ULL << MECHANIC_STUN))
absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct);
}
@@ -837,7 +837,7 @@ class spell_dru_primal_tenacity : public AuraScript
void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount)
{
// reduces all damage taken while Stunned in Cat Form
if (GetTarget()->GetShapeshiftForm() == FORM_CAT && GetTarget()->HasUnitFlag(UNIT_FLAG_STUNNED) && GetTarget()->HasAuraWithMechanic(1 << MECHANIC_STUN))
if (GetTarget()->GetShapeshiftForm() == FORM_CAT && GetTarget()->HasUnitFlag(UNIT_FLAG_STUNNED) && GetTarget()->HasAuraWithMechanic(1ULL << MECHANIC_STUN))
absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct);
}
+2 -2
View File
@@ -4372,7 +4372,7 @@ class spell_item_luffa : public SpellScript
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
Aura const* aura = itr->second->GetBase();
if (!(aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << MECHANIC_BLEED)) || aura->GetCasterLevel() > 60 || aura->GetSpellInfo()->IsPositive())
if (!(aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1ULL << MECHANIC_BLEED)) || aura->GetCasterLevel() > 60 || aura->GetSpellInfo()->IsPositive())
continue;
return SPELL_CAST_OK;
@@ -4392,7 +4392,7 @@ class spell_item_luffa : public SpellScript
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
Aura const* aura = itr->second->GetBase();
if (!(aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << MECHANIC_BLEED)) || aura->GetCasterLevel() > 60 || aura->GetSpellInfo()->IsPositive())
if (!(aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1ULL << MECHANIC_BLEED)) || aura->GetCasterLevel() > 60 || aura->GetSpellInfo()->IsPositive())
continue;
player->RemoveAurasDueToSpell(aura->GetId(), aura->GetCasterGUID());
+1 -1
View File
@@ -120,7 +120,7 @@ class spell_mage_burning_determination : public AuraScript
return false;
// Need Interrupt or Silenced mechanic
if (!(eventInfo.GetSpellInfo()->GetAllEffectsMechanicMask() & ((1 << MECHANIC_INTERRUPT) | (1 << MECHANIC_SILENCE))))
if (!(eventInfo.GetSpellInfo()->GetAllEffectsMechanicMask() & ((1ULL << MECHANIC_INTERRUPT) | (1ULL << MECHANIC_SILENCE))))
return false;
// Xinef: immuned effect should just eat charge
+1 -1
View File
@@ -1486,7 +1486,7 @@ class spell_pal_divine_purpose : public AuraScript
{
PreventDefaultAction();
if (Unit* target = eventInfo.GetActionTarget())
target->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
target->RemoveAurasWithMechanic(1ULL << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
}
void Register() override
+1 -1
View File
@@ -473,7 +473,7 @@ class spell_pri_mana_burn : public SpellScript
void HandleAfterHit()
{
if (Unit* unitTarget = GetHitUnit())
unitTarget->RemoveAurasWithMechanic((1 << MECHANIC_FEAR) | (1 << MECHANIC_POLYMORPH));
unitTarget->RemoveAurasWithMechanic((1ULL << MECHANIC_FEAR) | (1ULL << MECHANIC_POLYMORPH));
}
void Register() override
+2 -2
View File
@@ -735,13 +735,13 @@ class spell_rog_vanish_purge : public SpellScript
void HandleRootRemove(SpellEffIndex /*effIndex*/)
{
if (GetCaster() && !GetCaster()->HasAura(SPELL_PARALYZE)) // Root from Tainted Core SSC, should not be removed by vanish.
GetCaster()->RemoveAurasWithMechanic(1 << MECHANIC_ROOT);
GetCaster()->RemoveAurasWithMechanic(1ULL << MECHANIC_ROOT);
}
void HandleSnareRemove(SpellEffIndex /*effIndex*/)
{
if (GetCaster())
GetCaster()->RemoveAurasWithMechanic(1 << MECHANIC_SNARE);
GetCaster()->RemoveAurasWithMechanic(1ULL << MECHANIC_SNARE);
}
void Register() override
+1 -1
View File
@@ -1494,7 +1494,7 @@ class spell_sha_astral_shift_aura : public AuraScript
bool CheckProc(ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
if (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR)))
if (spellInfo->GetAllEffectsMechanicMask() & ((1ULL << MECHANIC_SILENCE) | (1ULL << MECHANIC_STUN) | (1ULL << MECHANIC_FEAR)))
return true;
return false;
+1 -1
View File
@@ -927,7 +927,7 @@ class spell_warl_demonic_circle_teleport : public AuraScript
if (GameObject* circle = player->GetGameObject(SPELL_WARLOCK_DEMONIC_CIRCLE_SUMMON))
{
player->NearTeleportTo(circle->GetPositionX(), circle->GetPositionY(), circle->GetPositionZ(), circle->GetOrientation(), false, false, false, true);
player->RemoveAurasWithMechanic(1 << MECHANIC_SNARE);
player->RemoveAurasWithMechanic(1ULL << MECHANIC_SNARE);
}
}
}
+2 -2
View File
@@ -612,7 +612,7 @@ class spell_warr_shattering_throw : public SpellScript
// remove shields, will still display immune to damage part
if (Unit* target = GetHitUnit())
target->RemoveAurasWithMechanic(1 << MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
target->RemoveAurasWithMechanic(1ULL << MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
}
void Register() override
@@ -1013,7 +1013,7 @@ class spell_warr_second_wind : public AuraScript
return false;
// Must be from stun or root mechanic
if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))))
if (!(procSpell->GetAllEffectsMechanicMask() & ((1ULL << MECHANIC_ROOT) | (1ULL << MECHANIC_STUN))))
return false;
// Not from self
+16 -16
View File
@@ -1352,22 +1352,22 @@ enum Mechanics : uint32
// Used for spell 42292 Immune Movement Impairment and Loss of Control (0x49967ca6)
inline constexpr uint64 IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK =
(UI64LIT(1) << MECHANIC_CHARM) |
(UI64LIT(1) << MECHANIC_DISORIENTED) |
(UI64LIT(1) << MECHANIC_FEAR) |
(UI64LIT(1) << MECHANIC_ROOT) |
(UI64LIT(1) << MECHANIC_SLEEP) |
(UI64LIT(1) << MECHANIC_SNARE) |
(UI64LIT(1) << MECHANIC_STUN) |
(UI64LIT(1) << MECHANIC_FREEZE) |
(UI64LIT(1) << MECHANIC_KNOCKOUT) |
(UI64LIT(1) << MECHANIC_POLYMORPH) |
(UI64LIT(1) << MECHANIC_BANISH) |
(UI64LIT(1) << MECHANIC_SHACKLE) |
(UI64LIT(1) << MECHANIC_TURN) |
(UI64LIT(1) << MECHANIC_HORROR) |
(UI64LIT(1) << MECHANIC_DAZE) |
(UI64LIT(1) << MECHANIC_SAPPED);
(1ULL << MECHANIC_CHARM) |
(1ULL << MECHANIC_DISORIENTED) |
(1ULL << MECHANIC_FEAR) |
(1ULL << MECHANIC_ROOT) |
(1ULL << MECHANIC_SLEEP) |
(1ULL << MECHANIC_SNARE) |
(1ULL << MECHANIC_STUN) |
(1ULL << MECHANIC_FREEZE) |
(1ULL << MECHANIC_KNOCKOUT) |
(1ULL << MECHANIC_POLYMORPH) |
(1ULL << MECHANIC_BANISH) |
(1ULL << MECHANIC_SHACKLE) |
(1ULL << MECHANIC_TURN) |
(1ULL << MECHANIC_HORROR) |
(1ULL << MECHANIC_DAZE) |
(1ULL << MECHANIC_SAPPED);
// Spell dispel type
enum DispelType : uint8
@@ -22,6 +22,7 @@
#include "gtest/gtest.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include "Unit.h" // needed for SpellSchoolMask and mask helper
@@ -79,30 +80,24 @@ namespace
bool HasOnlyDamageEffects(SpellDesc const& spell)
{
bool hasAny = false;
for (EffectDesc const& e : spell.effects)
bool hasAny = std::ranges::any_of(spell.effects, [](EffectDesc const& effect)
{
if (e.effect == EFFECT_NONE)
continue;
return effect.effect != EFFECT_NONE;
});
hasAny = true;
if (!IsDamageEffect(e.effect))
return false;
}
return hasAny;
return hasAny && std::ranges::all_of(spell.effects, [](EffectDesc const& effect)
{
return effect.effect == EFFECT_NONE || IsDamageEffect(effect.effect);
});
}
// Helper to classify spells which apply a stun aura
bool IsStunSpell(SpellDesc const& spell)
{
for (EffectDesc const& e : spell.effects)
return std::ranges::any_of(spell.effects, [](EffectDesc const& effect)
{
if (e.effect == EFFECT_APPLY_AURA && e.aura == AURA_MOD_STUN)
return true;
}
return false;
return effect.effect == EFFECT_APPLY_AURA && effect.aura == AURA_MOD_STUN;
});
}
bool IsEffectBlockedByStunImmunity(EffectDesc const& effect, bool immuneToStun)
@@ -130,6 +125,11 @@ namespace
return hasAnyEffect;
}
bool IsBlockedBySchoolImmunity(bool casterFriendly, bool immunityAppliesToFriendly)
{
return !casterFriendly || immunityAppliesToFriendly;
}
// The last parameter defaults to false to avoid updating existing tests
// that don't care about mechanic immunities. Bladestorm grants a
// specific mechanic immunity (including stun) that should block
@@ -364,3 +364,18 @@ TEST(SpellImmunityTest, StunImmunity_DoesNotFullyBlockMixedSpell)
EXPECT_TRUE(IsStunSpell(mixedSpell));
EXPECT_EQ(ComputeSpellHitResult(false, false, mixedSpell, true), SPELL_MISS_NONE);
}
TEST(SpellImmunityTest, SchoolImmunity_TemplateStyle_AllowsFriendlySpell)
{
EXPECT_FALSE(IsBlockedBySchoolImmunity(true, false));
}
TEST(SpellImmunityTest, SchoolImmunity_ExplicitFriendlyBlockStillApplies)
{
EXPECT_TRUE(IsBlockedBySchoolImmunity(true, true));
}
TEST(SpellImmunityTest, SchoolImmunity_BlocksHostileSpell)
{
EXPECT_TRUE(IsBlockedBySchoolImmunity(false, false));
}