From cbd3fd0967fd94a2a9eb96aaf55ebd69f32aa918 Mon Sep 17 00:00:00 2001 From: IntelligentQuantum Date: Sun, 2 Oct 2022 21:09:34 +0330 Subject: [PATCH 01/25] refactor(Core/Spells): Implement QAston Proc System (#11079) * . * sql * . * . * 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * Update spell_item.cpp * Update Unit.cpp * 16 * 17 * 18 * 19 * 20 * 21 * Update Unit.cpp * REVERT UltraNIX Commit * 22 * 23 * . * . * . * warrior * warlock * shaman rogue priest paladin mage * spell item * hunter * druid * dk * war * error style * Update rev_1647677899565690722.sql * Update rev_1647677899565690722.sql * Update rev_1647677899565690722.sql * . * DOND DEL ME WAD DO DO * error 2 * . * . * . * FIX * Update SpellInfoCorrections.cpp * Update SpellInfoCorrections.cpp * . * ja genau * Update .gitignore * . * . * ., * . * . * . * . * Update Unit.cpp --- .gitignore | 1 + .../rev_1647677899565690722.sql | 1100 ++++ src/server/game/Combat/ThreatMgr.cpp | 2 +- .../game/Entities/Creature/Creature.cpp | 4 +- src/server/game/Entities/Player/Player.cpp | 215 +- src/server/game/Entities/Player/Player.h | 230 +- src/server/game/Entities/Unit/Unit.cpp | 4783 ++--------------- src/server/game/Entities/Unit/Unit.h | 77 +- src/server/game/Handlers/CharacterHandler.cpp | 2 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 203 +- .../game/Spells/Auras/SpellAuraEffects.h | 3 +- src/server/game/Spells/Auras/SpellAuras.cpp | 205 +- src/server/game/Spells/Auras/SpellAuras.h | 18 +- src/server/game/Spells/Spell.cpp | 264 +- src/server/game/Spells/Spell.h | 26 +- src/server/game/Spells/SpellDefines.h | 62 +- src/server/game/Spells/SpellEffects.cpp | 52 +- src/server/game/Spells/SpellInfo.cpp | 42 +- src/server/game/Spells/SpellInfo.h | 4 +- .../game/Spells/SpellInfoCorrections.cpp | 10 +- src/server/game/Spells/SpellMgr.cpp | 590 +- src/server/game/Spells/SpellMgr.h | 107 +- src/server/game/Spells/SpellScript.cpp | 15 + src/server/game/Spells/SpellScript.h | 23 +- src/server/game/World/World.cpp | 5 +- src/server/scripts/Commands/cs_reload.cpp | 10 - .../BattleForMountHyjal/boss_anetheron.cpp | 54 +- .../TrialOfTheCrusader/boss_twin_valkyr.cpp | 2 +- .../boss_blood_prince_council.cpp | 20 + .../boss_deathbringer_saurfang.cpp | 40 +- .../boss_professor_putricide.cpp | 54 + .../IcecrownCitadel/icecrown_citadel.cpp | 2 +- .../Ulduar/Ulduar/boss_yoggsaron.cpp | 2 + .../UtgardeKeep/UtgardeKeep/utgarde_keep.cpp | 52 + .../ShadowLabyrinth/shadow_labyrinth.cpp | 58 + .../scripts/Outland/boss_doomlord_kazzak.cpp | 60 +- .../scripts/Outland/outland_script_loader.cpp | 2 + src/server/scripts/Pet/pet_hunter.cpp | 173 + src/server/scripts/Pet/pet_priest.cpp | 10 +- src/server/scripts/Spells/spell_dk.cpp | 464 +- src/server/scripts/Spells/spell_druid.cpp | 646 ++- src/server/scripts/Spells/spell_generic.cpp | 50 +- src/server/scripts/Spells/spell_hunter.cpp | 315 +- src/server/scripts/Spells/spell_item.cpp | 1575 +++++- src/server/scripts/Spells/spell_mage.cpp | 401 +- src/server/scripts/Spells/spell_paladin.cpp | 701 ++- src/server/scripts/Spells/spell_priest.cpp | 418 +- src/server/scripts/Spells/spell_rogue.cpp | 159 +- src/server/scripts/Spells/spell_shaman.cpp | 1106 +++- src/server/scripts/Spells/spell_warlock.cpp | 376 +- src/server/scripts/Spells/spell_warrior.cpp | 254 +- src/server/shared/DataStores/DBCStructure.h | 2 +- src/server/shared/SharedDefines.h | 10 +- src/server/shared/enuminfo_SharedDefines.cpp | 24 +- 54 files changed, 9126 insertions(+), 5957 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1647677899565690722.sql create mode 100644 src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp diff --git a/.gitignore b/.gitignore index 756f81587..23193e9c8 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ nbproject/ cmake-build-debug/* cmake-build-debug-coverage/* cmake-build-debug-event-trace/* +cmake-build-debug-visual-studio/* coverage-report/ # diff --git a/data/sql/updates/pending_db_world/rev_1647677899565690722.sql b/data/sql/updates/pending_db_world/rev_1647677899565690722.sql new file mode 100644 index 000000000..f12d9986a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1647677899565690722.sql @@ -0,0 +1,1100 @@ +-- Earth shield heal is DAMAGE_CLASS_NONE, it won't scale +-- Entry is unneeded +DELETE FROM `spell_bonus_data` WHERE `entry`=379; + +ALTER TABLE `spell_proc` + CHANGE `spellId` `SpellId` int(11) NOT NULL DEFAULT 0 FIRST, + CHANGE `schoolMask` `SchoolMask` tinyint(3) unsigned NOT NULL DEFAULT 0 AFTER `SpellId`, + CHANGE `spellFamilyName` `SpellFamilyName` smallint(5) unsigned NOT NULL DEFAULT 0 AFTER `SchoolMask`, + CHANGE `spellFamilyMask0` `SpellFamilyMask0` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyName`, + CHANGE `spellFamilyMask1` `SpellFamilyMask1` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask0`, + CHANGE `spellFamilyMask2` `SpellFamilyMask2` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask1`, + CHANGE `typeMask` `ProcFlags` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask2`, + CHANGE `spellTypeMask` `SpellTypeMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `ProcFlags`, + CHANGE `spellPhaseMask` `SpellPhaseMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellTypeMask`, + CHANGE `hitMask` `HitMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellPhaseMask`, + CHANGE `attributesMask` `AttributesMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `HitMask`, + CHANGE `ratePerMinute` `ProcsPerMinute` float NOT NULL DEFAULT 0 AFTER `AttributesMask`, + CHANGE `chance` `Chance` float NOT NULL DEFAULT 0 AFTER `ProcsPerMinute`, + CHANGE `cooldown` `Cooldown` int(10) unsigned NOT NULL DEFAULT 0 AFTER `Chance`, + CHANGE `charges` `Charges` tinyint(3) unsigned NOT NULL DEFAULT 0 AFTER `Cooldown`; + +DELETE FROM `command` WHERE `name`='reload spell_proc_event'; + +DELETE FROM `spell_proc`; +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES +(17941, 0, 5, 1, 0, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), +(18820, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 1), +(22008, 0, 3, 1631584309, 0, 0, 69632, 5, 1, 0, 0, 0, 0, 0, 1), +(28200, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 6), +(-7001, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(32216, 0, 4, 0, 256, 0, 16, 1, 4, 0, 0, 0, 0, 0, 1), +(34477, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 1), +(34936, 0, 5, 1, 64, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), +(44401, 0, 3, 2048, 0, 0, 65536, 5, 1, 0, 8, 0, 0, 0, 1), +(48108, 0, 3, 4194304, 0, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), +(51124, 0, 15, 2, 6, 0, 65552, 1, 4, 0, 8, 0, 0, 0, 1), +(54741, 0, 3, 4, 0, 0, 65536, 5, 1, 0, 0, 0, 0, 0, 1), +(57761, 0, 3, 1, 4096, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), +(64823, 0, 7, 4, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 0, 1), +(-974, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), +(-10400, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-11119, 4, 3, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-11185, 0, 3, 128, 0, 0, 65536, 1, 2, 0, 2, 0, 0, 0, 0), +(-12834, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-13983, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 1000, 0), +(-14156, 0, 8, 4063232, 9, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0), +(-15337, 0, 6, 8396800, 2, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(-16180, 0, 11, 448, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(-18094, 0, 5, 10, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-47230, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(-20234, 0, 10, 32768, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(-20335, 0, 10, 8388608, 0, 0, 16, 5, 2, 0, 0, 0, 100, 0, 0), +(-27243, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-29441, 0, 0, 0, 0, 0, 0, 7, 0, 8, 0, 0, 0, 1000, 0), +(-29723, 0, 4, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-29834, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), +(-30293, 0, 5, 385, 8519872, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-30675, 0, 11, 3, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-31244, 0, 8, 3801088, 9, 0, 0, 5, 2, 11196, 0, 0, 0, 0, 0), +(-31571, 0, 3, 0, 34, 0, 16384, 7, 4, 0, 2, 0, 0, 0, 0), +(-31785, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), +(-31871, 0, 10, 16, 0, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(-31876, 0, 10, 8388608, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-34497, 0, 9, 395264, 8388609, 513, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-34914, 0, 6, 8192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-44404, 0, 3, 536870945, 36864, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-44445, 0, 3, 19, 69632, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-44546, 0, 3, 736, 4096, 0, 69632, 0, 2, 0, 0, 0, 0, 0, 0), +(-46913, 0, 4, 64, 1028, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-46951, 0, 4, 1024, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-47569, 0, 6, 16384, 0, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(-48979, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(-49015, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(-49018, 0, 15, 20971520, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-49182, 0, 15, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-49188, 0, 15, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-49208, 0, 15, 4194304, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-49467, 0, 15, 16, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-51459, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(-51474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-51525, 0, 11, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-51556, 0, 11, 192, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(-51625, 0, 8, 268476416, 0, 0, 0, 5, 2, 0, 2, 0, 0, 0, 0), +(-51627, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), +(-51664, 0, 8, 131072, 8, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-53178, 0, 9, 0, 268435456, 0, 65536, 4, 2, 0, 0, 0, 100, 0, 0), +(-53228, 0, 9, 32, 16777216, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), +(-53290, 0, 9, 2048, 1, 512, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(-53380, 0, 10, 8388608, 163840, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(-53501, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(-53569, 0, 10, 1075838976, 65536, 0, 0, 3, 2, 0, 2, 0, 0, 0, 0), +(-53695, 0, 10, 8388608, 0, 8, 16, 5, 2, 0, 2, 0, 0, 0, 0), +(-54639, 0, 15, 4194304, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-54747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-59088, 0, 4, 0, 2, 0, 1024, 4, 4, 0, 0, 0, 0, 0, 0), +(-61680, 0, 9, 0, 268435456, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-62764, 0, 9, 0, 268435456, 0, 65536, 4, 2, 0, 0, 0, 100, 0, 0), +(-63156, 0, 5, 1, 192, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-63373, 0, 11, 2147483648, 0, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), +(-64127, 0, 6, 1, 1, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0), +(-65661, 0, 15, 4194321, 537001988, 0, 16, 1, 2, 0, 0, 0, 100, 0, 0), +(1719, 0, 4, 778044484, 4212549, 0, 0, 1, 2, 0, 8, 0, 0, 0, 0), +(11129, 4, 3, 146800663, 200776, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(12536, 0, 3, 549591799, 168000, 0, 0, 0, 1, 0, 12, 0, 0, 0, 0), +(15286, 32, 6, 41984016, 9218, 8, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(16246, 0, 11, 2551185859, 5120, 16, 0, 0, 1, 0, 12, 0, 0, 0, 0), +(16864, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0), +(16870, 0, 7, 14924799, 126879699, 263168, 0, 0, 1, 0, 12, 0, 0, 0, 0), +(17619, 0, 13, 0, 0, 0, 34816, 7, 0, 0, 0, 0, 0, 0, 0), +(20185, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 0), +(20186, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 0), +(22007, 0, 3, 2097185, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(24658, 0, 0, 0, 0, 0, 87376, 7, 2, 0, 0, 0, 0, 0, 0), +(24932, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(26169, 0, 6, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(26467, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(28719, 0, 7, 32, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(28744, 0, 7, 64, 0, 0, 278528, 2, 2, 0, 0, 0, 0, 0, 0), +(28789, 0, 10, 3221225472, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(28809, 0, 6, 4096, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(28823, 0, 11, 192, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(28845, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(28847, 0, 7, 32, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(28849, 0, 11, 128, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(29601, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0), +(32863, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(36123, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(38252, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(39367, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(44141, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(70388, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(30823, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 10, 0, 0, 0), +(31801, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(32409, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(33757, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3000, 0), +(37288, 0, 7, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(37295, 0, 7, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(37381, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(37377, 32, 5, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(39437, 4, 5, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(37168, 0, 8, 4063232, 9, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0), +(37594, 0, 6, 4096, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(38164, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(39372, 48, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(40442, 0, 7, 20, 1088, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0), +(40463, 0, 11, 129, 16, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), +(40470, 0, 10, 3229614080, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), +(40971, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(42770, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), +(45057, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(46916, 0, 4, 2097152, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0), +(47383, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(71162, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(71165, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(49005, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(49028, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0), +(49194, 0, 15, 0, 0, 1, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(49222, 0, 0, 0, 0, 0, 139944, 1, 0, 0, 0, 0, 0, 2000, 0), +(49796, 0, 15, 2, 131078, 0, 0, 0, 4, 0, 8, 0, 0, 0, 0), +(51209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(51528, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 4, 0, 0, 0), +(51529, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 8, 0, 0, 0), +(51530, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), +(51531, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 16, 0, 0, 0), +(51532, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 20, 0, 0, 0), +(51698, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 33, 0, 0), +(51700, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 66, 0, 0), +(51701, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 100, 0, 0), +(52420, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(52437, 1, 4, 536870912, 0, 0, 16, 0, 4, 0, 0, 0, 0, 0, 0), +(53601, 0, 0, 0, 0, 0, 1048576, 0, 0, 0, 0, 0, 0, 0, 0), +(53736, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(54274, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(54276, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(54277, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(54748, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0), +(54815, 0, 7, 32768, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), +(54821, 0, 7, 4096, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), +(54832, 0, 7, 0, 4096, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(54845, 0, 7, 4, 0, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), +(54937, 0, 10, 2147483648, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(54939, 0, 10, 32768, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(55198, 0, 11, 448, 0, 0, 16384, 2, 2, 2, 0, 0, 0, 0, 3), +(55440, 0, 11, 64, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(55677, 0, 6, 0, 1, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), +(56372, 0, 3, 0, 128, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(56374, 0, 3, 0, 16384, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(56375, 0, 3, 16777216, 0, 0, 65536, 4, 2, 2049, 0, 0, 0, 0, 0), +(56800, 0, 8, 4, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), +(58375, 0, 4, 0, 512, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), +(58642, 0, 15, 0, 134217728, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), +(58677, 0, 15, 8192, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), +(58877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(59906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(59915, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(37447, 0, 3, 0, 256, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(61062, 0, 3, 0, 256, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), +(61257, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), +(62259, 0, 15, 33554432, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(62600, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(62606, 0, 0, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0, 0), +(63279, 0, 11, 0, 1024, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), +(63280, 0, 11, 536870912, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0), +(63320, 0, 5, 2147745792, 0, 32768, 1024, 7, 2, 0, 0, 0, 0, 0, 0), +(64890, 0, 10, 0, 65536, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0), +(64928, 0, 11, 1, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(65032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(67228, 0, 11, 0, 4096, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(69755, 0, 0, 0, 0, 0, 0, 7, 2, 0, 0, 0, 0, 45000, 0), +(69739, 0, 0, 0, 0, 0, 0, 7, 2, 0, 0, 0, 0, 45000, 0), +(69762, 0, 0, 0, 0, 0, 87040, 0, 1, 0, 256, 0, 0, 0, 0), +(70723, 0, 7, 5, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(70770, 0, 6, 2048, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(70805, 0, 8, 0, 131072, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), +(70808, 0, 11, 256, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(70817, 0, 11, 0, 4096, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), +(70844, 0, 4, 256, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(70672, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), +(72455, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), +(72832, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), +(72833, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), +(71756, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(72782, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(72783, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(72784, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(71406, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 50, 0, 0), +(71545, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 50, 0, 0), +(71880, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), +(71892, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), +(71519, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 105000, 0), +(71562, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 105000, 0), +(71564, 126, 0, 0, 0, 0, 0, 3, 2, 2, 0, 0, 0, 0, 5), +(71634, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(71640, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(71761, 0, 3, 0, 1048576, 0, 0, 5, 2, 256, 0, 0, 0, 0, 0), +(71770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(72176, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(75475, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), +(75481, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), +(-66799, 0, 15, 4194304, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-63730, 0, 6, 2048, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-58872, 0, 0, 0, 0, 0, 0, 1, 0, 8259, 0, 0, 0, 0, 0), +(-57878, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 0, 0, 0, 0), +(-57470, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), +(-56342, 0, 9, 24, 134217728, 147456, 0, 0, 4, 0, 2, 0, 0, 0, 0), +(-55666, 0, 15, 1, 134217728, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-53709, 2, 10, 16384, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-53671, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-53551, 0, 10, 4096, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-53527, 1, 10, 0, 0, 4, 1024, 0, 2, 1, 0, 0, 100, 0, 0), +(-53486, 0, 10, 8388608, 163840, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), +(-53256, 0, 9, 2048, 8388609, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-53234, 0, 9, 131072, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-53221, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-53215, 0, 9, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-52795, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-52127, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), +(-51940, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(-51692, 0, 8, 516, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-51672, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 1000, 0), +(-51634, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(-51562, 0, 11, 256, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-51523, 0, 11, 0, 1, 0, 65536, 0, 2, 0, 0, 0, 50, 0, 0), +(-51521, 0, 11, 0, 16777216, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(-50880, 0, 15, 0, 67108864, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(-49223, 0, 15, 17, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-49219, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(-49149, 0, 15, 6, 131074, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-49027, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 20000, 0), +(-49004, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0), +(-48988, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-48516, 0, 7, 5, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-48506, 0, 7, 5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-48496, 0, 7, 96, 33554434, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-48483, 0, 7, 34816, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-47580, 0, 6, 0, 0, 64, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-47516, 0, 6, 6144, 65536, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(-47509, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(-47263, 32, 5, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 20000, 0), +(-47258, 0, 5, 0, 8388608, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-47201, 0, 5, 16393, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-46945, 0, 4, 0, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-46867, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-46854, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-45234, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-44557, 0, 3, 32, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-44449, 0, 3, 551686775, 102472, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-44442, 0, 3, 8388608, 64, 0, 0, 0, 2, 0, 0, 0, 0, 1000, 0), +(-41635, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(-35541, 0, 0, 0, 0, 0, 8388608, 0, 0, 0, 0, 0, 0, 0, 0), +(-35100, 0, 9, 4096, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-34950, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-34935, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 8000, 0), +(-34753, 0, 6, 6144, 4, 4096, 0, 0, 2, 2, 2, 0, 0, 0, 0), +(-34500, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-33881, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-33191, 0, 6, 32768, 1024, 64, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-33150, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 0, 0, 0, 0), +(-33142, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-33076, 0, 0, 0, 0, 0, 664232, 1, 0, 0, 0, 0, 0, 0, 0), +(-32385, 0, 5, 1, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-31833, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-31569, 0, 3, 65536, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-31124, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-30881, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(-30701, 28, 0, 0, 0, 0, 664232, 1, 0, 0, 0, 0, 100, 0, 0), +(-30299, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-30160, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-29593, 0, 0, 0, 0, 0, 0, 1, 0, 112, 0, 0, 0, 0, 0), +(-29074, 20, 3, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-27811, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-20925, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(-20500, 0, 4, 268435456, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-20210, 0, 10, 3221225472, 65536, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-20177, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-20049, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-19184, 0, 9, 16, 8192, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0), +(-18119, 0, 5, 0, 8388608, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-18096, 0, 5, 256, 8388608, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-17793, 0, 5, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-17106, 0, 7, 524288, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-16958, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-16952, 0, 7, 233472, 1024, 262144, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-16880, 72, 7, 103, 58720258, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(-16487, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-16257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-16256, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-16176, 0, 11, 448, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), +(-14892, 0, 6, 268443136, 65540, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), +(-14531, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-14186, 0, 8, 1107296782, 2, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), +(-13754, 0, 8, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-12966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-12319, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(-12311, 0, 4, 2048, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-12298, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), +(-12289, 0, 4, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-12281, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 6000, 0), +(-11255, 0, 3, 16384, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-11213, 0, 3, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(-11180, 16, 3, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0), +(-11095, 0, 3, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-9799, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(-9452, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(-5952, 0, 8, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(-324, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), +(6346, 0, 0, 0, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0, 0), +(7383, 1, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), +(7434, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(57351, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(9782, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(9784, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(12169, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(12322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), +(12999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0), +(13000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0), +(13001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0), +(13002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0), +(15088, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), +(15128, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(15277, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(15346, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(15600, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, 0, 0), +(16164, 28, 0, 0, 0, 0, 65536, 1, 2, 2, 0, 0, 0, 0, 0), +(16550, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), +(16620, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), +(16624, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(17364, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(17495, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(20128, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(20131, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(20132, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(20164, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 5, 0, 0, 0), +(20165, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 20, 0, 0, 0), +(20166, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), +(20375, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1000, 0), +(20705, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), +(20911, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), +(21185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(21882, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), +(21890, 0, 4, 712396527, 876, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(22618, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(22648, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), +(23547, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(23548, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(23551, 0, 11, 192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(23552, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(23572, 0, 11, 192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(23578, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), +(23581, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), +(23686, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), +(23688, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(23689, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 4, 0, 0, 0), +(23721, 0, 9, 2048, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(23920, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(24353, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(24389, 4, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(24905, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 15, 0, 0, 0), +(25050, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(25669, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), +(25899, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), +(26107, 0, 7, 8388608, 268435584, 0, 0, 0, 2, 116, 0, 0, 0, 0, 0), +(26119, 0, 0, 2416967683, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(26128, 0, 0, 0, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 0), +(26135, 0, 10, 8388608, 0, 0, 16, 0, 2, 0, 2, 0, 0, 0, 0), +(26480, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(26605, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(27419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), +(27498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), +(27521, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), +(27656, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(27774, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), +(27787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), +(28305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(28752, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(28802, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(28812, 0, 8, 33554438, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(28816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), +(29150, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), +(29455, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(29501, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29624, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29625, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29626, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29632, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29633, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29634, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29635, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29636, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29637, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(29977, 4, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(30003, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(30937, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(31394, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(31794, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(31904, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(32587, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(32642, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(32734, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(32748, 0, 8, 0, 1, 0, 320, 0, 2, 0, 0, 0, 0, 0, 0), +(32776, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(32777, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(32837, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(32844, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), +(32885, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(33089, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(33127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), +(33297, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(33299, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(33510, 0, 0, 0, 0, 0, 340, 1, 2, 0, 0, 3, 0, 0, 0), +(33648, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(33719, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(33746, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(33759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(33953, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 45000, 0), +(34074, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(34080, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(34138, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(34139, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(34258, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(34262, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(34320, 0, 0, 0, 0, 0, 0, 3, 2, 2, 0, 0, 0, 45000, 0), +(34355, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(34584, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 30000, 0), +(34586, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.5, 0, 0, 0), +(34598, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(34749, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 0, 0, 0, 0), +(34774, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.5, 0, 20000, 0), +(34783, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(34827, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(35077, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 55000, 0), +(35080, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 55000, 0), +(35083, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 55000, 0), +(35086, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 55000, 0), +(35121, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(36032, 0, 3, 4096, 32768, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(36096, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(36111, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(36541, 4, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(37165, 0, 8, 2098176, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37170, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), +(37173, 0, 8, 750519704, 262, 0, 0, 0, 2, 0, 0, 0, 0, 25000, 0), +(37189, 0, 10, 3221225472, 0, 0, 0, 0, 2, 2, 0, 0, 0, 60000, 0), +(37193, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(37195, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(37197, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(37213, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(37214, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(37227, 0, 11, 448, 0, 0, 0, 0, 2, 2, 0, 0, 0, 60000, 0), +(37237, 0, 11, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(37247, 8, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(37379, 32, 5, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37384, 0, 5, 1, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37443, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(37514, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(37516, 0, 4, 1024, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37519, 0, 0, 0, 0, 0, 0, 0, 2, 48, 0, 0, 0, 0, 0), +(37523, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(37528, 0, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37536, 0, 4, 65536, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37568, 0, 6, 2048, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(37600, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(37601, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(37655, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), +(37657, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 2500, 0), +(38026, 1, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), +(38031, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(38290, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.6, 0, 0, 0), +(38299, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 12000, 0), +(38326, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(38327, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(38334, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), +(38347, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), +(38350, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(48504, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(39027, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(39442, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0), +(39443, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(39530, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(39958, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0.7, 0, 40000, 0), +(40407, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(40444, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(40458, 0, 4, 33554432, 1537, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(40475, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), +(40482, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(40485, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(40899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(41034, 126, 0, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0, 0), +(41260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(41262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(41381, 0, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), +(41393, 0, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0), +(41434, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 45000, 0), +(41469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), +(41989, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0.5, 0, 0, 0), +(42083, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(42135, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 90000, 0), +(42136, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 90000, 0), +(42368, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(42370, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43443, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(43726, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43728, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43737, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), +(43739, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43741, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43745, 0, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43748, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43750, 0, 11, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(43819, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(44543, 0, 3, 1049120, 4096, 0, 0, 0, 1, 0, 2, 0, 7, 0, 0), +(44545, 0, 3, 1049120, 4096, 0, 0, 0, 1, 0, 2, 0, 15, 0, 0), +(45354, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(45355, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(45469, 0, 15, 16, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0), +(45481, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(45482, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(45483, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(45484, 0, 0, 0, 0, 0, 16384, 2, 2, 0, 0, 0, 0, 45000, 0), +(46025, 32, 6, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(46092, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(46098, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(46569, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(46662, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 20000, 0), +(46832, 0, 7, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(46910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.5, 0, 0, 0), +(46911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7.5, 0, 0, 0), +(47981, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(48833, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(48835, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), +(48837, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(49592, 0, 0, 0, 0, 0, 8528552, 1, 0, 0, 0, 0, 0, 0, 0), +(49622, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), +(50240, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0), +(50421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(50781, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 6000, 0), +(51123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(51127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0), +(51128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0), +(51129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0), +(51130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0), +(51346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(51349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(51352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(51359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), +(51414, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), +(51915, 0, 0, 0, 0, 0, 16777216, 0, 0, 0, 0, 0, 100, 600000, 0), +(52020, 0, 7, 32768, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(52423, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(52898, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(53386, 0, 15, 2182250279, 447, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(53397, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(54646, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(54695, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(54707, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 60000, 0), +(54738, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), +(54808, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 60000, 0), +(54838, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(54841, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 2500, 0), +(54925, 2, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(55380, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0.7, 0, 40000, 0), +(55381, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), +(55640, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(55680, 0, 6, 512, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(55681, 0, 6, 32768, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(55689, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), +(55747, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(55768, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(55776, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(56249, 0, 5, 0, 0, 1024, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(56355, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(56364, 0, 3, 0, 16777216, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(56451, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), +(56816, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0), +(56817, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(56821, 0, 8, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(56841, 0, 9, 2048, 0, 0, 256, 0, 2, 0, 0, 0, 0, 0, 0), +(57345, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), +(57352, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(57907, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(57989, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(58357, 0, 4, 64, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(58364, 0, 4, 1024, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(58372, 0, 4, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(58386, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0), +(58442, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), +(58444, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 5000, 0), +(58616, 0, 15, 16777216, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(58620, 0, 15, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(58626, 0, 15, 33554432, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(58901, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(59176, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), +(59327, 0, 15, 134217728, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(59345, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(59630, 0, 0, 0, 0, 0, 69648, 5, 1, 0, 2, 0, 0, 35000, 0), +(59725, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), +(60063, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60066, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(60132, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60172, 0, 5, 262144, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60221, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), +(60301, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60306, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60317, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60436, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60442, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60473, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), +(60482, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(60490, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(60493, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(60503, 1, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60519, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), +(60524, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60529, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), +(60537, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), +(60564, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60571, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60572, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60573, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60574, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60575, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60710, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60717, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60719, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60722, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60724, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60726, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60770, 0, 11, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60818, 0, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(60826, 0, 15, 20971520, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(61324, 0, 10, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(61356, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 90000, 0), +(61618, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(62114, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(62115, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(62147, 0, 15, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(62459, 0, 15, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(63086, 0, 9, 0, 0, 65536, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(63108, 0, 5, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(63251, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(63310, 0, 5, 0, 65536, 0, 65536, 0, 2, 0, 0, 0, 0, 0, 0), +(63335, 0, 15, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(63611, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 0, 0), +(64343, 0, 3, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64411, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 0, 0), +(64415, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 45000, 0), +(64440, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(64571, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 10000, 0), +(64714, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(64738, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(64742, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(64786, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(64792, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(64860, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64867, 0, 3, 536870945, 4096, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64882, 0, 10, 0, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64908, 0, 6, 8192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64912, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64938, 0, 4, 2097216, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), +(64952, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64955, 0, 10, 0, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64964, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64976, 0, 4, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(64999, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0), +(65002, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(65005, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), +(65007, 0, 0, 0, 0, 0, 81920, 3, 1, 0, 0, 0, 0, 0, 0), +(65013, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(65020, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(65025, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(66808, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(67115, 0, 15, 20971520, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), +(67151, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(67353, 0, 7, 32768, 1049856, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(67363, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), +(67379, 0, 10, 0, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(67381, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), +(67384, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 80, 10000, 0), +(67386, 0, 11, 1, 0, 0, 65536, 0, 1, 0, 0, 0, 0, 6000, 0), +(67389, 0, 11, 256, 0, 0, 16384, 0, 1, 0, 0, 0, 0, 8000, 0), +(67392, 0, 11, 0, 0, 4, 16, 0, 2, 0, 0, 0, 0, 0, 0), +(67653, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 50000, 0), +(67667, 0, 0, 0, 0, 0, 16384, 2, 1, 0, 0, 0, 0, 45000, 0), +(67670, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), +(67672, 0, 0, 0, 0, 0, 8388948, 1, 2, 0, 0, 0, 0, 45000, 0), +(67698, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(67702, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(67712, 0, 0, 0, 0, 0, 69632, 1, 2, 2, 0, 0, 0, 2000, 0), +(67752, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(67758, 0, 0, 0, 0, 0, 69632, 1, 2, 2, 0, 0, 0, 2000, 0), +(67771, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(68051, 1, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(68160, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(70188, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0), +(70652, 0, 15, 8, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(70727, 0, 9, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(70748, 0, 3, 0, 2097152, 0, 1024, 0, 2, 0, 0, 0, 0, 0, 0), +(70756, 0, 10, 0, 65536, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(70761, 0, 10, 0, 0, 1, 1024, 0, 2, 0, 0, 0, 0, 0, 0), +(70803, 0, 8, 4063232, 8, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(70807, 0, 11, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(70811, 0, 11, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(70830, 0, 11, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71186, 0, 10, 0, 32768, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71191, 0, 10, 0, 65536, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), +(71194, 0, 10, 0, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71214, 0, 11, 0, 16, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0), +(71217, 0, 11, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71226, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71228, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), +(71402, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(71404, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), +(71540, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(71585, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 45000, 0), +(71602, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), +(71611, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), +(71642, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), +(71645, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), +(71903, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), +(72413, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 10, 60000, 0), +(72417, 0, 0, 0, 0, 0, 327680, 1, 2, 0, 0, 0, 0, 60000, 0), +(72419, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 60000, 0), +(74396, 84, 3, 685904631, 1151048, 0, 65536, 0, 1, 0, 0, 0, 0, 0, 0), +(75455, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(75457, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), +(75465, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), +(75474, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), +(-12317, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(63057, 0, 7, 0, 262144, 0, 16384, 0, 2, 0, 0, 0, 0, 0, 0), +(71571, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(71573, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(71865, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), +(71868, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), +(75490, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), +(75495, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), +(53651, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0), +(53257, 0, 9, 0, 268435456, 0, 16, 1, 2, 2, 8, 0, 0, 0, 0), +(-31226, 0, 8, 0, 524288, 0, 0, 5, 2, 0, 2, 0, 0, 0, 0), +(-51682, 0, 8, 0, 524288, 0, 0, 4, 2, 0, 2, 0, 0, 0, 0), +(53817, 0, 11, 451, 32768, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(12328, 0, 4, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(21084, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(5118, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(13159, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(-168, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), +(-7302, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), +(-30482, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), +(17670, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(50908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(58501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(-49200, 126, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), +(41350, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), +(18708, 0, 5, 536870912, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), +(57529, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(57531, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(72059, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), +(-11103, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(13234, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), +(12043, 0, 3, 1631584309, 4096, 0, 0, 7, 1, 0, 8, 0, 0, 0, 0), +(16166, 0, 11, 3, 4096, 0, 0, 7, 1, 0, 8, 0, 0, 0, 0), +(17116, 0, 7, 268436065, 33554464, 32768, 0, 7, 1, 0, 8, 0, 0, 0, 0), +(-53583, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), +(53515, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), +(71993, 0, 0, 0, 0, 0, 4, 0, 0, 12287, 0, 0, 0, 4000, 0), +(35321, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), +(38363, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), +(39215, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), +(45092, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(50871, 0, 9, 0, 1073741824, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), +(32065, 0, 0, 0, 0, 0, 524288, 1, 0, 0, 0, 0, 0, 0, 0), +(36659, 0, 0, 0, 0, 0, 524288, 1, 0, 0, 0, 0, 0, 0, 0), +(4341, 0, 0, 0, 0, 0, 4096, 1, 1, 0, 0, 0, 0, 0, 0), +(70904, 0, 6, 0, 0, 2048, 2048, 4, 0, 0, 0, 0, 0, 0, 0), +(63849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(23591, 0, 10, 8388608, 0, 0, 16, 0, 2, 0, 2, 0, 0, 0, 0), +(-16689, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-588, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-59887, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), +(71567, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 400, 0), +(-14143, 0, 8, 1191182854, 2097152, 0, 0, 1, 2, 0, 8, 0, 0, 0, 0), +(60617, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), +(40816, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7000, 0); + +-- Threat of Thassarian triggered spells, for easier script access +DELETE FROM `spell_ranks` WHERE `first_spell_id` IN (59133,66198,66196,66216,66188,66215); +INSERT INTO `spell_ranks` (`first_spell_id`, `spell_id`, `rank`) VALUES +(66198, 66198, 1), +(66198, 66972, 2), +(66198, 66973, 3), +(66198, 66974, 4), + +(66196, 66196, 1), +(66196, 66958, 2), +(66196, 66959, 3), +(66196, 66960, 4), +(66196, 66961, 5), +(66196, 66962, 6), + +(66216, 66216, 1), +(66216, 66988, 2), +(66216, 66989, 3), +(66216, 66990, 4), +(66216, 66991, 5), +(66216, 66992, 6), + +(66188, 66188, 1), +(66188, 66950, 2), +(66188, 66951, 3), +(66188, 66952, 4), +(66188, 66953, 5), + +(66215, 66215, 1), +(66215, 66975, 2), +(66215, 66976, 3), +(66215, 66977, 4), +(66215, 66978, 5), +(66215, 66979, 6); + +-- Remove renamed scripts +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_gen_dummy_trigger','spell_pri_item_greater_heal_refund'); + +-- Stop console spam from dummy EFFECT_2 proc +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_pal_seals'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(20375, 'spell_pal_seals'), -- Seal of Command +(21084, 'spell_pal_seals'), -- Seal of Righteousness +(31801, 'spell_pal_seals'), -- Seal of Vengeance +(31892, 'spell_pal_seals'), -- Seal of Blood +(33127, 'spell_pal_seals'), -- Seal of Command +(38008, 'spell_pal_seals'), -- Seal of Blood +(41459, 'spell_pal_seals'), -- Seal of Blood +(53720, 'spell_pal_seals'), -- Seal of the Martyr +(53736, 'spell_pal_seals'); -- Seal of Corruption + +-- Grouped several hacks and handled with AuraScript now +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_mage_fingers_of_frost'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(74396, 'spell_mage_fingers_of_frost'); -- Fingers of Frost + +-- Add spellscripts to spells previously on giant switches in Unit.cpp +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_rog_t10_2p_bonus'; +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_sha_flametongue_weapon','spell_mage_imp_blizzard','spell_warr_deep_wounds_aura','spell_rog_setup','spell_pri_improved_spirit_tap','spell_sha_imp_water_shield','spell_pal_improved_lay_of_hands','spell_pal_heart_of_the_crusader','spell_warl_seed_of_corruption_dummy','spell_mage_magic_absorption','spell_warr_extra_proc','spell_warr_second_wind','spell_warl_soul_leech','spell_sha_lightning_overload','spell_rog_quick_recovery','spell_mage_arcane_potency','spell_mage_empowered_fire','spell_pal_spiritual_attunement','spell_pal_divine_purpose','spell_pal_judgements_of_the_wise','spell_hun_thrill_of_the_hunt','spell_mage_missile_barrage','spell_mage_hot_streak','spell_pri_imp_shadowform','spell_dk_butchery','spell_item_unstable_power','spell_item_restless_strength','spell_pri_aq_3p_bonus','spell_item_persistent_shield','spell_dru_revitalize','spell_dk_scent_of_blood_trigger','spell_dk_vendetta','spell_dk_sudden_doom','spell_dk_blade_barrier','spell_dk_wandering_plague','spell_sha_astral_shift_aura','spell_dk_necrosis','spell_sha_static_shock','spell_sha_maelstrom_weapon','spell_sha_ancestral_awakening','spell_rog_deadly_brew','spell_rog_turn_the_tables','spell_rog_cut_to_the_chase','spell_pet_guard_dog','spell_hun_rapid_recuperation_trigger','spell_hun_hunting_party','spell_pal_infusion_of_light','spell_pal_judgements_of_the_just','spell_mage_burning_determination','spell_warr_improved_spell_reflection','spell_pet_culling_the_herd','spell_pet_silverback','spell_warl_decimation','spell_sha_frozen_power','spell_pri_body_and_soul','spell_dk_threat_of_thassarian','spell_warl_seduction','spell_mage_combustion','spell_pri_vampiric_embrace','spell_dru_omen_of_clarity','spell_item_alchemists_stone','spell_pal_judgement_of_light_heal','spell_pal_judgement_of_wisdom_mana','spell_twisted_reflection','spell_dru_t3_2p_bonus','spell_dru_t3_8p_bonus','spell_dru_t3_6p_bonus','spell_pal_t3_6p_bonus','spell_pri_t3_4p_bonus','spell_sha_t3_6p_bonus','spell_warr_t3_prot_8p_bonus','spell_item_healing_touch_refund','spell_item_totem_of_flowing_water','spell_sha_shamanistic_rage','spell_pal_seal_of_vengeance','spell_warl_seed_of_corruption_generic','spell_mark_of_malice','spell_item_mark_of_conquest','spell_sha_windfury_weapon','spell_dru_t4_2p_bonus','spell_pri_t5_heal_2p_bonus','spell_anetheron_vampiric_aura','spell_item_frozen_shadoweave','spell_item_aura_of_madness','spell_pri_item_t6_trinket','spell_dru_item_t6_trinket','spell_sha_item_t6_trinket','spell_pal_item_t6_trinket','spell_item_crystal_spire_of_karabor','spell_item_dementia','spell_item_pet_healing','spell_warl_t4_2p_bonus_shadow','spell_warl_t4_2p_bonus_fire','spell_mage_gen_extra_effects','spell_uk_second_wind','spell_item_sunwell_exalted_caster_neck','spell_item_sunwell_exalted_melee_neck','spell_item_sunwell_exalted_tank_neck','spell_item_sunwell_exalted_healer_neck','spell_warl_glyph_of_corruption_nightfall','spell_dk_mark_of_blood','spell_dk_dancing_rune_weapon','spell_dk_hungering_cold','spell_pal_sacred_shield_dummy','spell_warl_demonic_pact','spell_pal_seal_of_corruption','spell_dru_glyph_of_rejuvenation','spell_dru_glyph_of_shred','spell_dru_glyph_of_rake','spell_dru_glyph_of_innervate','spell_dru_glyph_of_starfire_dummy','spell_pal_glyph_of_holy_light_dummy','spell_pal_glyph_of_divinity','spell_sha_tidal_force_dummy','spell_sha_glyph_of_healing_wave','spell_pri_glyph_of_dispel_magic','spell_mage_glyph_of_icy_veins','spell_mage_glyph_of_polymorph','spell_rog_glyph_of_backstab','spell_hun_glyph_of_mend_pet','spell_pri_shadowfiend_death','spell_warr_glyph_of_blocking','spell_dk_glyph_of_scourge_strike','spell_sha_spirit_hunt','spell_hun_kill_command_pet','spell_item_swift_hand_justice_dummy','spell_item_discerning_eye_beast_dummy','spell_mage_imp_mana_gems','spell_dk_pvp_4p_bonus','spell_dru_savage_defense','spell_sha_glyph_of_earth_shield','spell_sha_glyph_of_totem_of_wrath','spell_warl_glyph_of_life_tap','spell_item_purified_shard_of_the_scale','spell_item_shiny_shard_of_the_scale','spell_dru_t10_balance_4p_bonus','spell_dru_t10_restoration_4p_bonus_dummy','spell_sha_t10_restoration_4p_bonus','spell_sha_t10_elemental_4p_bonus','spell_warr_item_t10_prot_4p_bonus','spell_item_tiny_abomination_in_a_jar','spell_item_tiny_abomination_in_a_jar_hero','spell_item_deadly_precision_dummy','spell_item_deadly_precision','spell_item_heartpierce','spell_item_heartpierce_hero','spell_item_deathbringers_will_normal','spell_item_deathbringers_will_heroic','spell_putricide_ooze_tank_protection','spell_deathbringer_blood_beast_blood_link'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(-10400, 'spell_sha_flametongue_weapon'), +(-11185, 'spell_mage_imp_blizzard'), +(-12834, 'spell_warr_deep_wounds_aura'), +(-13983, 'spell_rog_setup'), +(-15337, 'spell_pri_improved_spirit_tap'), +(-16180, 'spell_sha_imp_water_shield'), +(-20234, 'spell_pal_improved_lay_of_hands'), +(-20335, 'spell_pal_heart_of_the_crusader'), +(-27243, 'spell_warl_seed_of_corruption_dummy'), +(-29441, 'spell_mage_magic_absorption'), + +(-29723, 'spell_warr_extra_proc'), +(-46913, 'spell_warr_extra_proc'), + +(-29834, 'spell_warr_second_wind'), +(-30293, 'spell_warl_soul_leech'), +(-30675, 'spell_sha_lightning_overload'), +(-31244, 'spell_rog_quick_recovery'), +(-31571, 'spell_mage_arcane_potency'), +(-31656, 'spell_mage_empowered_fire'), +(-31785, 'spell_pal_spiritual_attunement'), +(-31871, 'spell_pal_divine_purpose'), +(-31876, 'spell_pal_judgements_of_the_wise'), +(-34497, 'spell_hun_thrill_of_the_hunt'), +(-44404, 'spell_mage_missile_barrage'), +(-44445, 'spell_mage_hot_streak'), +(-47569, 'spell_pri_imp_shadowform'), +(-48979, 'spell_dk_butchery'), +(-48539, 'spell_dru_revitalize'), + +(-49004, 'spell_dk_scent_of_blood_trigger'), +(-49015, 'spell_dk_vendetta'), +(-49018, 'spell_dk_sudden_doom'), +(-49182, 'spell_dk_blade_barrier'), +(-49217, 'spell_dk_wandering_plague'), +(-51474, 'spell_sha_astral_shift_aura'), +(-51459, 'spell_dk_necrosis'), +(-51525, 'spell_sha_static_shock'), +(-51556, 'spell_sha_ancestral_awakening'), +(-51625, 'spell_rog_deadly_brew'), +(-51627, 'spell_rog_turn_the_tables'), +(-51664, 'spell_rog_cut_to_the_chase'), +(-53178, 'spell_pet_guard_dog'), +(-53228, 'spell_hun_rapid_recuperation_trigger'), +(-53290, 'spell_hun_hunting_party'), +(-53569, 'spell_pal_infusion_of_light'), +(-53695, 'spell_pal_judgements_of_the_just'), +(-54747, 'spell_mage_burning_determination'), +(-59088, 'spell_warr_improved_spell_reflection'), +(-61680, 'spell_pet_culling_the_herd'), +(-62764, 'spell_pet_silverback'), +(-63156, 'spell_warl_decimation'), +(-63373, 'spell_sha_frozen_power'), +(-64127, 'spell_pri_body_and_soul'), +(-65661, 'spell_dk_threat_of_thassarian'), +(6358, 'spell_warl_seduction'), +(11129, 'spell_mage_combustion'), +(15286, 'spell_pri_vampiric_embrace'), +(16864, 'spell_dru_omen_of_clarity'), +(17619, 'spell_item_alchemists_stone'), +(20185, 'spell_pal_judgement_of_light_heal'), +(20186, 'spell_pal_judgement_of_wisdom_mana'), +(21063, 'spell_twisted_reflection'), +(24658, 'spell_item_unstable_power'), +(24661, 'spell_item_restless_strength'), +(26169, 'spell_pri_aq_3p_bonus'), +(26467, 'spell_item_persistent_shield'), +(28716, 'spell_dru_t3_2p_bonus'), +(28719, 'spell_dru_t3_8p_bonus'), +(28744, 'spell_dru_t3_6p_bonus'), +(28789, 'spell_pal_t3_6p_bonus'), +(28809, 'spell_pri_t3_4p_bonus'), +(28823, 'spell_sha_t3_6p_bonus'), +(28845, 'spell_warr_t3_prot_8p_bonus'), +(28847, 'spell_item_healing_touch_refund'), +(28849, 'spell_item_totem_of_flowing_water'), +(30823, 'spell_sha_shamanistic_rage'), +(31801, 'spell_pal_seal_of_vengeance'), + +(32863, 'spell_warl_seed_of_corruption_generic'), +(36123, 'spell_warl_seed_of_corruption_generic'), +(38252, 'spell_warl_seed_of_corruption_generic'), +(39367, 'spell_warl_seed_of_corruption_generic'), +(44141, 'spell_warl_seed_of_corruption_generic'), +(70388, 'spell_warl_seed_of_corruption_generic'), + +(33493, 'spell_mark_of_malice'), +(33510, 'spell_item_mark_of_conquest'), +(33757, 'spell_sha_windfury_weapon'), +(37288, 'spell_dru_t4_2p_bonus'), +(37295, 'spell_dru_t4_2p_bonus'), +(37594, 'spell_pri_t5_heal_2p_bonus'), +(38196, 'spell_anetheron_vampiric_aura'), +(39372, 'spell_item_frozen_shadoweave'), +(39446, 'spell_item_aura_of_madness'), +(40438, 'spell_pri_item_t6_trinket'), +(40442, 'spell_dru_item_t6_trinket'), +(40463, 'spell_sha_item_t6_trinket'), +(40470, 'spell_pal_item_t6_trinket'), +(40971, 'spell_item_crystal_spire_of_karabor'), +(41404, 'spell_item_dementia'), + +(37381, 'spell_item_pet_healing'), + +(37377, 'spell_warl_t4_2p_bonus_shadow'), +(39437, 'spell_warl_t4_2p_bonus_fire'), + +(44401, 'spell_mage_gen_extra_effects'), +(48108, 'spell_mage_gen_extra_effects'), +(57761, 'spell_mage_gen_extra_effects'), + +(42770, 'spell_uk_second_wind'), +(45481, 'spell_item_sunwell_exalted_caster_neck'), +(45482, 'spell_item_sunwell_exalted_melee_neck'), +(45483, 'spell_item_sunwell_exalted_tank_neck'), +(45484, 'spell_item_sunwell_exalted_healer_neck'), + +(-18094, 'spell_warl_glyph_of_corruption_nightfall'), +(56218, 'spell_warl_glyph_of_corruption_nightfall'), + +(49005, 'spell_dk_mark_of_blood'), +(49028, 'spell_dk_dancing_rune_weapon'), +(51209, 'spell_dk_hungering_cold'), + +(53601, 'spell_pal_sacred_shield_dummy'), + +(53646, 'spell_warl_demonic_pact'), +(54909, 'spell_warl_demonic_pact'), + +(53736, 'spell_pal_seal_of_corruption'), +(53817, 'spell_sha_maelstrom_weapon'), +(54748, 'spell_mage_burning_determination'), +(54754, 'spell_dru_glyph_of_rejuvenation'), +(54815, 'spell_dru_glyph_of_shred'), +(54821, 'spell_dru_glyph_of_rake'), +(54832, 'spell_dru_glyph_of_innervate'), +(54845, 'spell_dru_glyph_of_starfire_dummy'), +(54937, 'spell_pal_glyph_of_holy_light_dummy'), +(54939, 'spell_pal_glyph_of_divinity'), +(55198, 'spell_sha_tidal_force_dummy'), +(55440, 'spell_sha_glyph_of_healing_wave'), +(55677, 'spell_pri_glyph_of_dispel_magic'), +(56374, 'spell_mage_glyph_of_icy_veins'), +(56375, 'spell_mage_glyph_of_polymorph'), +(56800, 'spell_rog_glyph_of_backstab'), +(57870, 'spell_hun_glyph_of_mend_pet'), +(57989, 'spell_pri_shadowfiend_death'), +(58375, 'spell_warr_glyph_of_blocking'), +(58642, 'spell_dk_glyph_of_scourge_strike'), +(58877, 'spell_sha_spirit_hunt'), +(58914, 'spell_hun_kill_command_pet'), +(59906, 'spell_item_swift_hand_justice_dummy'), +(59915, 'spell_item_discerning_eye_beast_dummy'), + +(37447, 'spell_mage_imp_mana_gems'), +(61062, 'spell_mage_imp_mana_gems'), + +(61257, 'spell_dk_pvp_4p_bonus'), +(62600, 'spell_dru_savage_defense'), +(63279, 'spell_sha_glyph_of_earth_shield'), +(63280, 'spell_sha_glyph_of_totem_of_wrath'), +(63320, 'spell_warl_glyph_of_life_tap'), +(69755, 'spell_item_purified_shard_of_the_scale'), +(69739, 'spell_item_shiny_shard_of_the_scale'), +(70723, 'spell_dru_t10_balance_4p_bonus'), +(70664, 'spell_dru_t10_restoration_4p_bonus_dummy'), +(70808, 'spell_sha_t10_restoration_4p_bonus'), +(70817, 'spell_sha_t10_elemental_4p_bonus'), +(70844, 'spell_warr_item_t10_prot_4p_bonus'), + +(71406, 'spell_item_tiny_abomination_in_a_jar'), +(71545, 'spell_item_tiny_abomination_in_a_jar_hero'), + +(71563, 'spell_item_deadly_precision_dummy'), +(71564, 'spell_item_deadly_precision'), + +(71880, 'spell_item_heartpierce'), +(71892, 'spell_item_heartpierce_hero'), + +(71519, 'spell_item_deathbringers_will_normal'), +(71562, 'spell_item_deathbringers_will_heroic'), + +(61685, 'spell_pet_charge'), +(-49200, 'spell_dk_acclimation'), +(70656, 'spell_dk_advantage_t10_4p'), +(37336, 'spell_dru_forms_trinket'), +(67353, 'spell_dru_t9_feral_relic'), +(13567, 'spell_gen_dummy_trigger'), +(-53234, 'spell_hun_piercing_shots'), +(67151, 'spell_hun_t9_4p_bonus'), +(-31641, 'spell_mage_blazing_speed'), +(-20210, 'spell_pal_illumination'), +(-27811, 'spell_pri_blessed_recovery'), +(37594, 'spell_pri_item_greater_heal_refund'), +(-47580, 'spell_pri_pain_and_suffering_dummy'), +(-324, 'spell_sha_lightning_shield'), +(-30881, 'spell_sha_nature_guardian'), +(-30299, 'spell_warl_nether_protection'), +(60510, 'spell_item_soul_preserver'), +(67702, 'spell_item_death_choice'), +(67771, 'spell_item_death_choice'), +(37657, 'spell_item_lightning_capacitor'), +(54841, 'spell_item_thunder_capacitor'), +(67712, 'spell_item_toc25_normal_caster_trinket'), +(67758, 'spell_item_toc25_heroic_caster_trinket'), +(57345, 'spell_item_darkmoon_card_greatness'), +(43820, 'spell_item_charm_witch_doctor'), +(27522, 'spell_item_mana_drain'), +(40336, 'spell_item_mana_drain'), + +(71770, 'spell_putricide_ooze_tank_protection'), +(72176, 'spell_deathbringer_blood_beast_blood_link'); + +-- Kill the damned thing already! +DROP TABLE IF EXISTS `spell_proc_event`; diff --git a/src/server/game/Combat/ThreatMgr.cpp b/src/server/game/Combat/ThreatMgr.cpp index 91751f22a..51c38a0ce 100644 --- a/src/server/game/Combat/ThreatMgr.cpp +++ b/src/server/game/Combat/ThreatMgr.cpp @@ -46,7 +46,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMas return threat; if (Player* modOwner = hatedUnit->GetSpellModOwner()) - modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat); + modOwner->ApplySpellMod(threatSpell->Id, threat); } return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 512e7c39e..6b9c4b666 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2751,8 +2751,8 @@ void Creature::AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_t uint32 categorycooldown = categoryId ? spellInfo->CategoryRecoveryTime : 0; if (Player* modOwner = GetSpellModOwner()) { - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, spellcooldown); - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categorycooldown); + modOwner->ApplySpellMod(spellInfo->Id, spellcooldown); + modOwner->ApplySpellMod(spellInfo->Id, categorycooldown); } SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 79d8565cd..e152cfe42 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -764,7 +764,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) case DAMAGE_LAVA: case DAMAGE_SLIME: { - DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE); + DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK); Unit::CalcAbsorbResist(dmgInfo); absorb = dmgInfo.GetAbsorb(); resist = dmgInfo.GetResist(); @@ -7058,21 +7058,22 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, } } -void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx) +void Player::CastItemCombatSpell(DamageInfo const& damageInfo) { + Unit* target = damageInfo.GetVictim(); if (!target || !target->IsAlive() || target == this) return; // Xinef: do not use disarmed weapons, special exception - shaman ghost wolf form // Xinef: normal forms proc on hit enchants / built in item bonuses - if (!CanUseAttackType(attType) || GetShapeshiftForm() == FORM_GHOSTWOLF) + if (!CanUseAttackType(damageInfo.GetAttackType()) || GetShapeshiftForm() == FORM_GHOSTWOLF) return; for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { // If usable, try to cast item spell if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (!item->IsBroken()) + if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType())) if (ItemTemplate const* proto = item->GetTemplate()) { // Additional check for weapons @@ -7080,7 +7081,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 { // offhand item cannot proc from main hand hit etc EquipmentSlots slot; - switch (attType) + switch (damageInfo.GetAttackType()) { case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; @@ -7099,19 +7100,20 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 continue; } - CastItemCombatSpell(target, attType, procVictim, procEx, item, proto); + CastItemCombatSpell(damageInfo, item, proto); } } } -void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto) +void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto) { - if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto)) - return; +// if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto)) +// return; // Can do effect if any damage done to target - if (procVictim & PROC_FLAG_TAKEN_DAMAGE) - //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) + // for done procs allow normal + critical + absorbs by default + bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0; + if (canTrigger) { for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i) { @@ -7132,11 +7134,15 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 continue; } + // not allow proc extra attack spell at extra attack + if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + return; + float chance = (float)spellInfo->ProcChance; if (spellData.SpellPPMRate) { - uint32 WeaponSpeed = GetAttackTime(attType); + uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType()); chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo); } else if (chance > 100.0f) @@ -7144,8 +7150,8 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 chance = GetWeaponProcChance(); } - if (roll_chance_f(chance) && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item)) - CastSpell(target, spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); + if (roll_chance_f(chance)/* && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item)*/) + CastSpell(damageInfo.GetVictim(), spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); } } @@ -7167,14 +7173,14 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 if (entry && entry->procEx) { // Check hit/crit/dodge/parry requirement - if ((entry->procEx & procEx) == 0) + if ((entry->procEx & damageInfo.GetHitMask()) == 0) continue; } else { // Can do effect if any damage done to target - if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE)) - //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)) + // for done procs allow normal + critical + absorbs by default + if (!canTrigger) continue; } @@ -7197,7 +7203,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 } // Apply spell mods - ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance); + ApplySpellMod(pEnchant->spellid[s], chance); // Shiv has 100% chance to apply the poison if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT) @@ -7220,7 +7226,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 if (spellInfo->IsPositive()) CastSpell(this, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); else - CastSpell(target, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); + CastSpell(damageInfo.GetVictim(), spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); } } } @@ -9565,9 +9571,11 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod if (!mod || !spellInfo) return false; - // Mod out of charges - if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end()) + // First time this aura applies a mod to us and is out of charges + if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura)) + { return false; + } // +duration to infinite duration spells making them limited if (mod->op == SPELLMOD_DURATION && spellInfo->GetDuration() == -1) @@ -9609,50 +9617,46 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) LOG_DEBUG("spells.aura", "Player::AddSpellMod {}", mod->spellId); uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; - int i = 0; - flag96 _mask = 0; - for (int eff = 0; eff < 96; ++eff) + flag96 modMask; + for (uint8 i = 0; i < 3; ++i) { - if (eff != 0 && eff % 32 == 0) - _mask[i++] = 0; - - _mask[i] = uint32(1) << (eff - (32 * i)); - if (mod->mask & _mask) + for (uint32 eff = 0; eff < 32; ++eff) { - int32 val = 0; - for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) + modMask[i] = uint32(1) << eff; + if ((mod->mask & modMask)) { - if ((*itr)->type == mod->type && (*itr)->mask & _mask) - val += (*itr)->value; + int32 val = 0; + for (SpellModifier* spellMod : m_spellMods[mod->op]) + { + if (spellMod->type == mod->type && (spellMod->mask & modMask)) + { + val += spellMod->value; + } + } + val += apply ? mod->value : -(mod->value); + WorldPacket data(Opcode, (1 + 1 + 4)); + data << uint8(eff + 32 * i); + data << uint8(mod->op); + data << int32(val); + SendDirectMessage(&data); } - val += apply ? mod->value : -(mod->value); - WorldPacket data(Opcode, (1 + 1 + 4)); - data << uint8(eff); - data << uint8(mod->op); - data << int32(val); - SendDirectMessage(&data); } + + modMask[i] = 0; } if (apply) { - m_spellMods[mod->op].push_back(mod); - if (getClass() == CLASS_MAGE) - m_spellMods[mod->op].sort(MageSpellModPred()); - else - m_spellMods[mod->op].sort(SpellModPred()); + m_spellMods[mod->op].insert(mod); } else { - m_spellMods[mod->op].remove(mod); - // mods bound to aura will be removed in AuraEffect::~AuraEffect - if (!mod->ownerAura) - delete mod; + m_spellMods[mod->op].erase(mod); } } // Restore spellmods in case of failed cast -void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) +void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/) { if (!spell || spell->m_appliedMods.empty()) return; @@ -9661,16 +9665,16 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) for (uint8 i = 0; i < MAX_SPELLMOD; ++i) { - for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr) + for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr) { SpellModifier* mod = *itr; - // Spellmods without aura set cannot be charged - if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges()) + // Spellmods without charged aura set cannot be charged + if (!mod->ownerAura->IsUsingCharges()) continue; // Restore only specific owner aura mods - if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id)) + if (ownerAuraId && mod->spellId != ownerAuraId) continue; if (aura && mod->ownerAura != aura) @@ -9691,27 +9695,14 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) // only see the first of its modifier restored) aurasQueue.push_back(mod->ownerAura); - // add mod charges back to mod - if (mod->charges == -1) - mod->charges = 1; - else - mod->charges++; - - // Do not set more spellmods than available - if (mod->ownerAura->GetCharges() < mod->charges) - mod->charges = mod->ownerAura->GetCharges(); - - // Skip this check for now - aura charges may change due to various reason - /// @todo track these changes correctly - //ASSERT (mod->ownerAura->GetCharges() <= mod->charges); + // add charges back to aura + mod->ownerAura->ModCharges(1); } } - for (std::list::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr) + for (Aura* aura : aurasQueue) { - Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr); - if (iterMod != spell->m_appliedMods.end()) - spell->m_appliedMods.erase(iterMod); + spell->m_appliedMods.erase(aura); } // Xinef: clear the list just do be sure @@ -9719,77 +9710,32 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) spell->m_appliedMods.clear(); } -void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura) +void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/) { for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - if (m_currentSpells[i]) - RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura); + if (Spell* spell = m_currentSpells[i]) + RestoreSpellMods(spell, ownerAuraId, aura); } -void Player::RemoveSpellMods(Spell* spell) +void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell) { if (!spell) return; - if (spell->m_appliedMods.empty()) + // don't do anything with no charges + if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges()) return; - SpellInfo const* const spellInfo = spell->m_spellInfo; - - for (uint8 i = 0; i < MAX_SPELLMOD; ++i) - { - for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();) - { - SpellModifier* mod = *itr; - ++itr; - - // spellmods without aura set cannot be charged - if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges()) - continue; - - // check if mod affected this spell - Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura); - if (iterMod == spell->m_appliedMods.end()) - continue; - - // remove from list - // leave this here, if spell have two mods it will remove 2 charges - wrong - spell->m_appliedMods.erase(iterMod); - - // MAGE T8P4 BONUS - if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE ) - { - SpellInfo const* sp = mod->ownerAura->GetSpellInfo(); - // Missile Barrage, Hot Streak, Brain Freeze (trigger spell - Fireball!) - if( sp->SpellIconID == 3261 || sp->SpellIconID == 2999 || sp->SpellIconID == 2938 ) - if( AuraEffect* aurEff = GetAuraEffectDummy(64869) ) - if( roll_chance_i(aurEff->GetAmount()) ) - { - mod->charges = 1; - continue; - } - } - - if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE)) - itr = m_spellMods[i].begin(); - } - } + // register inside spell, proc system uses this to drop charges + spell->m_appliedMods.insert(mod->ownerAura); } -void Player::DropModCharge(SpellModifier* mod, Spell* spell) +bool Player::HasSpellModApplied(SpellModifier* mod, Spell* spell) { - // don't handle spells with proc_event entry defined - // this is a temporary workaround, because all spellmods should be handled like that - if (sSpellMgr->GetSpellProcEvent(mod->spellId)) - return; + if (!spell) + return false; - if (spell && mod->ownerAura && mod->charges > 0) - { - if (--mod->charges == 0) - mod->charges = -1; - - spell->m_appliedMods.insert(mod->ownerAura); - } + return spell->m_appliedMods.count(mod->ownerAura) != 0; } void Player::SetSpellModTakingSpell(Spell* spell, bool apply) @@ -10687,7 +10633,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (rec > 0) { int32 oldRec = rec; - ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell); + ApplySpellMod(spellInfo->Id, rec, spell); if (oldRec != rec) { useSpellCooldown = true; @@ -10696,7 +10642,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS)) { - ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell); + ApplySpellMod(spellInfo->Id, catrec, spell); } if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN)) @@ -11472,6 +11418,7 @@ void Player::ApplyEquipCooldown(Item* pItem) if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_NO_EQUIP_COOLDOWN)) return; + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = pItem->GetTemplate()->Spells[i]; @@ -11480,11 +11427,15 @@ void Player::ApplyEquipCooldown(Item* pItem) if (!spellData.SpellId) continue; - // xinef: apply hidden cooldown for procs + // apply proc cooldown to equip auras if we have any if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP) { - // xinef: uint32(-1) special marker for proc cooldowns - AddSpellCooldown(spellData.SpellId, uint32(-1), 30 * IN_MILLISECONDS); + SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(spellData.SpellId); + if (!procEntry) + continue; + + if (Aura* itemAura = GetAura(spellData.SpellId, GetGUID(), pItem->GetGUID())) + itemAura->AddProcCooldown(now + procEntry->Cooldown); continue; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 73a652459..b0b03bbc4 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -89,10 +89,10 @@ typedef void(*bgZoneRef)(Battleground*, WorldPacket&); #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) // Note: SPELLMOD_* values is aura types in fact -enum SpellModType +enum SpellModType : uint8 { - SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER - SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER + SPELLMOD_FLAT = SPELL_AURA_ADD_FLAT_MODIFIER, + SPELLMOD_PCT = SPELL_AURA_ADD_PCT_MODIFIER }; // 2^n values, Player::m_isunderwater is a bitmask. These are Trinity internal values, they are never send to any client @@ -180,10 +180,9 @@ enum TalentTree // talent tabs // Spell modifier (used for modify other spells) struct SpellModifier { - SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {} - SpellModOp op : 8; - SpellModType type : 8; - int16 charges : 16; + SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), mask(), ownerAura(_ownerAura) {} + SpellModOp op; + SpellModType type; int32 value{0}; flag96 mask; uint32 spellId{0}; @@ -192,7 +191,7 @@ struct SpellModifier typedef std::unordered_map PlayerTalentMap; typedef std::unordered_map PlayerSpellMap; -typedef std::list SpellModList; +typedef std::unordered_set SpellModContainer; typedef GuidList WhisperListContainer; @@ -1730,13 +1729,14 @@ public: SpellCooldowns& GetSpellCooldownMap() { return m_spellCooldowns; } void AddSpellMod(SpellModifier* mod, bool apply); - bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); + static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); bool HasSpellMod(SpellModifier* mod, Spell* spell); - template T ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr, bool temporaryPet = false); - void RemoveSpellMods(Spell* spell); + template + void ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell = nullptr) const; void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr); void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr); - void DropModCharge(SpellModifier* mod, Spell* spell); + static void ApplyModToSpell(SpellModifier* mod, Spell* spell); + static bool HasSpellModApplied(SpellModifier* mod, Spell* spell); void SetSpellModTakingSpell(Spell* spell, bool apply); [[nodiscard]] bool HasSpellCooldown(uint32 spell_id) const override; @@ -2166,9 +2166,9 @@ public: void ApplyItemEquipSpell(Item* item, bool apply, bool form_change = false); void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool form_change = false); void UpdateEquipSpellsAtFormChange(); - void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx); + void CastItemCombatSpell(DamageInfo const& damageInfo); + void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto); void CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex); - void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto); void SendEquipmentSetList(); void SetEquipmentSet(uint32 index, EquipmentSet eqset); @@ -2551,7 +2551,7 @@ public: // mt maps [[nodiscard]] const PlayerTalentMap& GetTalentMap() const { return m_talents; } [[nodiscard]] uint32 GetNextSave() const { return m_nextSave; } - [[nodiscard]] SpellModList const& GetSpellModList(uint32 type) const { return m_spellMods[type]; } + [[nodiscard]] SpellModContainer const& GetSpellModContainer(uint32 type) const { return m_spellMods[type]; } void SetServerSideVisibility(ServerSideVisibilityType type, AccountTypes sec); void SetServerSideVisibilityDetect(ServerSideVisibilityType type, AccountTypes sec); @@ -2756,7 +2756,7 @@ public: uint32 m_baseHealthRegen; int32 m_spellPenetrationItemMod; - SpellModList m_spellMods[MAX_SPELLMOD]; + SpellModContainer m_spellMods[MAX_SPELLMOD]; //uint32 m_pad; // Spell* m_spellModTakingSpell; // Spell for which charges are dropped in spell::finish @@ -2940,130 +2940,132 @@ void AddItemsSetItem(Player* player, Item* item); void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); // "the bodies of template functions must be made available in a header file" -template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell, bool temporaryPet) +template +void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell) const { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) - { - return 0; - } + return; - float totalmul = 1.0f; + float totalmul = 1.f; int32 totalflat = 0; - auto calculateSpellMod = [&](SpellModifier* mod) - { - // xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras - if (temporaryPet && mod->charges != 0) - { - return; - } - - if (mod->type == SPELLMOD_FLAT) - { - // xinef: do not allow to consume more than one 100% crit increasing spell - if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100) - { - return; - } - - int32 flatValue = mod->value; - - // SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100) - if (mod->op == SPELLMOD_THREAT) - { - flatValue /= 100; - } - - totalflat += flatValue; - } - else if (mod->type == SPELLMOD_PCT) - { - // skip percent mods for null basevalue (most important for spell mods with charges) - if (basevalue == T(0) || totalmul == 0.0f) - { - return; - } - - // special case (skip > 10sec spell casts for instant cast setting) - if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) - { - return; - } - // xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied - else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) - { - return; - } - // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied - else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) - { - return; - } - - // xinef: those two mods should be multiplicative (Glyph of Renew) - if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) - { - totalmul *= CalculatePct(1.0f, 100.0f + mod->value); - } - else - { - totalmul += CalculatePct(1.0f, mod->value); - } - } - - DropModCharge(mod, spell); - }; - // Drop charges for triggering spells instead of triggered ones if (m_spellModTakingSpell) - { spell = m_spellModTakingSpell; - } - SpellModifier* chargedMod = nullptr; - for (auto mod : m_spellMods[op]) + switch (op) { - // Charges can be set only for mods with auras - if (!mod->ownerAura) + // special case, if a mod makes spell instant, only consume that mod + case SPELLMOD_CASTING_TIME: { - ASSERT(!mod->charges); - } - - if (!IsAffectedBySpellmod(spellInfo, mod, spell)) - { - continue; - } - - if (mod->ownerAura->IsUsingCharges()) - { - if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority)) + SpellModifier* modInstantSpell = nullptr; + for (SpellModifier* mod : m_spellMods[SPELLMOD_CASTING_TIME]) { - chargedMod = mod; + if (!IsAffectedBySpellmod(spellInfo, mod, spell)) + { + continue; + } + + if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100) + { + modInstantSpell = mod; + break; + } } - continue; + if (modInstantSpell) + { + Player::ApplyModToSpell(modInstantSpell, spell); + basevalue = T(0); + return; + } + break; } - calculateSpellMod(mod); + // special case if two mods apply 100% critical chance, only consume one + case SPELLMOD_CRITICAL_CHANCE: + { + SpellModifier* modCritical = nullptr; + for (auto mod : m_spellMods[SPELLMOD_CRITICAL_CHANCE]) + { + if (!IsAffectedBySpellmod(spellInfo, mod, spell)) + { + continue; + } + + if (mod->type == SPELLMOD_FLAT && mod->value >= 100) + { + modCritical = mod; + break; + } + } + + if (modCritical) + { + Player::ApplyModToSpell(modCritical, spell); + basevalue = T(100); + return; + } + break; + } + + default: + break; } - if (chargedMod) + for (auto mod : m_spellMods[op]) { - calculateSpellMod(chargedMod); - } + if (!IsAffectedBySpellmod(spellInfo, mod, spell)) + continue; + switch (mod->type) + { + case SPELLMOD_FLAT: + totalflat += mod->value; + break; + case SPELLMOD_PCT: + { + // skip percent mods for null basevalue (most important for spell mods with charges) + if (basevalue == T(0)) + { + continue; + } + + // special case (skip > 10s spell casts for instant cast setting) + if (op == SPELLMOD_CASTING_TIME) + { + if (mod->value <= -100 && basevalue >= T(10000)) + { + continue; + } + } + + totalmul += CalculatePct(1.f, mod->value); + break; + } + } + + /*// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied + else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) + continue; + // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied + else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) + continue; + // xinef: those two mods should be multiplicative (Glyph of Renew) + if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) + totalmul *= CalculatePct(1.0f, 100.0f + mod->value); + else + totalmul += CalculatePct(1.0f, mod->value);*/ + + Player::ApplyModToSpell(mod, spell); + } float diff = 0.0f; if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION) - { diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat; - } else - { diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat; - } - basevalue = T((float)basevalue + diff); - return T(diff); } + #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d190cbdcd..67669f562 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -98,44 +98,92 @@ float playerBaseMoveSpeed[MAX_MOVE_TYPE] = 3.14f // MOVE_PITCH_RATE }; -// Used for prepare can/can`t triggr aura -static bool InitTriggerAuraData(); -// Define can trigger auras -static bool isTriggerAura[TOTAL_AURAS]; -// Define can't trigger auras (need for disable second trigger) -static bool isNonTriggerAura[TOTAL_AURAS]; -// Triggered always, even from triggered spells -static bool isAlwaysTriggeredAura[TOTAL_AURAS]; -// Prepare lists -static bool procPrepared = InitTriggerAuraData(); - -DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage) - : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask), - m_damageType(_damageType), m_attackType(BASE_ATTACK), m_cleanDamage(cleanDamage) +DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType, uint32 cleanDamage) + : m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), + m_damageType(damageType), m_attackType(attackType), m_absorb(0), m_resist(0), m_block(0), m_hitMask(0), m_cleanDamage(cleanDamage) { - m_absorb = 0; - m_resist = 0; - m_block = 0; } DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo) : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)), m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.absorb), m_resist(dmgInfo.resist), m_block(dmgInfo.blocked_amount), - m_cleanDamage(dmgInfo.cleanDamage) + m_hitMask(0), m_cleanDamage(dmgInfo.cleanDamage) { + switch (dmgInfo.TargetState) + { + case VICTIMSTATE_IS_IMMUNE: + m_hitMask |= PROC_HIT_IMMUNE; + break; + case VICTIMSTATE_BLOCKS: + m_hitMask |= PROC_HIT_FULL_BLOCK; + break; + } + + if (dmgInfo.HitInfo & (HITINFO_PARTIAL_ABSORB | HITINFO_FULL_ABSORB)) + { + m_hitMask |= PROC_HIT_ABSORB; + } + + if (dmgInfo.HitInfo & HITINFO_FULL_RESIST) + { + m_hitMask |= PROC_HIT_FULL_RESIST; + } + + if (m_block) + { + m_hitMask |= PROC_HIT_BLOCK; + } + + bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || + (m_hitMask & (PROC_HIT_IMMUNE | PROC_HIT_FULL_BLOCK)) != 0; + + switch (dmgInfo.hitOutCome) + { + case MELEE_HIT_MISS: + m_hitMask |= PROC_HIT_MISS; + break; + case MELEE_HIT_DODGE: + m_hitMask |= PROC_HIT_DODGE; + break; + case MELEE_HIT_PARRY: + m_hitMask |= PROC_HIT_PARRY; + break; + case MELEE_HIT_EVADE: + m_hitMask |= PROC_HIT_EVADE; + break; + case MELEE_HIT_BLOCK: + case MELEE_HIT_CRUSHING: + case MELEE_HIT_GLANCING: + case MELEE_HIT_NORMAL: + if (!damageNullified) + m_hitMask |= PROC_HIT_NORMAL; + break; + case MELEE_HIT_CRIT: + if (!damageNullified) + m_hitMask |= PROC_HIT_CRITICAL; + break; + } } -DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType) +DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType /*attackType*/, uint32 /* hitMask */) : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_spellInfo(spellNonMeleeDamage.spellInfo), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), - m_cleanDamage(spellNonMeleeDamage.cleanDamage) + m_hitMask(0), m_cleanDamage(spellNonMeleeDamage.cleanDamage) { + if (spellNonMeleeDamage.blocked) + { + m_hitMask |= PROC_HIT_BLOCK; + } + if (spellNonMeleeDamage.absorb) + { + m_hitMask |= PROC_HIT_ABSORB; + } } void DamageInfo::ModifyDamage(int32 amount) { - amount = std::min(amount, int32(GetDamage())); + amount = std::max(amount, -static_cast(GetDamage())); m_damage += amount; } @@ -144,6 +192,7 @@ void DamageInfo::AbsorbDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_absorb += amount; m_damage -= amount; + m_hitMask |= PROC_HIT_ABSORB;m_damage -= amount; } void DamageInfo::ResistDamage(uint32 amount) @@ -151,6 +200,11 @@ void DamageInfo::ResistDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_resist += amount; m_damage -= amount; + if (!m_damage) + { + m_hitMask |= PROC_HIT_FULL_RESIST; + m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL); + } } void DamageInfo::BlockDamage(uint32 amount) @@ -158,6 +212,37 @@ void DamageInfo::BlockDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_block += amount; m_damage -= amount; + m_hitMask |= PROC_HIT_BLOCK; + if (!m_damage) + { + m_hitMask |= PROC_HIT_FULL_BLOCK; + m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL); + } +} + +uint32 DamageInfo::GetHitMask() const +{ + return m_hitMask; +} + +HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask) + : m_healer(healer), m_target(target), m_heal(heal), m_effectiveHeal(0), m_absorb(0), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_hitMask(0) +{ +} + +void HealInfo::AbsorbHeal(uint32 amount) +{ + amount = std::min(amount, GetHeal()); + m_absorb += amount; + m_heal -= amount; + amount = std::min(amount, GetEffectiveHeal()); + m_effectiveHeal -= amount; + m_hitMask |= PROC_HIT_ABSORB; +} + +uint32 HealInfo::GetHitMask() const +{ + return m_hitMask; } uint32 DamageInfo::GetUnmitigatedDamage() const @@ -231,6 +316,7 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; + m_extraAttacks = 0; m_canDualWield = false; m_rootTimes = 0; @@ -317,8 +403,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), _oldFactionId = 0; _isWalkingBeforeCharm = false; - - _lastExtraAttackSpell = 0; } //////////////////////////////////////////////////////////// @@ -444,23 +528,6 @@ void Unit::Update(uint32 p_time) } } - _lastDamagedTargetGuid = ObjectGuid::Empty; - if (_lastExtraAttackSpell) - { - while (!extraAttacksTargets.empty()) - { - auto itr = extraAttacksTargets.begin(); - ObjectGuid targetGuid = itr->first; - uint32 count = itr->second; - extraAttacksTargets.erase(itr); - if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid)) - { - HandleProcExtraAttackFor(victim, count); - } - } - _lastExtraAttackSpell = 0; - } - // not implemented before 3.0.2 // xinef: if attack time > 0, reduce by diff // if on next update, attack time < 0 assume player didnt attack - set to 0 @@ -893,7 +960,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage } else { - DamageInfo sharedDamageInfo(attacker, shareDamageTarget, shareDamage, spellProto, damageSchoolMask, damagetype); + DamageInfo sharedDamageInfo(attacker, shareDamageTarget, shareDamage, spellProto, damageSchoolMask, damagetype, BASE_ATTACK); Unit::CalcAbsorbResist(sharedDamageInfo, true); shareAbsorb = sharedDamageInfo.GetAbsorb(); shareResist = sharedDamageInfo.GetResist(); @@ -1022,7 +1089,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage //if (attacker && victim->GetTypeId() == TYPEID_PLAYER && victim != attacker) //victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); // pussywizard: optimization - Unit::Kill(attacker, victim, durabilityLoss, cleanDamage ? cleanDamage->attackType : BASE_ATTACK, spellProto, damageSpell); + Unit::Kill(attacker, victim, durabilityLoss, cleanDamage ? cleanDamage->attackType : BASE_ATTACK, spellProto); } else { @@ -1319,7 +1386,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama uint32 crit_bonus = damage; // Apply crit_damage bonus for melee spells if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + modOwner->ApplySpellMod(spellInfo->Id, crit_bonus); damage += crit_bonus; // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE @@ -1403,7 +1470,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // Calculate absorb resist if (damageInfo->damage > 0) { - DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE); + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, 0); Unit::CalcAbsorbResist(dmgInfo); damageInfo->absorb = dmgInfo.GetAbsorb(); damageInfo->resist = dmgInfo.GetResist(); @@ -1453,7 +1520,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo = 0; damageInfo->procAttacker = PROC_FLAG_NONE; damageInfo->procVictim = PROC_FLAG_NONE; - damageInfo->procEx = PROC_EX_NONE; damageInfo->hitOutCome = MELEE_HIT_EVADE; if (!victim) @@ -1484,7 +1550,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo |= HITINFO_NORMALSWING; damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; - damageInfo->procEx |= PROC_EX_IMMUNE; return; } @@ -1517,27 +1582,23 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam case MELEE_HIT_EVADE: damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND; damageInfo->TargetState = VICTIMSTATE_EVADES; - damageInfo->procEx |= PROC_EX_EVADE; damageInfo->damage = 0; damageInfo->cleanDamage = 0; return; case MELEE_HIT_MISS: damageInfo->HitInfo |= HITINFO_MISS; damageInfo->TargetState = VICTIMSTATE_INTACT; - damageInfo->procEx |= PROC_EX_MISS; damageInfo->damage = 0; damageInfo->cleanDamage = 0; break; case MELEE_HIT_NORMAL: damageInfo->TargetState = VICTIMSTATE_HIT; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; break; case MELEE_HIT_CRIT: { damageInfo->HitInfo |= HITINFO_CRITICALHIT; damageInfo->TargetState = VICTIMSTATE_HIT; - damageInfo->procEx |= PROC_EX_CRITICAL_HIT; // Crit bonus calc damageInfo->damage += damageInfo->damage; float mod = 0.0f; @@ -1562,20 +1623,17 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam } case MELEE_HIT_PARRY: damageInfo->TargetState = VICTIMSTATE_PARRY; - damageInfo->procEx |= PROC_EX_PARRY; damageInfo->cleanDamage += damageInfo->damage; damageInfo->damage = 0; break; case MELEE_HIT_DODGE: damageInfo->TargetState = VICTIMSTATE_DODGE; - damageInfo->procEx |= PROC_EX_DODGE; damageInfo->cleanDamage += damageInfo->damage; damageInfo->damage = 0; break; case MELEE_HIT_BLOCK: damageInfo->TargetState = VICTIMSTATE_HIT; damageInfo->HitInfo |= HITINFO_BLOCK; - damageInfo->procEx |= PROC_EX_BLOCK; damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); // double blocked amount if block is critical if (damageInfo->target->isBlockCritical()) @@ -1584,10 +1642,8 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam { damageInfo->TargetState = VICTIMSTATE_BLOCKS; damageInfo->blocked_amount = damageInfo->damage; - damageInfo->procEx |= PROC_EX_FULL_BLOCK; } - else - damageInfo->procEx |= PROC_EX_NORMAL_HIT; + damageInfo->damage -= damageInfo->blocked_amount; damageInfo->cleanDamage += damageInfo->blocked_amount; break; @@ -1595,7 +1651,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam { damageInfo->HitInfo |= HITINFO_GLANCING; damageInfo->TargetState = VICTIMSTATE_HIT; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; int32 leveldif = int32(victim->getLevel()) - int32(getLevel()); if (leveldif > 3) leveldif = 3; @@ -1607,7 +1662,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam case MELEE_HIT_CRUSHING: damageInfo->HitInfo |= HITINFO_CRUSHING; damageInfo->TargetState = VICTIMSTATE_HIT; - damageInfo->procEx |= PROC_EX_NORMAL_HIT; // 150% normal damage damageInfo->damage += (damageInfo->damage / 2); break; @@ -1649,7 +1703,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam if (damageInfo->absorb) { damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); - damageInfo->procEx |= PROC_EX_ABSORB; } if (damageInfo->resist) @@ -1735,7 +1788,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) } if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx); + { + DamageInfo dmgInfo(*damageInfo); + ToPlayer()->CastItemCombatSpell(dmgInfo); + } // Do effect if any damage done to target if (damageInfo->damage) @@ -1770,7 +1826,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) uint32 absorb = 0; - DamageInfo dmgInfo(victim, this, damage, i_spellProto, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE); + DamageInfo dmgInfo(victim, this, damage, i_spellProto, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); Unit::CalcAbsorbResist(dmgInfo); absorb = dmgInfo.GetAbsorb(); damage = dmgInfo.GetDamage(); @@ -1836,7 +1892,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, co if (spellInfo) if (Player* modOwner = attacker->GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); + modOwner->ApplySpellMod(spellInfo->Id, armor); AuraEffectList const& ResIgnoreAurasAb = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j) @@ -2185,11 +2241,9 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) uint32 splitted_absorb = 0; uint32 splitted_resist = 0; - uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; - DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, schoolMask, dmgInfo.GetDamageType()); + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, schoolMask, dmgInfo.GetDamageType(), BASE_ATTACK); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { - procEx |= PROC_EX_IMMUNE; splittedDmgInfo.AbsorbDamage(splitted); } else @@ -2202,10 +2256,6 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) splitted_resist = splittedDmgInfo.GetResist(); splitted = splittedDmgInfo.GetDamage(); - // create procs - createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); - caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr, -1, nullptr, &splittedDmgInfo); - if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo(), splitted, schoolMask, splitted_absorb, splitted_resist, false, 0, false); @@ -2256,11 +2306,9 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) uint32 splitted_absorb = 0; uint32 splitted_resist = 0; - uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; - DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, splitSchoolMask, dmgInfo.GetDamageType()); + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, splitSchoolMask, dmgInfo.GetDamageType(), BASE_ATTACK); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { - procEx |= PROC_EX_IMMUNE; splittedDmgInfo.AbsorbDamage(splitted); } else @@ -2273,10 +2321,6 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) splitted_resist = splittedDmgInfo.GetResist(); splitted = splittedDmgInfo.GetDamage(); - // create procs - createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); - caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); - if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo, splitted, splitSchoolMask, splitted_absorb, splitted_resist, false, 0, false); @@ -2376,11 +2420,6 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case - if (!extra && _lastExtraAttackSpell) - { - _lastExtraAttackSpell = 0; - } - bool meleeAttack = true; // melee attack spell casted at main hand attack only - no normal melee dmg dealt @@ -2420,16 +2459,11 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A Unit::DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb); SendAttackStateUpdate(&damageInfo); - //TriggerAurasProcOnEvent(damageInfo); - - _lastDamagedTargetGuid = victim->GetGUID(); + DamageInfo dmgInfo(damageInfo); + ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); DealMeleeDamage(&damageInfo, true); - DamageInfo dmgInfo(damageInfo); - Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, - damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo); - if (GetTypeId() == TYPEID_PLAYER) LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.", GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); @@ -2536,31 +2570,15 @@ bool Unit::GetMeleeAttackPoint(Unit* attacker, Position& pos) return true; } -void Unit::HandleProcExtraAttackFor(Unit* victim, uint32 count) +void Unit::HandleProcExtraAttackFor(Unit* victim) { - while (count) + while (m_extraAttacks) { - --count; AttackerStateUpdate(victim, BASE_ATTACK, true); + --m_extraAttacks; } } -void Unit::AddExtraAttacks(uint32 count) -{ - ObjectGuid targetGUID = _lastDamagedTargetGuid; - if (!targetGUID) - { - if (ObjectGuid selection = GetTarget()) - { - targetGUID = selection; // Spell was cast directly (not triggered by aura) - } - else - return; - } - - extraAttacksTargets[targetGUID] += count; -} - MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const { // This is only wrapper @@ -3130,7 +3148,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo // Spellmod from SPELLMOD_RESIST_MISS_CHANCE if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); + modOwner->ApplySpellMod(spellInfo->Id, modHitChance); // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); @@ -3260,8 +3278,6 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca reflectchance += (*i)->GetAmount(); if (reflectchance > 0 && roll_chance_i(reflectchance)) { - // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) - //ProcDamageAndSpell(victim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); return SPELL_MISS_REFLECT; } } @@ -5973,15 +5989,20 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, SendSpellNonMeleeDamageLog(&log); } -void Unit::ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase) +void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { - // Not much to do if no flags are set. - if (procAttacker && actor) - actor->ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase); - // Now go on with a victim's events'n'auras - // Not much to do if no flags are set or there is no victim - if (victim && victim->IsAlive() && procVictim) - victim->ProcDamageAndSpellFor(true, actor, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase); + WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK; + if (typeMaskActor) + { + ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); + } + + if (typeMaskActionTarget && actionTarget) + { + actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType); + } + + TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) @@ -6162,3458 +6183,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType SendAttackStateUpdate(&dmgInfo); } -//victim may be nullptr -bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/) -{ - SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); - uint32 effIndex = triggeredByAura->GetEffIndex(); - int32 triggerAmount = triggeredByAura->GetAmount(); - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; - - uint32 triggered_spell_id = 0; - uint32 cooldown_spell_id = 0; // for random trigger, will be one of the triggered spell to avoid repeatable triggers - // otherwise, it's the triggered_spell_id by default - Unit* target = victim; - int32 basepoints0 = 0; - ObjectGuid originalCaster; - - switch (dummySpell->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch (dummySpell->Id) - { - // Overkill - case 58426: - { - triggered_spell_id = 58427; - break; - } - // Unstable Power - case 24658: - { - if (!procSpell || procSpell->Id == 24659) - return false; - // Need remove one 24659 aura - RemoveAuraFromStack(24659); - return true; - } - // Restless Strength - case 24661: - { - // Need remove one 24662 aura - RemoveAuraFromStack(24662); - return true; - } - // Mark of Malice - case 33493: - { - if (triggeredByAura->GetBase()->GetCharges() > 1) - return true; - - target = this; - triggered_spell_id = 33494; - break; - } - // Twisted Reflection (boss spell) - case 21063: - triggered_spell_id = 21064; - break; - // Vampiric Aura (boss spell) - case 38196: - { - basepoints0 = 3 * damage; // 300% - if (basepoints0 < 0) - return false; - - triggered_spell_id = 31285; - target = this; - break; - } - // Aura of Madness (Darkmoon Card: Madness trinket) - //===================================================== - // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) - // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) - // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) - // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) - // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) - // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) - // 41011 Martyr Complex: +35 stamina (All classes) - // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - case 39446: - { - if (GetTypeId() != TYPEID_PLAYER || !IsAlive()) - return false; - - // Select class defined buff - switch (getClass()) - { - case CLASS_PALADIN: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409 - case CLASS_DRUID: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409 - triggered_spell_id = RAND(39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409); - cooldown_spell_id = 39511; - break; - case CLASS_ROGUE: // 39511, 40997, 40998, 41002, 41005, 41011 - case CLASS_WARRIOR: // 39511, 40997, 40998, 41002, 41005, 41011 - case CLASS_DEATH_KNIGHT: - triggered_spell_id = RAND(39511, 40997, 40998, 41002, 41005, 41011); - cooldown_spell_id = 39511; - break; - case CLASS_PRIEST: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 - case CLASS_SHAMAN: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 - case CLASS_MAGE: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 - case CLASS_WARLOCK: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 - triggered_spell_id = RAND(40999, 41002, 41005, 41009, 41011, 41406, 41409); - cooldown_spell_id = 40999; - break; - case CLASS_HUNTER: // 40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409 - triggered_spell_id = RAND(40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409); - cooldown_spell_id = 40997; - break; - default: - return false; - } - - target = this; - if (roll_chance_i(10)) - ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); // TODO: It should be moved to database, shouldn't it? - break; - } - // Sunwell Exalted Caster Neck (??? neck) - // cast ??? Light's Wrath if Exalted by Aldor - // cast ??? Arcane Bolt if Exalted by Scryers - case 46569: - return false; // old unused version - // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) - // cast 45479 Light's Wrath if Exalted by Aldor - // cast 45429 Arcane Bolt if Exalted by Scryers - case 45481: - { - Player* player = ToPlayer(); - if (!player) - return false; - - // Get Aldor reputation rank - if (player->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45479; - break; - } - // Get Scryers reputation rank - if (player->GetReputationRank(934) == REP_EXALTED) - { - // triggered at positive/self casts also, current attack target used then - if (target && IsFriendlyTo(target)) - { - target = GetVictim(); - if (!target) - { - target = player->GetSelectedUnit(); - if (!target) - return false; - } - if (IsFriendlyTo(target)) - return false; - } - - triggered_spell_id = 45429; - break; - } - return false; - } - // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) - // cast 45480 Light's Strength if Exalted by Aldor - // cast 45428 Arcane Strike if Exalted by Scryers - case 45482: - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45480; - break; - } - // Get Scryers reputation rank - if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45428; - break; - } - return false; - } - // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) - // cast 45431 Arcane Insight if Exalted by Aldor - // cast 45432 Light's Ward if Exalted by Scryers - case 45483: - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45432; - break; - } - // Get Scryers reputation rank - if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45431; - break; - } - return false; - } - // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) - // cast 45478 Light's Salvation if Exalted by Aldor - // cast 45430 Arcane Surge if Exalted by Scryers - case 45484: - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - // Get Aldor reputation rank - if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) - { - target = this; - triggered_spell_id = 45478; - break; - } - // Get Scryers reputation rank - if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) - { - triggered_spell_id = 45430; - break; - } - return false; - } - // Kill command - case 58914: - { - // Remove aura stack from pet - RemoveAuraFromStack(58914); - Unit* owner = GetOwner(); - if (!owner) - return true; - // reduce the owner's aura stack - owner->RemoveAuraFromStack(34027); - return true; - } - // Vampiric Touch (generic, used by some boss) - case 52723: - case 60501: - { - triggered_spell_id = 52724; - basepoints0 = damage / 2; - target = this; - break; - } - // Divine purpose - case 31871: - case 31872: - { - // Roll chane - if (!victim || !victim->IsAlive() || !roll_chance_i(triggerAmount)) - return false; - - // Remove any stun effect on target - victim->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL); - return true; - } - // Glyph of Life Tap - case 63320: - { - triggered_spell_id = 63321; // Life Tap - break; - } - case 71519: // Deathbringer's Will Normal - { - if (GetTypeId() != TYPEID_PLAYER || HasSpellCooldown(71484)) - return false; - - AddSpellCooldown(71484, 0, cooldown); - - std::vector RandomSpells; - switch (getClass()) - { - case CLASS_WARRIOR: - case CLASS_PALADIN: - case CLASS_DEATH_KNIGHT: - RandomSpells.push_back(71484); - RandomSpells.push_back(71491); - RandomSpells.push_back(71492); - break; - case CLASS_SHAMAN: - case CLASS_ROGUE: - RandomSpells.push_back(71486); - RandomSpells.push_back(71485); - RandomSpells.push_back(71492); - break; - case CLASS_DRUID: - RandomSpells.push_back(71484); - RandomSpells.push_back(71485); - RandomSpells.push_back(71492); - break; - case CLASS_HUNTER: - RandomSpells.push_back(71486); - RandomSpells.push_back(71491); - RandomSpells.push_back(71485); - break; - default: - return false; - } - if (RandomSpells.empty()) // shouldn't happen - return false; - - uint8 rand_spell = irand(0, (RandomSpells.size() - 1)); - CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); - break; - } - case 71562: // Deathbringer's Will Heroic - { - if (GetTypeId() != TYPEID_PLAYER || HasSpellCooldown(71561)) - return false; - - AddSpellCooldown(71561, 0, cooldown); - - std::vector RandomSpells; - switch (getClass()) - { - case CLASS_WARRIOR: - case CLASS_PALADIN: - case CLASS_DEATH_KNIGHT: - RandomSpells.push_back(71561); - RandomSpells.push_back(71559); - RandomSpells.push_back(71560); - break; - case CLASS_SHAMAN: - case CLASS_ROGUE: - RandomSpells.push_back(71558); - RandomSpells.push_back(71556); - RandomSpells.push_back(71560); - break; - case CLASS_DRUID: - RandomSpells.push_back(71561); - RandomSpells.push_back(71556); - RandomSpells.push_back(71560); - break; - case CLASS_HUNTER: - RandomSpells.push_back(71558); - RandomSpells.push_back(71559); - RandomSpells.push_back(71556); - break; - default: - return false; - } - if (RandomSpells.empty()) // shouldn't happen - return false; - - uint8 rand_spell = irand(0, (RandomSpells.size() - 1)); - CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); - break; - } - // Freya, Petrified Bark - case 62933: - case 62337: - { - if (!victim) - return false; - - int32 dmg = damage; - victim->CastCustomSpell(this, 62379, &dmg, 0, 0, true); - return true; - } - // Trial of the Champion, Earth Shield - case 67534: - { - const int32 dmg = (int32)damage; - CastCustomSpell(this, 67535, &dmg, nullptr, nullptr, true, 0, triggeredByAura, triggeredByAura->GetCasterGUID()); - return true; - } - // Trial of the Crusader, Faction Champions, Retaliation - case 65932: - { - // check attack comes not from behind - if (!victim || !HasInArc(M_PI, victim)) - return false; - - triggered_spell_id = 65934; - break; - } - // Pit of Saron, Tyrannus, Overlord's Brand - case 69172: // everything except for DoTs - { - if (!target) - return false; - if (Unit* caster = triggeredByAura->GetCaster()) - { - if (procFlag & (PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS)) - { - int32 dmg = 5.5f * damage; - target->CastCustomSpell(caster, 69190, &dmg, 0, 0, true); - } - else - { - if (caster->GetVictim()) - { - int32 dmg = damage; - target->CastCustomSpell(caster->GetVictim(), 69189, &dmg, 0, 0, true); - } - } - } - return true; - } - // Pit of Saron, Tyrannus, Overlord's Brand - case 69173: // only DoTs - { - if (!target) - return false; - if (Unit* caster = triggeredByAura->GetCaster()) - { - if (procEx & PROC_EX_INTERNAL_HOT) - { - int32 dmg = 5.5f * damage; - target->CastCustomSpell(caster, 69190, &dmg, 0, 0, true); - } - else - { - if (caster->GetVictim()) - { - int32 dmg = damage; - target->CastCustomSpell(caster->GetVictim(), 69189, &dmg, 0, 0, true); - } - } - } - return true; - } - // Icecrown Citadel, Lady Deathwhisper, Vampiric Might - case 70674: - { - if (Unit* caster = triggeredByAura->GetCaster()) - { - int32 dmg = 3 * damage; - caster->CastCustomSpell(caster, 70677, &dmg, 0, 0, true); - } - return true; - } - // Item: Purified Shard of the Gods - case 69755: - { - triggered_spell_id = ((procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69733 : 69729); - break; - } - // Item: Shiny Shard of the Gods - case 69739: - { - triggered_spell_id = ((procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69734 : 69730); - break; - } - // VoA: Meteor Fists koralon - case 66725: - case 68161: - { - triggered_spell_id = 66765; // handled by spell_difficulty - break; - } - } - break; - } - case SPELLFAMILY_MAGE: - { - // Magic Absorption - if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura - { - if (getPowerType() != POWER_MANA) - return false; - - // mana reward - basepoints0 = CalculatePct(int32(GetMaxPower(POWER_MANA)), triggerAmount); - target = this; - triggered_spell_id = 29442; - break; - } - // Hot Streak - if (dummySpell->SpellIconID == 2999) - { - if (effIndex != 0) - return false; - AuraEffect* counter = triggeredByAura->GetBase()->GetEffect(EFFECT_1); - if (!counter) - return true; - - // Count spell criticals in a row in second aura - if (procEx & PROC_EX_CRITICAL_HIT) - { - counter->SetAmount(counter->GetAmount() * 2); - if (counter->GetAmount() < 100) // not enough - return true; - // Crititcal counted -> roll chance - if (roll_chance_i(triggerAmount)) - CastSpell(this, 48108, true, castItem, triggeredByAura); - } - counter->SetAmount(25); - return true; - } - // Incanter's Regalia set (add trigger chance to Mana Shield) - if (dummySpell->SpellFamilyFlags[0] & 0x8000) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - target = this; - triggered_spell_id = 37436; - break; - } - switch (dummySpell->Id) - { - // Glyph of Polymorph - case 56375: - { - if (!target) - return false; - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed. - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); - target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); - return true; - } - // Glyph of Icy Veins - case 56374: - { - RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false); - RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - return true; - } - // Glyph of Ice Block - case 56372: - { - Player* player = ToPlayer(); - if (!player) - return false; - - SpellCooldowns const cooldowns = player->GetSpellCooldowns(); - // remove cooldowns on all ranks of Frost Nova - for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr) - { - SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first); - // Frost Nova - if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE - && cdSpell->SpellFamilyFlags[0] & 0x00000040) - player->RemoveSpellCooldown(cdSpell->Id, true); - } - break; - } - } - break; - } - case SPELLFAMILY_WARRIOR: - { - switch (dummySpell->Id) - { - // Victorious - case 32216: - { - RemoveAura(dummySpell->Id); - return false; - } - } - - // Second Wind - if (dummySpell->SpellIconID == 1697) - { - // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example) - if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) - return false; - // Need stun or root mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN)))) - return false; - - switch (dummySpell->Id) - { - case 29838: - triggered_spell_id = 29842; - break; - case 29834: - triggered_spell_id = 29841; - break; - case 42770: - triggered_spell_id = 42771; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: {} (SW)", dummySpell->Id); - return false; - } - - target = this; - break; - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Seed of Corruption - if (dummySpell->SpellFamilyFlags[1] & 0x00000010) - { - if (procSpell && procSpell->SpellFamilyFlags[1] & 0x8000) - return false; - // if damage is more than need or target die from damage deal finish spell - if (triggeredByAura->GetAmount() <= int32(damage) || GetHealth() <= damage) - { - // remember guid before aura delete - ObjectGuid casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - uint32 spell = sSpellMgr->GetSpellWithRank(27285, dummySpell->GetRank()); - - // Cast finish spell (triggeredByAura already not exist!) - if (Unit* caster = ObjectAccessor::GetUnit(*this, casterGuid)) - { - this->CastSpell(this, 37826, true); // VISUAL! - caster->CastSpell(this, spell, true, castItem); - } - - return true; // no hidden cooldown - } - - // Damage counting - triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage); - return true; - } - // Seed of Corruption (Mobs cast) - no die req - if (dummySpell->SpellFamilyFlags.IsEqual(0, 0, 0) && dummySpell->SpellIconID == 1932) - { - // if damage is more than need deal finish spell - if (triggeredByAura->GetAmount() <= int32(damage)) - { - // remember guid before aura delete - ObjectGuid casterGuid = triggeredByAura->GetCasterGUID(); - - // Remove aura (before cast for prevent infinite loop handlers) - RemoveAurasDueToSpell(triggeredByAura->GetId()); - - // Cast finish spell (triggeredByAura already not exist!) - if (Unit* caster = ObjectAccessor::GetUnit(*this, casterGuid)) - { - this->CastSpell(this, 37826, true); // VISUAL! - caster->CastSpell(this, 32865, true, castItem); - } - return true; // no hidden cooldown - } - // Damage counting - triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage); - return true; - } - switch (dummySpell->Id) - { - // Nightfall - case 18094: - case 18095: - // Glyph of corruption - case 56218: - { - target = this; - triggered_spell_id = 17941; - break; - } - // Soul Leech - case 30293: - case 30295: - case 30296: - { - // Improved Soul Leech - AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i) - { - if ((*i)->GetId() == 54117 || (*i)->GetId() == 54118) - { - if ((*i)->GetEffIndex() != 0) - continue; - basepoints0 = int32((*i)->GetAmount()); - target = GetGuardianPet(); - if (target) - { - // regen mana for pet - CastCustomSpell(target, 54607, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); - } - // regen mana for caster - CastCustomSpell(this, 59117, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); - // Get second aura of spell for replenishment effect on party - if (AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1)) - { - // Replenishment - roll chance - if (roll_chance_i(aurEff->GetAmount())) - { - CastSpell(this, 57669, true, castItem, triggeredByAura); - } - } - break; - } - } - // health - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - triggered_spell_id = 30294; - break; - } - // Shadowflame (Voidheart Raiment set bonus) - case 37377: - { - triggered_spell_id = 37379; - break; - } - // Pet Healing (Corruptor Raiment or Rift Stalker Armor) - case 37381: - { - target = GetGuardianPet(); - if (!target) - return false; - - // heal amount - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 37382; - break; - } - // Shadowflame Hellfire (Voidheart Raiment set bonus) - case 39437: - { - triggered_spell_id = 37378; - break; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Body and Soul - if (dummySpell->SpellIconID == 2218) - { - // Proc only from Abolish desease on self cast - if (procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount)) - return false; - triggered_spell_id = 64136; - target = this; - break; - } - switch (dummySpell->Id) - { - // Vampiric Embrace - case 15286: - { - if (!victim || !victim->IsAlive() || procSpell->SpellFamilyFlags[1] & 0x80000) - return false; - - // heal amount - int32 total = CalculatePct(int32(damage), triggerAmount); - int32 team = total / 5; - int32 self = total - team; - CastCustomSpell(this, 15290, &team, &self, nullptr, true, castItem, triggeredByAura); - return true; // no hidden cooldown - } - // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) - case 40438: - { - // Shadow Word: Pain - if (procSpell->SpellFamilyFlags[0] & 0x8000) - triggered_spell_id = 40441; - // Renew - else if (procSpell->SpellFamilyFlags[0] & 0x40) - triggered_spell_id = 40440; - else - return false; - - target = this; - break; - } - // Improved Shadowform - case 47570: - case 47569: - { - if (!roll_chance_i(triggerAmount)) - return false; - - RemoveMovementImpairingAuras(true); - break; - } - // Glyph of Dispel Magic - case 55677: - { - // Dispel Magic shares spellfamilyflag with abolish disease - if (procSpell->SpellIconID != 74) - return false; - if (!target || !target->IsFriendlyTo(this)) - return false; - - basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount)); - triggered_spell_id = 56131; - break; - } - // Oracle Healing Bonus ("Garments of the Oracle" set) - case 26169: - { - // heal amount - basepoints0 = int32(CalculatePct(damage, 10)); - target = this; - triggered_spell_id = 26170; - break; - } - // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set - case 39372: - { - if (!procSpell || (procSpell->GetSchoolMask() & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0) - return false; - - // heal amount - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - triggered_spell_id = 39373; - break; - } - // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus) - case 28809: - { - triggered_spell_id = 28810; - break; - } - // Priest T10 Healer 2P Bonus - case 70770: - // Flash Heal - if (procSpell->SpellFamilyFlags[0] & 0x800) - { - triggered_spell_id = 70772; - SpellInfo const* blessHealing = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!blessHealing || !victim) - return false; - basepoints0 = int32(CalculatePct(damage, triggerAmount) / (blessHealing->GetMaxDuration() / blessHealing->Effects[0].Amplitude)); - victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_HEAL, basepoints0); - return true; - } - break; - } - break; - } - case SPELLFAMILY_DRUID: - { - switch (dummySpell->Id) - { - // Glyph of Innervate - case 54832: - { - if (procSpell->SpellIconID != 62) - return false; - - int32 mana_perc = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcValue(); - basepoints0 = int32(CalculatePct(GetCreatePowers(POWER_MANA), mana_perc) / 10); - triggered_spell_id = 54833; - target = this; - break; - } - // Glyph of Starfire - case 54845: - { - triggered_spell_id = 54846; - break; - } - // Glyph of Shred - case 54815: - { - if (!target) - return false; - - // try to find spell Rip on the target - if (AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID())) - { - // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip - uint32 CountMin = AurEff->GetBase()->GetMaxDuration(); - - // just Rip's max duration without other spells - uint32 CountMax = AurEff->GetSpellInfo()->GetMaxDuration(); - - // add possible auras' and Glyph of Shred's max duration - CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds - CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds - CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds - - // if min < max -> that means caster didn't cast 3 shred yet - // so set Rip's duration and max duration - if (CountMin < CountMax) - { - AurEff->GetBase()->SetDuration(AurEff->GetBase()->GetDuration() + triggerAmount * IN_MILLISECONDS); - AurEff->GetBase()->SetMaxDuration(CountMin + triggerAmount * IN_MILLISECONDS); - return true; - } - } - // if not found Rip - return false; - } - // Glyph of Rake - case 54821: - { - if (procSpell->SpellVisual[0] == 750 && procSpell->Effects[1].ApplyAuraName == 3) - { - if (target && target->GetTypeId() == TYPEID_UNIT) - { - triggered_spell_id = 54820; - break; - } - } - return false; - } - // Leader of the Pack - case 24932: - { - if (triggerAmount <= 0) - return false; - basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); - target = this; - triggered_spell_id = 34299; - if (triggeredByAura->GetCasterGUID() != GetGUID()) - break; - int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); - // Improved Leader of the Pack - // Check cooldown of heal spell cooldown - if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) - CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); - break; - } - // Healing Touch (Dreamwalker Raiment set) - case 28719: - { - // mana back - basepoints0 = int32(CalculatePct(spellProc->GetPowerCost(), 30)); - target = this; - triggered_spell_id = 28742; - break; - } - // Glyph of Rejuvenation - case 54754: - { - if (!victim || !victim->HealthBelowPct(uint32(triggerAmount))) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 54755; - break; - } - // Healing Touch Refund (Idol of Longevity trinket) - case 28847: - { - target = this; - triggered_spell_id = 28848; - break; - } - // Mana Restore (Malorne Raiment set / Malorne Regalia set) - case 37288: - case 37295: - { - target = this; - triggered_spell_id = 37238; - break; - } - // Druid Tier 6 Trinket - case 40442: - { - float chance; - - // Starfire - if (procSpell->SpellFamilyFlags[0] & 0x4) - { - triggered_spell_id = 40445; - chance = 25.0f; - } - // Rejuvenation - else if (procSpell->SpellFamilyFlags[0] & 0x10) - { - triggered_spell_id = 40446; - chance = 25.0f; - } - // Mangle (Bear) and Mangle (Cat) - else if (procSpell->SpellFamilyFlags[1] & 0x00000440) - { - triggered_spell_id = 40452; - chance = 40.0f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - target = this; - break; - } - // Maim Interrupt - case 44835: - { - // Deadly Interrupt Effect - triggered_spell_id = 32747; - break; - } - // Item - Druid T10 Restoration 4P Bonus (Rejuvenation) - case 70664: - { - // xinef: proc only from normal Rejuvenation, and proc rejuvenation - if (!victim || !procSpell || procSpell->SpellIconID != 64) - return false; - - Player* caster = ToPlayer(); - if (!caster) - return false; - if (!caster->GetGroup() && victim == this) - return false; - - CastCustomSpell(70691, SPELLVALUE_BASE_POINT0, damage, victim, true); - return true; - } - } - // Eclipse - if (dummySpell->SpellIconID == 2856 && GetTypeId() == TYPEID_PLAYER) - { - if (!procSpell || effIndex != 0) - return false; - - bool isWrathSpell = (procSpell->SpellFamilyFlags[0] & 1); - - if (!roll_chance_f(dummySpell->ProcChance * (isWrathSpell ? 0.6f : 1.0f))) - return false; - - target = this; - if (target->HasAura(isWrathSpell ? 48517 : 48518)) - return false; - - triggered_spell_id = isWrathSpell ? 48518 : 48517; - break; - } - [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. - } - case SPELLFAMILY_ROGUE: - { - switch(dummySpell->Id) - { - // Glyph of Backstab - case 56800: - { - if (victim) - if (AuraEffect* aurEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x100000, 0, 0, GetGUID())) - if (Aura* aur = aurEff->GetBase()) - if (!aur->IsRemoved() && aur->GetDuration() > 0) - if ((aur->GetApplyTime() + aur->GetMaxDuration() / 1000 + 5) > (GameTime::GetGameTime().count() + aur->GetDuration() / 1000) ) - { - aur->SetDuration(aur->GetDuration() + 2000); - return true; - } - return false; - } - // Deadly Throw Interrupt - case 32748: - { - // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw - if (this == victim) - return false; - - triggered_spell_id = 32747; - break; - } - } - // Master of subtlety - if( dummySpell->SpellIconID == 2114 ) - { - triggered_spell_id = 31665; - basepoints0 = triggerAmount; - break; - } - // Cut to the Chase - if (dummySpell->SpellIconID == 2909) - { - // "refresh your Slice and Dice duration to its 5 combo point maximum" - // lookup Slice and Dice - if (AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0)) - { - aur->GetBase()->SetDuration(aur->GetSpellInfo()->GetMaxDuration(), true); - return true; - } - return false; - } - // Deadly Brew - else if (dummySpell->SpellIconID == 2963) - { - triggered_spell_id = 3409; - break; - } - // Quick Recovery - else if (dummySpell->SpellIconID == 2116) - { - if (!procSpell) - return false; - - // energy cost save - basepoints0 = CalculatePct(int32(procSpell->ManaCost), triggerAmount); - if (basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 31663; - break; - } - break; - } - case SPELLFAMILY_HUNTER: - { - switch (dummySpell->SpellIconID) - { - case 2236: // Thrill of the Hunt - { - if (!procSpell) - return false; - - Spell* spell = ToPlayer()->m_spellModTakingSpell; - - // Disable charge drop because of Lock and Load - if (spell) - ToPlayer()->SetSpellModTakingSpell(spell, false); - - // Explosive Shot - if (procSpell->SpellFamilyFlags[2] & 0x200) - { - if (!victim) - return false; - if (AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID())) - basepoints0 = pEff->GetSpellInfo()->CalcPowerCost(this, SpellSchoolMask(pEff->GetSpellInfo()->SchoolMask)) * 4 / 10 / 3; - } - else - basepoints0 = procSpell->CalcPowerCost(this, SpellSchoolMask(procSpell->SchoolMask)) * 4 / 10; - - if (spell) - ToPlayer()->SetSpellModTakingSpell(spell, true); - - if (basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 34720; - break; - } - case 3406: // Hunting Party - { - triggered_spell_id = 57669; - target = this; - break; - } - case 3560: // Rapid Recuperation - { - // This effect only from Rapid Killing (mana regen) - if (!(procSpell->SpellFamilyFlags[1] & 0x01000000)) - return false; - - target = this; - - switch (dummySpell->Id) - { - case 53228: // Rank 1 - triggered_spell_id = 56654; - break; - case 53232: // Rank 2 - triggered_spell_id = 58882; - break; - } - break; - } - } - - switch (dummySpell->Id) - { - case 57870: // Glyph of Mend Pet - { - if (!victim) - return false; - - victim->CastSpell(victim, 57894, true, nullptr, nullptr, GetGUID()); - return true; - } - } - break; - } - case SPELLFAMILY_PALADIN: - { - // Light's Beacon - Beacon of Light - if (dummySpell->Id == 53651) - { - if (!victim) - return false; - - // Do not proc from Glyph of Holy Light and Judgement of Light - if (procSpell->Id == 20267 || procSpell->Id == 54968) - { - return false; - } - - Unit* beaconTarget = triggeredByAura->GetBase()->GetCaster(); - if (!beaconTarget || beaconTarget == this || !beaconTarget->GetAura(53563, victim->GetGUID())) - return false; - - basepoints0 = int32(damage); - triggered_spell_id = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(635)) ? 53652 : 53654; - - victim->CastCustomSpell(beaconTarget, triggered_spell_id, &basepoints0, nullptr, nullptr, true, 0, triggeredByAura, victim->GetGUID()); - return true; - } - // Judgements of the Wise - if (dummySpell->SpellIconID == 3017) - { - target = this; - triggered_spell_id = 31930; - // replenishment - CastSpell(this, 57669, true, castItem, triggeredByAura); - break; - } - // Righteous Vengeance - if (dummySpell->SpellIconID == 3025) - { - if (!victim) - return false; - - // 4 damage tick - basepoints0 = triggerAmount * damage / 400; - triggered_spell_id = 61840; - // Add remaining ticks to damage done - victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); - return true; - } - // Sheath of Light - if (dummySpell->SpellIconID == 3030) - { - // 4 healing tick - basepoints0 = triggerAmount * damage / 400; - triggered_spell_id = 54203; - break; - } - switch (dummySpell->Id) - { - // Judgement of Light - case 20185: - { - if (!victim || !victim->IsAlive() || victim->HasSpellCooldown(20267)) - return false; - // 2% of base mana - basepoints0 = int32(victim->CountPctFromMaxHealth(2)); - victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); - victim->AddSpellCooldown(20267, 0, 4 * IN_MILLISECONDS); - return true; - } - // Judgement of Wisdom - case 20186: - { - if (!victim || !victim->IsAlive() || victim->getPowerType() != POWER_MANA || victim->HasSpellCooldown(20268)) - return false; - - // 2% of base mana - basepoints0 = int32(CalculatePct(victim->GetCreateMana(), 2)); - victim->CastCustomSpell(victim, 20268, &basepoints0, nullptr, nullptr, true, 0, triggeredByAura); - victim->AddSpellCooldown(20268, 0, 4 * IN_MILLISECONDS); - return true; - } - // Holy Power (Redemption Armor set) - case 28789: - { - if (!victim) - return false; - - // Set class defined buff - switch (victim->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. - break; - case CLASS_WARRIOR: - triggered_spell_id = 28790; // Increases the friendly target's armor - break; - default: - return false; - } - break; - } - // Seal of Vengeance (damage calc on apply aura) - case 31801: - { - if (effIndex != 0 || !victim) // effect 1, 2 used by seal unleashing code - return false; - - // At melee attack or Hammer of the Righteous spell damage considered as melee attack - bool stacker = !procSpell || procSpell->Id == 53595; - // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements - bool damager = procSpell && (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)); - - if (!stacker && !damager) - return false; - - triggered_spell_id = 31803; - - // On target with 5 stacks of Holy Vengeance direct damage is done - if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) - { - if (aur->GetStackAmount() == 5) - { - if (stacker) - aur->RefreshDuration(); - - CastSpell(victim, 42463, true, castItem, triggeredByAura); - return true; - } - } - - if (!stacker) - return false; - break; - } - // Seal of Corruption - case 53736: - { - if (effIndex != 0 || !victim) // effect 1, 2 used by seal unleashing code - return false; - - // At melee attack or Hammer of the Righteous spell damage considered as melee attack - bool stacker = !procSpell || procSpell->Id == 53595; - // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements - bool damager = procSpell && (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)); - - if (!stacker && !damager) - return false; - - triggered_spell_id = 53742; - - // On target with 5 stacks of Blood Corruption direct damage is done - if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) - { - if (aur->GetStackAmount() == 5) - { - if (stacker) - aur->RefreshDuration(); - - CastSpell(victim, 53739, true, castItem, triggeredByAura); - return true; - } - } - - if (!stacker) - return false; - break; - } - // Spiritual Attunement - case 31785: - case 33776: - { - // if healed by another unit (victim) - if (this == victim) - return false; - - // dont allow non-positive dots to proc - if (!procSpell || !procSpell->IsPositive()) - return false; - - // heal amount - basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount)); - target = this; - - if (basepoints0) - triggered_spell_id = 31786; - break; - } - // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) - case 40470: - { - if (!procSpell) - return false; - - float chance = 0.0f; - - // Flash of light/Holy light - if (procSpell->SpellFamilyFlags[0] & 0xC0000000) - { - triggered_spell_id = 40471; - chance = 15.0f; - } - // Judgement (any) - else if (procSpell->SpellFamilyFlags[0] & 0x800000) - { - triggered_spell_id = 40472; - chance = 50.0f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - break; - } - // Glyph of Holy Light - case 54937: - { - triggered_spell_id = 54968; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } - // Item - Paladin T8 Holy 2P Bonus - case 64890: - { - triggered_spell_id = 64891; - basepoints0 = triggerAmount * damage / 300; - break; - } - case 71406: // Tiny Abomination in a Jar - case 71545: // Tiny Abomination in a Jar (Heroic) - { - if (!victim || !victim->IsAlive()) - return false; - - CastSpell(this, 71432, true, nullptr, triggeredByAura); - - Aura const* dummy = GetAura(71432); - if (!dummy || dummy->GetStackAmount() < (dummySpell->Id == 71406 ? 8 : 7)) - return false; - - RemoveAurasDueToSpell(71432); - triggered_spell_id = 71433; // default main hand attack - // roll if offhand - if (Player const* player = ToPlayer()) - if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) - triggered_spell_id = 71434; - target = victim; - break; - } - // Item - Icecrown 25 Normal Dagger Proc - case 71880: - { - switch (getPowerType()) - { - case POWER_MANA: - triggered_spell_id = 71881; - break; - case POWER_RAGE: - triggered_spell_id = 71883; - break; - case POWER_ENERGY: - triggered_spell_id = 71882; - break; - case POWER_RUNIC_POWER: - triggered_spell_id = 71884; - break; - default: - return false; - } - break; - } - // Item - Icecrown 25 Heroic Dagger Proc - case 71892: - { - switch (getPowerType()) - { - case POWER_MANA: - triggered_spell_id = 71888; - break; - case POWER_RAGE: - triggered_spell_id = 71886; - break; - case POWER_ENERGY: - triggered_spell_id = 71887; - break; - case POWER_RUNIC_POWER: - triggered_spell_id = 71885; - break; - default: - return false; - } - break; - } - } - break; - } - case SPELLFAMILY_SHAMAN: - { - switch (dummySpell->Id) - { - // Tidal Force - case 55198: - { - // Remove aura stack from caster - RemoveAuraFromStack(55166); - // drop charges - return false; - } - // Totemic Power (The Earthshatterer set) - case 28823: - { - if (!victim) - return false; - - // Set class defined buff - switch (victim->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. - break; - case CLASS_WARRIOR: - triggered_spell_id = 28827; // Increases the friendly target's armor - break; - default: - return false; - } - break; - } - // Lesser Healing Wave (Totem of Flowing Water Relic) - case 28849: - { - target = this; - triggered_spell_id = 28850; - break; - } - // Windfury Weapon (Passive) 1-8 Ranks - case 33757: - { - Player* player = ToPlayer(); - if (!player || !castItem || !castItem->IsEquipped() || !victim || !victim->IsAlive()) - return false; - - if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID()) - return false; - - WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); - if ((attType != BASE_ATTACK && attType != OFF_ATTACK) - || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) - return false; - - // Now amount of extra power stored in 1 effect of Enchant spell - // Get it by item enchant id - uint32 spellId; - switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) - { - case 283: - spellId = 8232; - break; // 1 Rank - case 284: - spellId = 8235; - break; // 2 Rank - case 525: - spellId = 10486; - break; // 3 Rank - case 1669: - spellId = 16362; - break; // 4 Rank - case 2636: - spellId = 25505; - break; // 5 Rank - case 3785: - spellId = 58801; - break; // 6 Rank - case 3786: - spellId = 58803; - break; // 7 Rank - case 3787: - spellId = 58804; - break; // 8 Rank - default: - { - LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled item enchantment (rank?) {} for spell id: {} (Windfury)", - castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id); - return false; - } - } - - SpellInfo const* windfurySpellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!windfurySpellInfo) - { - LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non-existing spell id: {} (Windfury)", spellId); - return false; - } - - int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellInfo, 1); - - // Value gained from additional AP - basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(attType) / 1000); - - if (procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) - triggered_spell_id = 25504; - - if (procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - triggered_spell_id = 33750; - - // custom cooldown processing case - if (player->HasSpellCooldown(dummySpell->Id)) - return false; - - // apply cooldown before cast to prevent processing itself - player->AddSpellCooldown(dummySpell->Id, 0, 3 * IN_MILLISECONDS); - - // Attack Twice - for (uint32 i = 0; i < 2; ++i) - CastCustomSpell(victim, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); - - return true; - } - // Shaman Tier 6 Trinket - case 40463: - { - if (!procSpell) - return false; - - float chance; - if (procSpell->SpellFamilyFlags[0] & 0x1) - { - triggered_spell_id = 40465; // Lightning Bolt - chance = 15.0f; - } - else if (procSpell->SpellFamilyFlags[0] & 0x80) - { - triggered_spell_id = 40465; // Lesser Healing Wave - chance = 10.0f; - } - else if (procSpell->SpellFamilyFlags[1] & 0x00000010) - { - triggered_spell_id = 40466; // Stormstrike - chance = 50.0f; - } - else - return false; - - if (!roll_chance_f(chance)) - return false; - - target = this; - break; - } - // Glyph of Healing Wave - case 55440: - { - // Not proc from self heals - if (this == victim) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - triggered_spell_id = 55533; - break; - } - // Spirit Hunt - case 58877: - { - // Cast on owner - target = GetOwner(); - if (!target) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 58879; - // Heal wolf - CastCustomSpell(this, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); - break; - } - // Shaman T8 Elemental 4P Bonus - case 64928: - { - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 64930; // Electrified - break; - } - // Shaman T9 Elemental 4P Bonus - case 67228: - { - // Lava Burst - if (procSpell->SpellFamilyFlags[1] & 0x1000) - { - triggered_spell_id = 71824; - SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!triggeredSpell) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].Amplitude); - } - break; - } - // Item - Shaman T10 Elemental 4P Bonus - case 70817: - { - if (!target) - return false; - // try to find spell Flame Shock on the target - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID())) - { - Aura* flameShock = aurEff->GetBase(); - int32 extraTime = 2 * aurEff->GetAmplitude(); - flameShock->SetMaxDuration(flameShock->GetMaxDuration() + extraTime); - flameShock->SetDuration(flameShock->GetDuration() + extraTime); - - return true; - } - // if not found Flame Shock - return false; - } - break; - } - // Frozen Power - if (dummySpell->SpellIconID == 3780) - { - if (!target) - return false; - if (GetDistance(target) < 15.0f) - return false; - float chance = (float)triggerAmount; - if (!roll_chance_f(chance)) - return false; - - triggered_spell_id = 63685; - break; - } - // Ancestral Awakening - if (dummySpell->SpellIconID == 3065) - { - triggered_spell_id = 52759; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - target = this; - break; - } - // Flametongue Weapon (Passive) - if (dummySpell->SpellFamilyFlags[0] & 0x200000) - { - if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->IsAlive() || !castItem || !castItem->IsEquipped()) - return false; - - WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot())); - if ((attType != BASE_ATTACK && attType != OFF_ATTACK) - || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) - return false; - - float fire_onhit = float(CalculatePct(dummySpell->Effects[EFFECT_0]. CalcValue(), 1.0f)); - - float add_spellpower = (float)(SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) - + victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); - - // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84% - ApplyPct(add_spellpower, 3.84f); - - // Enchant on Off-Hand and ready? - if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) - { - float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f; - - // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); - triggered_spell_id = 10444; - } - - // Enchant on Main-Hand and ready? - else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) - { - float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f; - - // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); - triggered_spell_id = 10444; - } - - // If not ready, we should return, shouldn't we?! - else - return false; - - CastCustomSpell(victim, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); - return true; - } - // Improved Water Shield - if (dummySpell->SpellIconID == 2287) - { - if (!procSpell) - return false; - - // Default chance for Healing Wave and Riptide - float chance = (float)triggeredByAura->GetAmount(); - - if (procSpell->SpellFamilyFlags[0] & 0x80) - // Lesser Healing Wave - 0.6 of default - chance *= 0.6f; - else if (procSpell->SpellFamilyFlags[0] & 0x100) - // Chain heal - 0.3 of default - chance *= 0.3f; - - if (!roll_chance_f(chance)) - return false; - - // Water Shield - if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0)) - { - uint32 spell = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - CastSpell(this, spell, true, castItem, triggeredByAura); - return true; - } - return false; - } - // Lightning Overload - if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura - { - if(!procSpell || GetTypeId() != TYPEID_PLAYER || !victim) - return false; - - if (procEx & PROC_EX_CRITICAL_HIT) - damage /= 2; - - do - { - uint32 spell = 0; - - if (procSpell->SpellFamilyFlags[0] & 0x2) - { - // 1/3 of 33% if 11% - if (!roll_chance_i(33)) - return false; - - spell = 45297; - } - else - spell = 45284; - - // do not reduce damage-spells have correct basepoints - damage /= 2; - int32 dmg = damage; - - // Cast - CastCustomSpell(victim, spell, &dmg, 0, 0, true, castItem, triggeredByAura); - } while (roll_chance_i(33)); - return true; - } - // Static Shock - if (dummySpell->SpellIconID == 3059) - { - // Lightning Shield - if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0)) - { - uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank()); - CastSpell(target, spell, true, castItem, triggeredByAura); - aurEff->GetBase()->DropCharge(); - return true; - } - return false; - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Improved Blood Presence - if (dummySpell->SpellIconID == 2636) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } - // Butchery - if (dummySpell->SpellIconID == 2664) - { - basepoints0 = triggerAmount; - triggered_spell_id = 50163; - target = this; - break; - } - // Mark of Blood - if (dummySpell->Id == 49005) - { - // TODO: need more info (cooldowns/PPM) - triggered_spell_id = 61607; - break; - } - // Unholy Blight - if (dummySpell->Id == 49194) - { - triggered_spell_id = 50536; - SpellInfo const* unholyBlight = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!unholyBlight || !victim) - return false; - - basepoints0 = CalculatePct(int32(damage), triggerAmount); - - //Glyph of Unholy Blight - if (AuraEffect* glyph = GetAuraEffect(63332, 0)) - AddPct(basepoints0, glyph->GetAmount()); - - basepoints0 = basepoints0 / (unholyBlight->GetMaxDuration() / unholyBlight->Effects[0].Amplitude); - victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); - return true; - } - // Vendetta - if (dummySpell->SpellFamilyFlags[0] & 0x10000) - { - basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); - triggered_spell_id = 50181; - target = this; - break; - } - // Necrosis - if (dummySpell->SpellIconID == 2709) - { - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 51460; - break; - } - // Threat of Thassarian - if (dummySpell->SpellIconID == 2023) - { - // Must Dual Wield - if (!procSpell || !haveOffhandWeapon()) - return false; - // Chance as basepoints for dummy aura - if (!roll_chance_i(triggerAmount)) - return false; - - switch (procSpell->Id) - { - // Obliterate - case 49020: - triggered_spell_id = 66198; - break; // Rank 1 - case 51423: - triggered_spell_id = 66972; - break; // Rank 2 - case 51424: - triggered_spell_id = 66973; - break; // Rank 3 - case 51425: - triggered_spell_id = 66974; - break; // Rank 4 - - // Frost Strike - case 49143: - triggered_spell_id = 66196; - break; // Rank 1 - case 51416: - triggered_spell_id = 66958; - break; // Rank 2 - case 51417: - triggered_spell_id = 66959; - break; // Rank 3 - case 51418: - triggered_spell_id = 66960; - break; // Rank 4 - case 51419: - triggered_spell_id = 66961; - break; // Rank 5 - case 55268: - triggered_spell_id = 66962; - break; // Rank 6 - - // Plague Strike - case 45462: - triggered_spell_id = 66216; - break; // Rank 1 - case 49917: - triggered_spell_id = 66988; - break; // Rank 2 - case 49918: - triggered_spell_id = 66989; - break; // Rank 3 - case 49919: - triggered_spell_id = 66990; - break; // Rank 4 - case 49920: - triggered_spell_id = 66991; - break; // Rank 5 - case 49921: - triggered_spell_id = 66992; - break; // Rank 6 - - // Death Strike - case 49998: - triggered_spell_id = 66188; - break; // Rank 1 - case 49999: - triggered_spell_id = 66950; - break; // Rank 2 - case 45463: - triggered_spell_id = 66951; - break; // Rank 3 - case 49923: - triggered_spell_id = 66952; - break; // Rank 4 - case 49924: - triggered_spell_id = 66953; - break; // Rank 5 - - // Rune Strike - case 56815: - triggered_spell_id = 66217; - break; // Rank 1 - - // Blood Strike - case 45902: - triggered_spell_id = 66215; - break; // Rank 1 - case 49926: - triggered_spell_id = 66975; - break; // Rank 2 - case 49927: - triggered_spell_id = 66976; - break; // Rank 3 - case 49928: - triggered_spell_id = 66977; - break; // Rank 4 - case 49929: - triggered_spell_id = 66978; - break; // Rank 5 - case 49930: - triggered_spell_id = 66979; - break; // Rank 6 - default: - return false; - } - - // This should do, restore spell mod so next attack can also use this! - // crit chance for first strike is already computed - ToPlayer()->RestoreSpellMods(m_currentSpells[CURRENT_GENERIC_SPELL], 51124, nullptr); // Killing Machine - ToPlayer()->RestoreSpellMods(m_currentSpells[CURRENT_GENERIC_SPELL], 49796, nullptr); // Deathchill - - // Xinef: Somehow basepoints are divided by 2 which is later divided by 2 (offhand multiplier) - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (triggerEntry->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) - basepoints0 = triggerEntry->Effects[EFFECT_0].BasePoints * 2; - - SetCantProc(true); - if(basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); - SetCantProc(false); - return true; - } - // Runic Power Back on Snare/Root - if (dummySpell->Id == 61257) - { - // only for spells and hit/crit (trigger start always) and not start from self casted spells - if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) - return false; - // Need snare or root mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE)))) - return false; - triggered_spell_id = 61258; - target = this; - break; - } - // Sudden Doom - if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER) - { - SpellChainNode const* chain = nullptr; - // get highest rank of the Death Coil spell - PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - // check if shown in spell book - if (!itr->second->Active || !itr->second->IsInSpec(ToPlayer()->GetActiveSpec()) || itr->second->State == PLAYERSPELL_REMOVED) - continue; - - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(itr->first); - if (!spellProto) - continue; - - if (spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT - && spellProto->SpellFamilyFlags[0] & 0x2000) - { - SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first); - - // No chain entry or entry lower than found entry - if (!chain || !newChain || (chain->rank < newChain->rank)) - { - triggered_spell_id = itr->first; - chain = newChain; - } - else - continue; - // Found spell is last in chain - do not need to look more - // Optimisation for most common case - if (chain && chain->last->Id == itr->first) - break; - } - } - } - break; - } - case SPELLFAMILY_POTION: - { - // alchemist's stone - if (dummySpell->Id == 17619) - { - if (procSpell->SpellFamilyName == SPELLFAMILY_POTION) - { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (procSpell->Effects[i].Effect == SPELL_EFFECT_HEAL) - { - triggered_spell_id = 21399; - } - else if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) - { - triggered_spell_id = 21400; - } - else - continue; - - basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f); - CastCustomSpell(this, triggered_spell_id, &basepoints0, nullptr, nullptr, true, nullptr, triggeredByAura); - } - return true; - } - } - break; - } - case SPELLFAMILY_PET: - { - switch (dummySpell->SpellIconID) - { - // Guard Dog - case 201: - { - if (!victim) - return false; - - triggered_spell_id = 54445; - target = this; - float addThreat = float(CalculatePct(procSpell->Effects[0].CalcValue(this), triggerAmount)); - victim->AddThreat(this, addThreat); - break; - } - // Silverback - case 1582: - triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800; - target = this; - break; - } - break; - } - default: - break; - } - - // if not handled by custom case, get triggered spell from dummySpell proto - if (!triggered_spell_id) - triggered_spell_id = dummySpell->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; - - // processed charge only counting case - if (!triggered_spell_id) - return true; - - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!triggerEntry) - { - LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: Spell {} has non-existing triggered spell {}", dummySpell->Id, triggered_spell_id); - return false; - } - - if (cooldown_spell_id == 0) - cooldown_spell_id = triggered_spell_id; - - if (cooldown) - { - if (HasSpellCooldown(cooldown_spell_id)) - return false; - - AddSpellCooldown(cooldown_spell_id, 0, cooldown); - } - - if(basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); - - return true; -} - -// Used in case when access to whole aura is needed -// All procs should be handled like this... -bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool* handled) -{ - SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); - - switch (dummySpell->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - switch (dummySpell->Id) - { - // Nevermelting Ice Crystal - case 71564: - RemoveAuraFromStack(71564); - *handled = true; - break; - // Gaseous Bloat - case 70672: - case 72455: - case 72832: - case 72833: - { - if (Unit* caster = triggeredByAura->GetCaster()) - if (victim && caster->GetGUID() == victim->GetGUID()) - { - *handled = true; - uint32 stack = triggeredByAura->GetStackAmount(); - int32 const mod = (GetMap()->GetSpawnMode() & 1) ? 1500 : 1250; - int32 dmg = 0; - for (uint8 i = 1; i <= stack; ++i) - dmg += mod * i; - caster->CastCustomSpell(70701, SPELLVALUE_BASE_POINT0, dmg); - } - break; - } - // Ball of Flames Proc - case 71756: - case 72782: - case 72783: - case 72784: - RemoveAuraFromStack(dummySpell->Id); - *handled = true; - break; - // Discerning Eye of the Beast - case 59915: - { - CastSpell(this, 59914, true); // 59914 already has correct basepoints in DBC, no need for custom bp - *handled = true; - break; - } - // Swift Hand of Justice - case 59906: - { - int32 bp0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_0]. CalcValue()); - CastCustomSpell(this, 59913, &bp0, nullptr, nullptr, true); - *handled = true; - break; - } - } - - break; - case SPELLFAMILY_MAGE: - { - // Combustion - switch (dummySpell->Id) - { - case 11129: - { - *handled = true; - Unit* caster = triggeredByAura->GetCaster(); - if (!caster || !damage) - return false; - - // last charge and crit - if (triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT)) - return true; // charge counting (will removed) - - CastSpell(this, 28682, true); - - return procEx & PROC_EX_CRITICAL_HIT; - } - // Empowered Fire - case 31656: - case 31657: - case 31658: - { - *handled = true; - - SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(67545); - if (!spInfo) - return false; - - int32 bp0 = int32(CalculatePct(GetMaxPower(POWER_MANA), spInfo->Effects[0].CalcValue())); - CastCustomSpell(this, 67545, &bp0, nullptr, nullptr, true, nullptr, triggeredByAura->GetEffect(EFFECT_0), GetGUID()); - return true; - } - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Blood of the North - // Reaping - // Death Rune Mastery - // xinef: Icon 22 is used for item bonus, skip - if (dummySpell->SpellIconID == 3041 || (dummySpell->SpellIconID == 22 && dummySpell->Id != 62459) || dummySpell->SpellIconID == 2622) - { - *handled = true; - // Convert recently used Blood Rune to Death Rune - if (Player* player = ToPlayer()) - { - if (player->getClass() != CLASS_DEATH_KNIGHT) - return false; - - // xinef: not true - //RuneType rune = ToPlayer()->GetLastUsedRune(); - // can't proc from death rune use - //if (rune == RUNE_DEATH) - // return false; - AuraEffect* aurEff = triggeredByAura->GetEffect(EFFECT_0); - if (!aurEff) - return false; - - // Reset amplitude - set death rune remove timer to 30s - aurEff->ResetPeriodic(true); - uint32 runesLeft; - - if (dummySpell->SpellIconID == 2622) - runesLeft = 2; - else - runesLeft = 1; - - for (uint8 i = 0; i < MAX_RUNES && runesLeft; ++i) - { - if (dummySpell->SpellIconID == 2622) - { - if (player->GetCurrentRune(i) == RUNE_DEATH || - player->GetBaseRune(i) == RUNE_BLOOD) - continue; - } - else - { - if (player->GetCurrentRune(i) == RUNE_DEATH || - player->GetBaseRune(i) != RUNE_BLOOD) - continue; - } - if (player->GetRuneCooldown(i) != player->GetRuneBaseCooldown(i, false)) - continue; - - --runesLeft; - // Mark aura as used - player->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff); - } - return true; - } - return false; - } - break; - } - case SPELLFAMILY_WARRIOR: - { - switch (dummySpell->Id) - { - // Item - Warrior T10 Protection 4P Bonus - case 70844: - { - int32 basepoints0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_1]. CalcValue()); - CastCustomSpell(this, 70845, &basepoints0, nullptr, nullptr, true); - break; - } - default: - break; - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Flurry - if ((dummySpell->SpellFamilyFlags[1] & 0x00000200) != 0) - { - if (cooldown) - { - if (HasSpellCooldown(dummySpell->Id)) - { - *handled = true; - break; - } - - AddSpellCooldown(dummySpell->Id, 0, cooldown); - } - } - break; - } - } - return false; -} - -bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo) -{ - // Get triggered aura spell info - SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo(); - - // Basepoints of trigger aura - int32 triggerAmount = triggeredByAura->GetAmount(); - - // Set trigger spell id, target, custom basepoints - uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; - - Unit* target = nullptr; - int32 basepoints0 = 0; - - if (triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE) - basepoints0 = triggerAmount; - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; - - // Try handle unknown trigger spells - //if (sSpellMgr->GetSpellInfo(trigger_spell_id) == nullptr) - { - switch (auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - switch (auraSpellInfo->Id) - { - case 43820: // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket) - // Pct value stored in dummy - if (!victim) - return false; - basepoints0 = victim->GetCreateHealth() * auraSpellInfo->Effects[1].CalcValue() / 100; - target = victim; - break; - case 57345: // Darkmoon Card: Greatness - { - float stat = 0.0f; - // strength - if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229; stat = GetStat(STAT_STRENGTH); } - // agility - if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233; stat = GetStat(STAT_AGILITY); } - // intellect - if (GetStat(STAT_INTELLECT) > stat) { trigger_spell_id = 60234; stat = GetStat(STAT_INTELLECT);} - // spirit - if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235; } - break; - } - case 67702: // Death's Choice, Item - Coliseum 25 Normal Melee Trinket - { - if (!damage) - return false; - float stat = 0.0f; - // strength - if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67708; stat = GetStat(STAT_STRENGTH); } - // agility - if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67703; } - break; - } - case 67771: // Death's Choice (heroic), Item - Coliseum 25 Heroic Melee Trinket - { - if (!damage) - return false; - float stat = 0.0f; - // strength - if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67773; stat = GetStat(STAT_STRENGTH); } - // agility - if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67772; } - break; - } - // Mana Drain Trigger - case 27522: - case 40336: - { - // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target. - if (IsAlive()) - CastSpell(this, 29471, true, castItem, triggeredByAura); - if (victim && victim->IsAlive()) - CastSpell(victim, 27526, true, castItem, triggeredByAura); - return true; - } - // Forge of Souls, Devourer of Souls, Mirrored Soul - case 69023: - { - int32 dmg = damage * 0.45f; - if (dmg > 0) - if (Aura* a = GetAura(69023)) - if (Unit* c = a->GetCaster()) - CastCustomSpell(c, 69034, &dmg, 0, 0, true); - return true; - } - // Soul-Trader Beacon proc aura - case 50051: - { - if (!victim) - return false; - - if (Creature* cr = ObjectAccessor::GetCreature(*this, m_SummonSlot[SUMMON_SLOT_MINIPET])) - cr->CastSpell(victim, 50101, true); - - return false; - } - } - break; - case SPELLFAMILY_MAGE: - if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed - { - switch (auraSpellInfo->Id) - { - case 31641: // Rank 1 - case 31642: // Rank 2 - trigger_spell_id = 31643; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} miss posibly Blazing Speed", auraSpellInfo->Id); - return false; - } - } - else if (auraSpellInfo->Id == 71761) // Deep Freeze Immunity State (only permanent) - { - Creature* creature = victim->ToCreature(); - if (!creature || !creature->HasMechanicTemplateImmunity(1 << (MECHANIC_STUN - 1))) - return false; - } - break; - case SPELLFAMILY_WARLOCK: - { - // Nether Protection - if (auraSpellInfo->SpellIconID == 1985) - { - if (!procSpell) - return false; - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: - trigger_spell_id = 54370; - break; - case SPELL_SCHOOL_FIRE: - trigger_spell_id = 54371; - break; - case SPELL_SCHOOL_NATURE: - trigger_spell_id = 54375; - break; - case SPELL_SCHOOL_FROST: - trigger_spell_id = 54372; - break; - case SPELL_SCHOOL_SHADOW: - trigger_spell_id = 54374; - break; - case SPELL_SCHOOL_ARCANE: - trigger_spell_id = 54373; - break; - default: - return false; - } - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Blessed Recovery - if (auraSpellInfo->SpellIconID == 1875) - { - switch (auraSpellInfo->Id) - { - case 27811: - trigger_spell_id = 27813; - break; - case 27815: - trigger_spell_id = 27817; - break; - case 27816: - trigger_spell_id = 27818; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} not handled in BR", auraSpellInfo->Id); - return false; - } - basepoints0 = CalculatePct(int32(damage), triggerAmount) / 3; - target = this; - // Add remaining ticks to healing done - CastDelayedSpellWithPeriodicAmount(this, trigger_spell_id, SPELL_AURA_PERIODIC_HEAL, basepoints0); - return true; - } - break; - } - case SPELLFAMILY_DRUID: - { - switch (auraSpellInfo->Id) - { - // Druid Forms Trinket - case 37336: - { - switch (GetShapeshiftForm()) - { - case FORM_NONE: - trigger_spell_id = 37344; - break; - case FORM_CAT: - trigger_spell_id = 37341; - break; - case FORM_BEAR: - case FORM_DIREBEAR: - trigger_spell_id = 37340; - break; - case FORM_TREE: - trigger_spell_id = 37342; - break; - case FORM_MOONKIN: - trigger_spell_id = 37343; - break; - default: - return false; - } - break; - } - // Druid T9 Feral Relic (Lacerate, Swipe, Mangle, and Shred) - case 67353: - { - switch (GetShapeshiftForm()) - { - case FORM_CAT: - trigger_spell_id = 67355; - break; - case FORM_BEAR: - case FORM_DIREBEAR: - trigger_spell_id = 67354; - break; - default: - return false; - } - break; - } - default: - break; - } - break; - } - case SPELLFAMILY_HUNTER: - { - if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots - { - if (!victim) - return false; - - switch (auraSpellInfo->Id) - { - case 53234: // Rank 1 - case 53237: // Rank 2 - case 53238: // Rank 3 - trigger_spell_id = 63468; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} miss posibly Piercing Shots", auraSpellInfo->Id); - return false; - } - SpellInfo const* TriggerPS = sSpellMgr->GetSpellInfo(trigger_spell_id); - if (!TriggerPS) - return false; - - basepoints0 = CalculatePct(int32(damage), triggerAmount) / (TriggerPS->GetMaxDuration() / TriggerPS->Effects[0].Amplitude); - victim->CastDelayedSpellWithPeriodicAmount(this, trigger_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); - return true; - } - // Item - Hunter T9 4P Bonus (Steady Shot) - else if (auraSpellInfo->Id == 67151) - { - if (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetPet()) - return false; - - target = ToPlayer()->GetPet(); - trigger_spell_id = 68130; - break; - } - break; - } - case SPELLFAMILY_PALADIN: - { - switch (auraSpellInfo->Id) - { - // Soul Preserver - case 60510: - { - switch (getClass()) - { - case CLASS_DRUID: - trigger_spell_id = 60512; - break; - case CLASS_PALADIN: - trigger_spell_id = 60513; - break; - case CLASS_PRIEST: - trigger_spell_id = 60514; - break; - case CLASS_SHAMAN: - trigger_spell_id = 60515; - break; - } - - target = this; - break; - } - case 37657: // Lightning Capacitor - case 54841: // Thunder Capacitor - case 67712: // Item - Coliseum 25 Normal Caster Trinket - case 67758: // Item - Coliseum 25 Heroic Caster Trinket - { - if (!victim || !victim->IsAlive() || GetTypeId() != TYPEID_PLAYER) - return false; - - uint32 stack_spell_id = 0; - switch (auraSpellInfo->Id) - { - case 37657: - stack_spell_id = 37658; - trigger_spell_id = 37661; - break; - case 54841: - stack_spell_id = 54842; - trigger_spell_id = 54843; - break; - case 67712: - stack_spell_id = 67713; - trigger_spell_id = 67714; - break; - case 67758: - stack_spell_id = 67759; - trigger_spell_id = 67760; - break; - } - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - { - if (ToPlayer()->HasSpellCooldown(stack_spell_id)) - return false; - - ToPlayer()->AddSpellCooldown(stack_spell_id, 0, cooldown); - } - - CastSpell(this, stack_spell_id, true, nullptr, triggeredByAura); - - Aura* dummy = GetAura(stack_spell_id); - if (!dummy || dummy->GetStackAmount() < triggerAmount) - return false; - - RemoveAurasDueToSpell(stack_spell_id); - CastSpell(victim, trigger_spell_id, true, nullptr, triggeredByAura); - return true; - } - default: - // Illumination - if (auraSpellInfo->SpellIconID == 241) - { - if (!procSpell) - return false; - // procspell is triggered spell but we need mana cost of original casted spell - uint32 originalSpellId = procSpell->Id; - // Holy Shock heal - if (procSpell->SpellFamilyFlags[1] & 0x00010000) - { - switch (procSpell->Id) - { - case 25914: - originalSpellId = 20473; - break; - case 25913: - originalSpellId = 20929; - break; - case 25903: - originalSpellId = 20930; - break; - case 27175: - originalSpellId = 27174; - break; - case 33074: - originalSpellId = 33072; - break; - case 48820: - originalSpellId = 48824; - break; - case 48821: - originalSpellId = 48825; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} not handled in HShock", procSpell->Id); - return false; - } - } - SpellInfo const* originalSpell = sSpellMgr->GetSpellInfo(originalSpellId); - if (!originalSpell) - { - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} unknown but selected as original in Illu", originalSpellId); - return false; - } - // percent stored in effect 1 (class scripts) base points - int32 cost = int32(originalSpell->ManaCost + CalculatePct(GetCreateMana(), originalSpell->ManaCostPercentage)); - basepoints0 = CalculatePct(cost, auraSpellInfo->Effects[1].CalcValue()); - trigger_spell_id = 20272; - target = this; - } - break; - } - break; - } - case SPELLFAMILY_SHAMAN: - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc - if (auraSpellInfo->SpellFamilyFlags[0] & 0x400) - { - // Do not proc off from self-casted items - if (Spell const* spell = eventInfo.GetProcSpell()) - { - if (spell->m_castItemGUID && victim->GetGUID() == GetGUID()) - { - return false; - } - } - - trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, auraSpellInfo->GetRank()); - } - // Nature's Guardian - else if (auraSpellInfo->SpellIconID == 2013) - { - // Check health condition - should drop to less 30% (damage deal after this!) - if (!HealthBelowPctDamaged(30, damage)) - return false; - - if (victim && victim->IsAlive()) - victim->GetThreatMgr().ModifyThreatByPercent(this, -10); - - basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); - trigger_spell_id = 31616; - target = this; - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - // Acclimation - if (auraSpellInfo->SpellIconID == 1930) - { - if (!procSpell) - return false; - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: - trigger_spell_id = 50490; - break; - case SPELL_SCHOOL_FIRE: - trigger_spell_id = 50362; - break; - case SPELL_SCHOOL_NATURE: - trigger_spell_id = 50488; - break; - case SPELL_SCHOOL_FROST: - trigger_spell_id = 50485; - break; - case SPELL_SCHOOL_SHADOW: - trigger_spell_id = 50489; - break; - case SPELL_SCHOOL_ARCANE: - trigger_spell_id = 50486; - break; - default: - return false; - } - } - // Blood Presence (Improved) - else if (auraSpellInfo->Id == 63611) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - trigger_spell_id = 50475; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - } - break; - } - } - } - - // All ok. Check current trigger spell - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id); - if (!triggerEntry) - { - // Don't cast unknown spell - LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} (effIndex: {}) has unknown TriggerSpell {}. Unhandled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex(), trigger_spell_id); - return false; - } - - // not allow proc extra attack spell at extra attack - if (triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - { - uint32 lastExtraAttackSpell = eventInfo.GetActor()->GetLastExtraAttackSpell(); - - // Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves - if (lastExtraAttackSpell == trigger_spell_id) - { - return false; - } - - // Patch 2.2.0 Sword Specialization (Warrior, Rogue) extra attack can no longer proc additional extra attacks - // 3.3.5 Sword Specialization (Warrior), Hack and Slash (Rogue) - if (lastExtraAttackSpell == 16459 || lastExtraAttackSpell == 66923) - { - return false; - } - } - - // Custom requirements (not listed in procEx) Warning! damage dealing after this - // Custom triggered spells - switch (auraSpellInfo->Id) - { - // Deep Wounds - case 12834: - case 12849: - case 12867: - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - if (procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK) - basepoints0 = int32((GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE)) / 2.0f); - else - basepoints0 = int32((GetFloatValue(UNIT_FIELD_MAXDAMAGE) + GetFloatValue(UNIT_FIELD_MINDAMAGE)) / 2.0f); - break; - } - // Persistent Shield (Scarab Brooch trinket) - // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect) - case 26467: - { - basepoints0 = int32(CalculatePct(damage, 15)); - target = victim; - trigger_spell_id = 26470; - break; - } - // Unyielding Knights (item exploit 29108\29109) - case 38164: - { - if (!victim || victim->GetEntry() != 19457) // Proc only if your target is Grillok - return false; - break; - } - // Deflection - case 52420: - { - if (!HealthBelowPct(35)) - return false; - break; - } - - // Cheat Death - case 28845: - { - // When your health drops below 20% - if (HealthBelowPctDamaged(20, damage) || HealthBelowPct(20)) - return false; - break; - } - // Deadly Swiftness (Rank 1) - case 31255: - { - // whenever you deal damage to a target who is below 20% health. - if (!victim || !victim->IsAlive() || victim->HealthAbovePct(20)) - return false; - - target = this; - trigger_spell_id = 22588; - [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. - } - // Bonus Healing (Crystal Spire of Karabor mace) - case 40971: - { - // If your target is below $s1% health - if (!victim || !victim->IsAlive() || victim->HealthAbovePct(triggerAmount)) - return false; - break; - } - // Rapid Recuperation - case 53228: - case 53232: - { - // This effect only from Rapid Fire (ability cast) - if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x20)) - return false; - break; - } - // Decimation - case 63156: - case 63158: - // Can proc only if target has hp below 35% - if (!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this)) - return false; - break; - // Ulduar, Hodir, Toasty Fire - case 62821: - if (this->GetTypeId() != TYPEID_PLAYER) // spell has Attribute, but persistent area auras ignore it - return false; - break; - case 15337: // Improved Spirit Tap (Rank 1) - case 15338: // Improved Spirit Tap (Rank 2) - { - if (!procSpell) - return false; - - if (procSpell->SpellFamilyFlags[0] & 0x800000) - if ((procSpell->Id != 58381) || !roll_chance_i(50)) - return false; - - target = victim; - break; - } - // Professor Putricide - Ooze Spell Tank Protection - case 71770: - if (victim) - victim->CastSpell(victim, trigger_spell_id, true); // EffectImplicitTarget is self - return true; - case 45057: // Evasive Maneuvers (Commendation of Kael`thas trinket) - case 71634: // Item - Icecrown 25 Normal Tank Trinket 1 - case 71640: // Item - Icecrown 25 Heroic Tank Trinket 1 - case 75475: // Item - Chamber of Aspects 25 Normal Tank Trinket - case 75481: // Item - Chamber of Aspects 25 Heroic Tank Trinket - { - // Procs only if damage takes health below $s1% - if (!HealthBelowPctDamaged(triggerAmount, damage)) - return false; - break; - } - default: - break; - } - - if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT) - { - // Xinef: keep this order, Aura 70656 has SpellIconID 85! - // Item - Death Knight T10 Melee 4P Bonus - if (auraSpellInfo->Id == 70656) - { - if (GetTypeId() != TYPEID_PLAYER || getClass() != CLASS_DEATH_KNIGHT) - return false; - - for (uint8 i = 0; i < MAX_RUNES; ++i) - if (ToPlayer()->GetRuneCooldown(i) == 0) - return false; - } - // Blade Barrier - else if (auraSpellInfo->SpellIconID == 85) - { - Player* plr = ToPlayer(); - if (!plr || plr->getClass() != CLASS_DEATH_KNIGHT || !procSpell) - return false; - - if (!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) - return false; - } - // Rime - else if (auraSpellInfo->SpellIconID == 56) - { - if (GetTypeId() != TYPEID_PLAYER) - return false; - - // Howling Blast - ToPlayer()->RemoveCategoryCooldown(1248); - } - } - - // Custom basepoints/target for exist spell - // dummy basepoints or other customs - switch (trigger_spell_id) - { - // Auras which should proc on area aura source (caster in this case): - // Turn the Tables - case 52914: - case 52915: - case 52910: - // Honor Among Thieves - case 51699: - { - target = triggeredByAura->GetBase()->GetCaster(); - if (!target) - return false; - - if (Player* pTarget = target->ToPlayer()) - { - if (cooldown) - { - if (pTarget->HasSpellCooldown(trigger_spell_id) ) - return false; - pTarget->AddSpellCooldown(trigger_spell_id, 0, cooldown); - } - - Unit* cptarget = nullptr; - if (trigger_spell_id == 51699) - { - cptarget = pTarget->GetComboTarget(); - if (!cptarget) - { - cptarget = pTarget->GetSelectedUnit(); - } - } - else - cptarget = target; - - if (cptarget) - { - target->CastSpell(cptarget, trigger_spell_id, true); - return true; - } - } - return false; - } - // Cast positive spell on enemy target - case 7099: // Curse of Mending - case 39703: // Curse of Mending - case 29494: // Temptation - case 20233: // Improved Lay on Hands (cast on target) - { - target = victim; - break; - } - // Ruby Drake, Evasive Aura - case 50241: - { - if( GetAura(50240) ) - return false; - - break; - } - // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset) - case 15250: // Rogue Setup - { - // applied only for main target - if (!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit())) - return false; - break; // continue normal case - } - // Finish movies that add combo - case 14189: // Seal Fate (Netherblade set) - case 14157: // Ruthlessness - { - victim = nullptr; - // Need add combopoint AFTER finish movie (or they dropped in finish phase) - break; - } - // Item - Druid T10 Balance 2P Bonus - case 16870: - { - if (HasAura(70718)) - CastSpell(this, 70721, true); - RemoveAurasDueToSpell(trigger_spell_id); - break; - } - // Shamanistic Rage triggered spell - case 30824: - { - basepoints0 = int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount)); - break; - } - // Enlightenment (trigger only from mana cost spells) - case 35095: - { - if (!procSpell || procSpell->PowerType != POWER_MANA || (procSpell->ManaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->ManaCostPerlevel == 0)) - return false; - break; - } - // Demonic Pact - case 48090: - { - // Get talent aura from owner - if (IsPet()) - if (Unit* owner = GetOwner()) - { - if (HasSpellCooldown(trigger_spell_id)) - return false; - AddSpellCooldown(trigger_spell_id, 0, cooldown); - - if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0)) - { - int32 spellPower = owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)); - if (AuraEffect const* demonicAuraEffect = GetAuraEffect(trigger_spell_id, EFFECT_0)) - spellPower -= demonicAuraEffect->GetAmount(); - - basepoints0 = int32((aurEff->GetAmount() * spellPower + 100.0f) / 100.0f); - CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, nullptr, true, castItem, triggeredByAura); - return true; - } - } - break; - } - case 46916: // Slam! (Bloodsurge proc) - case 52437: // Sudden Death - { - // Item - Warrior T10 Melee 4P Bonus - if (AuraEffect const* aurEff = GetAuraEffect(70847, 0)) - { - if (!roll_chance_i(aurEff->GetAmount())) - { - // Xinef: dont allow normal proc to override set one - if (GetAura((trigger_spell_id == 46916) ? 71072 : 71069)) - return false; - // Xinef: just to be sure - RemoveAurasDueToSpell(70849); - break; - } - - // Xinef: fully remove all auras and reapply once more - RemoveAurasDueToSpell(70849); - RemoveAurasDueToSpell(71072); - RemoveAurasDueToSpell(71069); - - CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge! - if (trigger_spell_id == 46916) - CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced - else - CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced - } - break; - } - // Sword and Board - case 50227: - { - // Remove cooldown on Shield Slam - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveCategoryCooldown(1209); - break; - } - // Maelstrom Weapon - case 53817: - { - // have rank dependent proc chance, ignore too often cases - // PPM = 2.5 * (rank of talent), - uint32 rank = auraSpellInfo->GetRank(); - // 5 rank -> 100% 4 rank -> 80% and etc from full rate - if (!roll_chance_i(20 * rank)) - return false; - - // Item - Shaman T10 Enhancement 4P Bonus - if (AuraEffect const* aurEff = GetAuraEffect(70832, 0)) - if (Aura const* maelstrom = GetAura(53817)) - // xinef: we have 4 charges and all proc conditions are met - aura reaches 5 charges - if ((maelstrom->GetStackAmount() == 4) && roll_chance_i(aurEff->GetAmount())) - CastSpell(this, 70831, true, castItem, triggeredByAura); - - break; - } - // Astral Shift - case 52179: - { - if (!procSpell || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) - return false; - - // Need stun, fear or silence mechanic - if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR)))) - return false; - break; - } - // Glyph of Death's Embrace - case 58679: - { - // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags - if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000)) - return false; - break; - } - // Glyph of Death Grip - case 58628: - { - // remove cooldown of Death Grip - if (GetTypeId() == TYPEID_PLAYER) - ToPlayer()->RemoveSpellCooldown(49576, true); - return true; - } - // Savage Defense - case 62606: - { - basepoints0 = CalculatePct(triggerAmount, GetTotalAttackPowerValue(BASE_ATTACK)); - break; - } - // Body and Soul - case 64128: - case 65081: - { - // Proc only from PW:S cast - if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x00000001)) - return false; - break; - } - // Culling the Herd - case 70893: - { - if (!procSpell) - { - return false; - } - // check if we're doing a critical hit - if (!(procSpell->SpellFamilyFlags[1] & 0x10000000) && (procEx != PROC_EX_CRITICAL_HIT)) - return false; - // check if we're procced by Claw, Bite or Smack (need to use the spell icon ID to detect it) - if (!(procSpell->SpellIconID == 262 || procSpell->SpellIconID == 1680 || procSpell->SpellIconID == 473)) - return false; - break; - } - // Fingers of Frost, synchronise with Frostbite - case 44544: - { - if (procPhase == PROC_SPELL_PHASE_HIT) - { - // Find Frostbite - if (AuraEffect* aurEff = this->GetAuraEffect(SPELL_AURA_ADD_TARGET_TRIGGER, SPELLFAMILY_MAGE, 119, EFFECT_0)) - { - if (!victim) - return false; - - uint8 fofRank = sSpellMgr->GetSpellRank(triggeredByAura->GetId()); - uint8 fbRank = sSpellMgr->GetSpellRank(aurEff->GetId()); - uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f)); - - if (roll_chance_i(chance)) - CastSpell(victim, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); - } - } - break; - } - } - - // try detect target manually if not set - if (!target) - target = !(procFlags & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry->IsPositive() ? this : victim; - - if (cooldown) - { - if (HasSpellCooldown(triggerEntry->Id)) - return false; - - AddSpellCooldown(triggerEntry->Id, 0, cooldown); - } - - if(basepoints0) - CastCustomSpell(target, triggerEntry->Id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); - else - CastSpell(target, triggerEntry->Id, true, castItem, triggeredByAura); - - return true; -} - -bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown) -{ - int32 scriptId = triggeredByAura->GetMiscValue(); - - if (!victim || !victim->IsAlive()) - return false; - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; - - uint32 triggered_spell_id = 0; - - switch (scriptId) - { - case 836: // Improved Blizzard (Rank 1) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12484; - break; - } - case 988: // Improved Blizzard (Rank 2) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12485; - break; - } - case 989: // Improved Blizzard (Rank 3) - { - if (!procSpell || procSpell->SpellVisual[0] != 9487) - return false; - triggered_spell_id = 12486; - break; - } - case 4533: // Dreamwalker Raiment 2 pieces bonus - { - // Chance 50% - if (!roll_chance_i(50)) - return false; - - switch (victim->getPowerType()) - { - case POWER_MANA: - triggered_spell_id = 28722; - break; - case POWER_RAGE: - triggered_spell_id = 28723; - break; - case POWER_ENERGY: - triggered_spell_id = 28724; - break; - default: - return false; - } - break; - } - case 4537: // Dreamwalker Raiment 6 pieces bonus - triggered_spell_id = 28750; // Blessing of the Claw - break; - case 5497: // Improved Mana Gems - triggered_spell_id = 37445; // Mana Surge - break; - case 7010: // Revitalize - can proc on full hp target - case 7011: - case 7012: - { - if (!roll_chance_i(triggeredByAura->GetAmount())) - return false; - switch (victim->getPowerType()) - { - case POWER_MANA: - triggered_spell_id = 48542; - break; - case POWER_RAGE: - triggered_spell_id = 48541; - break; - case POWER_ENERGY: - triggered_spell_id = 48540; - break; - case POWER_RUNIC_POWER: - triggered_spell_id = 48543; - break; - default: - break; - } - break; - } - default: - break; - } - - // not processed - if (!triggered_spell_id) - return false; - - // standard non-dummy case - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - - if (!triggerEntry) - { - LOG_ERROR("entities.unit", "Unit::HandleOverrideClassScriptAuraProc: Spell {} triggering for class script id {}", triggered_spell_id, scriptId); - return false; - } - - if (cooldown) - { - if (HasSpellCooldown(triggered_spell_id)) - return false; - - AddSpellCooldown(triggered_spell_id, 0, cooldown); - } - - CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura); - - return true; -} - void Unit::setPowerType(Powers new_powertype) { SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); @@ -9660,7 +6229,7 @@ void Unit::setPowerType(Powers new_powertype) break; } - if (Player const* player = ToPlayer()) + if (const Player* player = ToPlayer()) if (player->NeedSendSpectatorData()) { ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PWT", new_powertype); @@ -9765,7 +6334,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target, bool checkOriginalFaction { // check contested flags if (targetFactionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS - && selfPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) + && selfPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) return REP_HOSTILE; // if faction has reputation, hostile state depends only from AtWar state @@ -9838,7 +6407,7 @@ ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTem { // check contested flags if (factionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS - && targetPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) + && targetPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) return REP_HOSTILE; if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry)) return *repRank; @@ -10180,8 +6749,8 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co if (spellProto) { AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); - for (AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j) - if ((*j)->IsAffectedOnSpell(spellProto)) + for (AuraEffect const* aurEff : stateAuras) + if (aurEff->IsAffectedOnSpell(spellProto)) return true; } // Check per caster aura state @@ -10577,9 +7146,12 @@ void Unit::SetCharm(Unit* charm, bool apply) } } -int32 Unit::DealHeal(Unit* healer, Unit* victim, uint32 addhealth) +void Unit::DealHeal(HealInfo& healInfo) { int32 gain = 0; + Unit* victim = healInfo.GetTarget(); + Unit* healer = healInfo.GetHealer(); + uint32 addhealth = healInfo.GetHeal(); if (healer) { @@ -10602,7 +7174,7 @@ int32 Unit::DealHeal(Unit* healer, Unit* victim, uint32 addhealth) unit = healer->GetOwner(); if (!unit) - return gain; + return; if (Player* player = unit->ToPlayer()) { @@ -10622,7 +7194,10 @@ int32 Unit::DealHeal(Unit* healer, Unit* victim, uint32 addhealth) //player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); // pussywizard: optimization }*/ - return gain; + if (gain) + { + healInfo.SetEffectiveHeal(gain > 0 ? static_cast(gain) : 0UL); + } } bool RedirectSpellEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) @@ -10853,16 +7428,16 @@ void Unit::UnsummonAllTotems(bool onDeath /*= false*/) } } -void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical) +void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/) { // we guess size WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 4 + 4 + 1 + 1)); - data << victim->GetPackGUID(); - data << GetPackGUID(); - data << uint32(SpellID); - data << uint32(Damage); - data << uint32(OverHeal); - data << uint32(Absorb); // Absorb amount + data << healInfo.GetTarget()->GetPackGUID(); + data << healInfo.GetHealer()->GetPackGUID(); + data << uint32(healInfo.GetSpellInfo()->Id); + data << uint32(healInfo.GetHeal()); + data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal()); + data << uint32(healInfo.GetAbsorb()); // Absorb amount data << uint8(critical ? 1 : 0); data << uint8(0); // unused SendMessageToSet(&data, true); @@ -10877,9 +7452,9 @@ int32 Unit::HealBySpell(HealInfo& healInfo, bool critical) // calculate heal absorb and reduce healing CalcHealAbsorb(healInfo); - int32 gain = Unit::DealHeal(healInfo.GetHealer(), healInfo.GetTarget(), healInfo.GetHeal()); - SendHealSpellLog(healInfo.GetTarget(), healInfo.GetSpellInfo()->Id, healInfo.GetHeal(), uint32(healInfo.GetHeal() - gain), healInfo.GetAbsorb(), critical); - return gain; + DealHeal(healInfo); + SendHealSpellLog(healInfo, critical); + return healInfo.GetEffectiveHeal(); } void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) @@ -10895,15 +7470,15 @@ void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Pow void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) { - victim->ModifyPower(powerType, damage, false); + SendEnergizeSpellLog(victim, spellID, damage, powerType); + // needs to be called after sending spell log + victim->ModifyPower(powerType, damage); if (powerType != POWER_HAPPINESS) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); victim->getHostileRefMgr().threatAssist(this, float(damage) * 0.5f, spellInfo); } - - SendEnergizeSpellLog(victim, spellID, damage, powerType); } float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) @@ -11365,7 +7940,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); + modOwner->ApplySpellMod(spellProto->Id, coeff); coeff /= 100.0f; } @@ -11375,7 +7950,16 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin float tmpDamage = (float(pdamage) + DoneTotal) * DoneTotalMod; // apply spellmod to Done damage (flat and pct) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + { + if (damagetype == DOT) + { + modOwner->ApplySpellMod(spellProto->Id, tmpDamage); + } + else + { + modOwner->ApplySpellMod(spellProto->Id, tmpDamage); + } + } return uint32(std::max(tmpDamage, 0.0f)); } @@ -11652,7 +8236,7 @@ float Unit::SpellDoneCritChance(Unit const* /*victim*/, SpellInfo const* spellPr // percent done // only players use intelligence for critical chance computations if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); + modOwner->ApplySpellMod(spellProto->Id, crit_chance); // xinef: can be negative! return crit_chance; @@ -11902,7 +8486,7 @@ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spell // adds additional damage to critBonus (from talents) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + modOwner->ApplySpellMod(spellProto->Id, crit_bonus); crit_bonus += damage; } @@ -11937,7 +8521,7 @@ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spel // adds additional damage to critBonus (from talents) // xinef: used for death knight death coil if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); + modOwner->ApplySpellMod(spellProto->Id, crit_bonus); } if (crit_bonus > 0) @@ -12122,7 +8706,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); + modOwner->ApplySpellMod(spellProto->Id, coeff); coeff /= 100.0f; } DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); @@ -12147,7 +8731,16 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui // apply spellmod to Done amount if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); + { + if (damagetype == DOT) + { + modOwner->ApplySpellMod(spellProto->Id, heal); + } + else + { + modOwner->ApplySpellMod(spellProto->Id, heal); + } + } return uint32(std::max(heal, 0.0f)); } @@ -12243,7 +8836,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); + modOwner->ApplySpellMod(spellProto->Id, coeff); coeff /= 100.0f; } @@ -12750,7 +9343,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType // apply spellmod to Done damage if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage); + modOwner->ApplySpellMod(spellProto->Id, tmpDamage); // bonus result can be negative return uint32(std::max(tmpDamage, 0.0f)); @@ -12940,7 +9533,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spe // Apply chance modifer aura if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM); + modOwner->ApplySpellMod(spellProto->Id, PPM); return floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } @@ -13367,7 +9960,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit. //Ignore stealth if target is player and unit in combat with same player - if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target))))) + if (GetEntry() != WORLD_TRIGGER && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target))))) return false; // can't attack dead @@ -13615,7 +10208,7 @@ int32 Unit::GetHealthGain(int32 dVal) } // returns negative amount on power reduction -int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/) +int32 Unit::ModifyPower(Powers power, int32 dVal) { if (dVal == 0) return 0; @@ -13627,7 +10220,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true* int32 val = dVal + curPower; if (val <= 0) { - SetPower(power, 0, withPowerUpdate); + SetPower(power, 0); return -curPower; } @@ -13635,12 +10228,12 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true* if (val < maxPower) { - SetPower(power, val, withPowerUpdate); + SetPower(power, val); gain = val - curPower; } else if (curPower != maxPower) { - SetPower(power, maxPower, withPowerUpdate); + SetPower(power, maxPower); gain = maxPower - curPower; } @@ -14266,17 +10859,17 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index { if (Player* modOwner = GetSpellModOwner()) { - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value); + modOwner->ApplySpellMod(spellProto->Id, value); switch (effect_index) { - case 0: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value); + case EFFECT_0: + modOwner->ApplySpellMod(spellProto->Id, value); break; - case 1: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value); + case EFFECT_1: + modOwner->ApplySpellMod(spellProto->Id, value); break; - case 2: - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value); + case EFFECT_2: + modOwner->ApplySpellMod(spellProto->Id, value); break; } } @@ -14417,7 +11010,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime, Spell* // called from caster if (Player* modOwner = GetSpellModOwner()) // TODO:(MadAgos) Eventually check and delete the bool argument - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell, bool(modOwner != this && !IsPet())); + modOwner->ApplySpellMod(spellInfo->Id, castTime, spell); switch (spellInfo->DmgClass) { @@ -14999,7 +11592,7 @@ void Unit::SetMaxHealth(uint32 val) SetHealth(val); } -void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/) +void Unit::SetPower(Powers power, uint32 val) { if (GetPower(power) == val) return; @@ -15010,14 +11603,11 @@ void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/) SetStatInt32Value(static_cast(UNIT_FIELD_POWER1) + power, val); - if (withPowerUpdate) - { - WorldPacket data(SMSG_POWER_UPDATE); - data << GetPackGUID(); - data << uint8(power); - data << uint32(val); - SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); - } + WorldPacket data(SMSG_POWER_UPDATE); + data << GetPackGUID(); + data << uint8(power); + data << uint32(val); + SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); // group update if (GetTypeId() == TYPEID_PLAYER) @@ -15508,92 +12098,6 @@ bool Unit::isFrozen() const return HasAuraState(AURA_STATE_FROZEN); } -struct ProcTriggeredData -{ - ProcTriggeredData(Aura* _aura) : aura(_aura) - { - effMask = 0; - spellProcEvent = nullptr; - triggerSpelId.fill(0); - } - - SpellProcEventEntry const* spellProcEvent; - Aura* aura; - uint32 effMask; - std::array triggerSpelId; - - bool operator==(const uint32 spellId) const - { - return aura->GetId() == spellId; - } -}; - -typedef std::list< ProcTriggeredData > ProcTriggeredList; - -// List of auras that CAN be trigger but may not exist in spell_proc_event -// in most case need for drop charges -// in some types of aura need do additional check -// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic -bool InitTriggerAuraData() -{ - for (uint16 i = 0; i < TOTAL_AURAS; ++i) - { - isTriggerAura[i] = false; - isNonTriggerAura[i] = false; - isAlwaysTriggeredAura[i] = false; - } - isTriggerAura[SPELL_AURA_DUMMY] = true; - isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; - isTriggerAura[SPELL_AURA_MOD_THREAT] = true; - isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger - isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; - isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; - isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; - isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; - isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger - isTriggerAura[SPELL_AURA_MOD_ROOT] = true; - isTriggerAura[SPELL_AURA_TRANSFORM] = true; - isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; - isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true; - isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true; - isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested - isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true; - isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true; - isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true; - isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true; - isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true; - isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true; - isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true; - isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true; - isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; - isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true; - isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true; - isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true; - isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true; - isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true; - isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; - isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true; - isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true; - isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true; - - isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN] = true; - isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK] = true; - - isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true; - isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true; - isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true; - isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true; - - return true; -} - void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bool positive, uint32& procAttacker, uint32& procVictim) { if (spellInfo) @@ -15668,73 +12172,74 @@ void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bo } } -uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition) +uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition) { - uint32 procEx = PROC_EX_NONE; + uint32 hitMask = PROC_HIT_NONE; // Check victim state if (missCondition != SPELL_MISS_NONE) + { switch (missCondition) { case SPELL_MISS_MISS: - procEx |= PROC_EX_MISS; - break; - case SPELL_MISS_RESIST: - procEx |= PROC_EX_RESIST; + hitMask |= PROC_HIT_MISS; break; case SPELL_MISS_DODGE: - procEx |= PROC_EX_DODGE; + hitMask |= PROC_HIT_DODGE; break; case SPELL_MISS_PARRY: - procEx |= PROC_EX_PARRY; + hitMask |= PROC_HIT_PARRY; break; case SPELL_MISS_BLOCK: - procEx |= PROC_EX_BLOCK; + hitMask |= PROC_HIT_BLOCK; break; case SPELL_MISS_EVADE: - procEx |= PROC_EX_EVADE; + hitMask |= PROC_HIT_EVADE; break; case SPELL_MISS_IMMUNE: - procEx |= PROC_EX_IMMUNE; + hitMask |= PROC_HIT_IMMUNE; break; case SPELL_MISS_IMMUNE2: - procEx |= PROC_EX_IMMUNE; + hitMask |= PROC_HIT_IMMUNE; break; case SPELL_MISS_DEFLECT: - procEx |= PROC_EX_DEFLECT; + hitMask |= PROC_HIT_DEFLECT; break; case SPELL_MISS_ABSORB: - procEx |= PROC_EX_ABSORB; + hitMask |= PROC_HIT_ABSORB; break; case SPELL_MISS_REFLECT: - procEx |= PROC_EX_REFLECT; + hitMask |= PROC_HIT_REFLECT; break; default: break; } + } else { // On block if (damageInfo->blocked) - procEx |= PROC_EX_BLOCK; + hitMask |= PROC_HIT_BLOCK; // On absorb if (damageInfo->absorb) - procEx |= PROC_EX_ABSORB; + hitMask |= PROC_HIT_ABSORB; // On crit if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - procEx |= PROC_EX_CRITICAL_HIT; + hitMask |= PROC_HIT_CRITICAL; else - procEx |= PROC_EX_NORMAL_HIT; + hitMask |= PROC_HIT_NORMAL; } - return procEx; + + return hitMask; } -void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase) +void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType) { // Player is loaded now - do not allow passive spell casts to proc if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading()) return; + // For melee/ranged based attack need update skills and set some Aura states if victim present - if (procFlag & MELEE_BASED_TRIGGER_MASK && target && procPhase == PROC_SPELL_PHASE_HIT) + if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget) { // Xinef: Shaman in ghost wolf form cant proc anything melee based if (!isVictim && GetShapeshiftForm() == FORM_GHOSTWOLF) @@ -15742,27 +12247,30 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u // Update skills here for players // only when you are not fighting other players or their pets/totems (pvp) - if (IsPlayer() && !target->IsCharmedOwnedByPlayerOrPlayer()) + if (GetTypeId() == TYPEID_PLAYER && + procTarget->GetTypeId() != TYPEID_PLAYER && + !(procTarget->IsTotem() && procTarget->ToTotem()->GetOwner()->IsPlayer()) && + !procTarget->IsPet() + ) { // On melee based hit/miss/resist/parry/dodge need to update skill (for victim and attacker) - if (procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_MISS | PROC_EX_RESIST | PROC_EX_PARRY | PROC_EX_DODGE)) + if (hitMask & (PROC_HIT_NORMAL | PROC_HIT_MISS | PROC_HIT_FULL_RESIST)) { - ToPlayer()->UpdateCombatSkills(target, attType, isVictim, procSpell ? procSpell->m_weaponItem : nullptr); - } - // Update defence if player is victim and we block - TODO: confirm that blocked attacks only have a chance to increase defence skill - else if (isVictim && procExtra & (PROC_EX_BLOCK)) - { - ToPlayer()->UpdateCombatSkills(target, attType, true); + if (procTarget->GetTypeId() != TYPEID_PLAYER && !procTarget->IsCritter()) + ToPlayer()->UpdateCombatSkills(procTarget, attType, isVictim); } + // Update defence if player is victim and we block + else if (isVictim && (hitMask & (PROC_HIT_DODGE | PROC_HIT_PARRY | PROC_HIT_BLOCK))) + ToPlayer()->UpdateCombatSkills(procTarget, attType, true); } // If exist crit/parry/dodge/block need update aura state (for victim and attacker) - if (procExtra & (PROC_EX_CRITICAL_HIT | PROC_EX_PARRY | PROC_EX_DODGE | PROC_EX_BLOCK)) + if (hitMask & (PROC_HIT_CRITICAL | PROC_HIT_PARRY | PROC_HIT_DODGE | PROC_HIT_BLOCK)) { // for victim if (isVictim) { // if victim and dodge attack - if (procExtra & PROC_EX_DODGE) + if (hitMask & PROC_HIT_DODGE) { // Update AURA_STATE on dodge if (getClass() != CLASS_ROGUE) // skip Rogue Riposte @@ -15772,7 +12280,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u } } // if victim and parry attack - if (procExtra & PROC_EX_PARRY) + if (hitMask & PROC_HIT_PARRY) { // For Hunters only Counterattack (skip Mongoose bite) if (getClass() == CLASS_HUNTER) @@ -15787,7 +12295,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u } } // if and victim block attack - if (procExtra & PROC_EX_BLOCK) + if (hitMask & PROC_HIT_BLOCK) { ModifyAuraState(AURA_STATE_DEFENSE, true); StartReactiveTimer(REACTIVE_DEFENSE); @@ -15796,416 +12304,38 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u else // For attacker { // Overpower on victim dodge - if (procExtra & PROC_EX_DODGE) + if (hitMask & PROC_HIT_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) { - if (getClass() == CLASS_WARRIOR) - { - AddComboPoints(target, 1); - StartReactiveTimer(REACTIVE_OVERPOWER); - } + AddComboPoints(procTarget, 1); + StartReactiveTimer(REACTIVE_OVERPOWER); } // Wolverine Bite - if ((procExtra & PROC_HIT_CRITICAL) && IsHunterPet()) + if ((hitMask & PROC_HIT_CRITICAL) && IsHunterPet()) { - AddComboPoints(target, 1); + AddComboPoints(procTarget, 1); StartReactiveTimer(REACTIVE_WOLVERINE_BITE); } } } } - - Unit* actor = isVictim ? target : this; - Unit* actionTarget = !isVictim ? target : this; - - ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, procPhase, procExtra, procSpell, damageInfo, healInfo, procAura, procAuraEffectIndex); - - ProcTriggeredList procTriggered; - // Fill procTriggered list - for (AuraApplicationMap::const_iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr) - { - // Do not allow auras to proc from effect triggered by itself - if (procAura && procAura->Id == itr->first) - continue; - - // Xinef: Generic Item Equipment cooldown, -1 is a special marker - if (itr->second->GetBase()->GetCastItemGUID() && HasSpellItemCooldown(itr->first, uint32(-1))) - continue; - - ProcTriggeredData triggerData(itr->second->GetBase()); - // Defensive procs are active on absorbs (so absorption effects are not a hindrance) - bool active = damage || (procExtra & PROC_EX_BLOCK && isVictim); - if (isVictim) - procExtra &= ~PROC_EX_INTERNAL_REQ_FAMILY; - - SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo(); - - // only auras that have trigger spell should proc from fully absorbed damage - if (procExtra & PROC_EX_ABSORB && isVictim) - if (damage || spellProto->Effects[EFFECT_0].TriggerSpell || spellProto->Effects[EFFECT_1].TriggerSpell || spellProto->Effects[EFFECT_2].TriggerSpell) - active = true; - - // xinef: fix spell procing from damaging / healing casts if spell has DoT / HoT effect only - // only player spells are taken into account - if (!active && !isVictim && !(procFlag & PROC_FLAG_DONE_PERIODIC) && procSpellInfo && procSpellInfo->SpellFamilyName && (procSpellInfo->HasAura(SPELL_AURA_PERIODIC_DAMAGE) || procSpellInfo->HasAura(SPELL_AURA_PERIODIC_HEAL))) - active = true; - - // AuraScript Hook - if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo)) - { - continue; - } - - bool isTriggeredAtSpellProcEvent = IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo); - - // AuraScript Hook - triggerData.aura->CallScriptCheckAfterProcHandlers(itr->second, eventInfo); - - if (!isTriggeredAtSpellProcEvent) - { - continue; - } - - // do checks using conditions table - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id); - ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget()); - if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) - { - continue; - } - - // Triggered spells not triggering additional spells - //bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_FROM_PROCS) ? - // (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false; - - bool hasTriggeredProc = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (itr->second->HasEffect(i)) - { - AuraEffect* aurEff = itr->second->GetBase()->GetEffect(i); - - // Skip this auras - if (isNonTriggerAura[aurEff->GetAuraType()]) - continue; - - // If not trigger by default and spellProcEvent == nullptr - skip - if (!isTriggerAura[aurEff->GetAuraType()] && !triggerData.spellProcEvent) - continue; - - switch (aurEff->GetAuraType()) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - case SPELL_AURA_MANA_SHIELD: - case SPELL_AURA_DUMMY: - case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: - if (uint32 triggerSpellId = aurEff->GetSpellInfo()->Effects[i].TriggerSpell) - { - triggerData.triggerSpelId[i] = triggerSpellId; - hasTriggeredProc = true; - } - break; - default: - break; - } - - // Some spells must always trigger - //if (isAlwaysTriggeredAura[aurEff->GetAuraType()]) - triggerData.effMask |= 1 << i; - } - } - - if (triggerData.effMask) - { - // If there is aura that triggers another proc aura, make sure that the triggered one is going to be proccessed on top of it - if (hasTriggeredProc) - { - bool proccessed = false; - for (uint8 i = 0; i < EFFECT_ALL; ++i) - { - if (uint32 triggeredSpellId = triggerData.triggerSpelId[i]) - { - auto iter = std::find(procTriggered.begin(), procTriggered.end(), triggeredSpellId); - if (iter != procTriggered.end()) - { - std::advance(iter, 1); - procTriggered.insert(iter, triggerData); - proccessed = true; - break; - } - } - } - - if (!proccessed) - { - procTriggered.push_front(triggerData); - } - } - else - { - procTriggered.push_front(triggerData); - } - } - } - - // Nothing found - if (procTriggered.empty()) - return; - - // Note: must SetCantProc(false) before return - if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC)) - SetCantProc(true); - - // Handle effects proceed this time - for (ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) - { - // look for aura in auras list, it may be removed while proc event processing - if (i->aura->IsRemoved()) - continue; - - bool useCharges = i->aura->IsUsingCharges(); - // no more charges to use, prevent proc - if (useCharges && !i->aura->GetCharges()) - continue; - - bool takeCharges = false; - SpellInfo const* spellInfo = i->aura->GetSpellInfo(); - - AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID()); - - bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo); - - // For players set spell cooldown if need - uint32 cooldown = 0; - if (prepare && i->spellProcEvent && i->spellProcEvent->cooldown) - cooldown = i->spellProcEvent->cooldown; - - // Xinef: set cooldown for actual proc - eventInfo.SetProcCooldown(cooldown); - - // Note: must SetCantProc(false) before return - if (spellInfo->HasAttribute(SPELL_ATTR3_INSTANT_TARGET_PROCS)) - SetCantProc(true); - - bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo); - - // "handled" is needed as long as proc can be handled in multiple places - if (!handled && HandleAuraProc(target, damage, i->aura, procSpellInfo, procFlag, procExtra, cooldown, &handled)) - { - uint32 Id = i->aura->GetId(); - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered with value by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), Id); - takeCharges = true; - } - - if (!handled) - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - { - if (!(i->effMask & (1 << effIndex))) - continue; - - AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex); - ASSERT(triggeredByAura); - - bool prevented = i->aura->CallScriptEffectProcHandlers(triggeredByAura, aurApp, eventInfo); - if (prevented) - { - takeCharges = true; - continue; - } - - switch (triggeredByAura->GetAuraType()) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - // Don`t drop charge or add cooldown for not started trigger - if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo)) - takeCharges = true; - break; - } - case SPELL_AURA_PROC_TRIGGER_DAMAGE: - { - // target has to be valid - if (!eventInfo.GetProcTarget()) - break; - - triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system - takeCharges = true; - break; - } - case SPELL_AURA_MANA_SHIELD: - case SPELL_AURA_DUMMY: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell)) - takeCharges = true; - break; - } - case SPELL_AURA_OBS_MOD_POWER: - case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: - case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - case SPELL_AURA_MOD_MELEE_HASTE: - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} aura of spell {})", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId()); - takeCharges = true; - break; - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpellInfo, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting mending (triggered by {} dummy aura of spell {})", - (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - if (damage > 0) - { - HandleAuraRaidProcFromChargeWithValue(triggeredByAura); - takeCharges = true; - } - break; - } - case SPELL_AURA_RAID_PROC_FROM_CHARGE: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting mending (triggered by {} dummy aura of spell {})", - (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - HandleAuraRaidProcFromCharge(triggeredByAura); - takeCharges = true; - break; - } - case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: - { - LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered with value by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); - - if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo)) - takeCharges = true; - break; - } - case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: - // Skip melee hits or instant cast spells - // xinef: check channeled spells which are affected by haste also - if (procSpellInfo && (procSpellInfo->SpellFamilyName || GetTypeId() != TYPEID_PLAYER) && - (procSpellInfo->CalcCastTime() > 0 /*|| - (procSpell->IsChanneled() && procSpell->GetDuration() > 0 && (HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, procSpell) || procSpell->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)))*/)) - takeCharges = true; - break; - case SPELL_AURA_REFLECT_SPELLS_SCHOOL: - // Skip Melee hits and spells ws wrong school - if (procSpellInfo && (triggeredByAura->GetMiscValue() & procSpellInfo->SchoolMask)) // School check - takeCharges = true; - break; - case SPELL_AURA_SPELL_MAGNET: - // Skip Melee hits and targets with magnet aura - if (procSpellInfo && (triggeredByAura->GetBase()->GetUnitOwner()->ToUnit() == ToUnit())) // Magnet - takeCharges = true; - break; - case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: - case SPELL_AURA_MOD_POWER_COST_SCHOOL: - // Skip melee hits and spells ws wrong school or zero cost - if (procSpellInfo && - (procSpellInfo->ManaCost != 0 || procSpellInfo->ManaCostPercentage != 0 || (procSpellInfo->SpellFamilyFlags[1] & 0x2)) && // Cost check, mutilate include - (triggeredByAura->GetMiscValue() & procSpellInfo->SchoolMask)) // School check - takeCharges = true; - break; - case SPELL_AURA_MECHANIC_IMMUNITY: - case SPELL_AURA_MOD_MECHANIC_RESISTANCE: - // Compare mechanic - if (procSpellInfo && procSpellInfo->Mechanic == uint32(triggeredByAura->GetMiscValue())) - takeCharges = true; - break; - case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: - // Compare casters - if (target && triggeredByAura->GetCasterGUID() == target->GetGUID()) - takeCharges = true; - break; - // CC Auras which use their amount amount to drop - // Are there any more auras which need this? - case SPELL_AURA_MOD_CONFUSE: - case SPELL_AURA_MOD_FEAR: - case SPELL_AURA_MOD_STUN: - case SPELL_AURA_MOD_ROOT: - case SPELL_AURA_TRANSFORM: - { - // Spell own direct damage at apply wont break the CC - // Xinef: Or when the aura is at full duration (assume that such auras should be added at the end, skipping all damage procs etc.) - if (procSpellInfo) - if ((!i->aura->IsPermanent() && i->aura->GetDuration() == i->aura->GetMaxDuration()) || procSpellInfo->Id == triggeredByAura->GetId() || - procSpellInfo->HasAttribute(SPELL_ATTR4_REACTIVE_DAMAGE_PROC)) - break; - - // chargeable mods are breaking on hit - if (useCharges) - takeCharges = true; - else if (triggeredByAura->GetAmount()) // aura must have amount - { - int32 damageLeft = triggeredByAura->GetAmount(); - // No damage left - if (damageLeft < int32(damage)) - i->aura->Remove(); - else - triggeredByAura->SetAmount(damageLeft - damage); - } - break; - } - case SPELL_AURA_ABILITY_IGNORE_AURASTATE: - if (procSpellInfo && procSpellInfo->Id == 20647) // hack for warriors execute, both dummy and damage spell are affected by ignore aurastate aura - break; - takeCharges = true; - break; - case SPELL_AURA_ADD_FLAT_MODIFIER: - case SPELL_AURA_ADD_PCT_MODIFIER: - { - if (SpellModifier* mod = triggeredByAura->GetSpellModifier()) - { - if (mod->op == SPELLMOD_CASTING_TIME && mod->value < 0 && procSpell) - { - // Skip instant spells - if (procSpellInfo->CalcCastTime() <= 0 || (procSpell->GetTriggeredCastFlags() & TRIGGERED_CAST_DIRECTLY) != 0) - { - break; - } - } - } - takeCharges = true; - break; - } - default: - takeCharges = true; - break; - } - i->aura->CallScriptAfterEffectProcHandlers(triggeredByAura, aurApp, eventInfo); - } - // Remove charge (aura can be removed by triggers) - // xinef: take into account attribute6 of proc spell - if (prepare && useCharges && takeCharges) - if (!procSpellInfo || isVictim || !procSpellInfo->HasAttribute(SPELL_ATTR6_DO_NOT_CONSUME_RESOURCES)) - i->aura->DropCharge(); - - i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo); - - if (spellInfo->HasAttribute(SPELL_ATTR3_INSTANT_TARGET_PROCS)) - SetCantProc(false); - } - - // Cleanup proc requirements - if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC)) - SetCantProc(false); } -void Unit::GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo) +void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo) { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + // use provided list of auras which can proc if (procAuras) { - for (std::list::iterator itr = procAuras->begin(); itr != procAuras->end(); ++itr) + for (AuraApplication* aurApp : *procAuras) { - ASSERT((*itr)->GetTarget() == this); - if (!(*itr)->GetRemoveMode()) - if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo)) + ASSERT(aurApp->GetTarget() == this); + if (!aurApp->GetRemoveMode()) + if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now)) { - (*itr)->GetBase()->PrepareProcToTrigger(*itr, eventInfo); - aurasTriggeringProc.push_back(*itr); + aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now); + aurasTriggeringProc.emplace_back(procEffectMask, aurApp); } } } @@ -16214,10 +12344,10 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list& aurasTrigge { for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr) { - if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo)) + if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now)) { - itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo); - aurasTriggeringProc.push_back(itr->second); + itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now); + aurasTriggeringProc.emplace_back(procEffectMask, itr->second); } } } @@ -16226,34 +12356,71 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list& aurasTrigge void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo) { DamageInfo dmgInfo = DamageInfo(damageInfo); - TriggerAurasProcOnEvent(nullptr, nullptr, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, 0, 0, damageInfo.procEx, nullptr, &dmgInfo, nullptr); + TriggerAurasProcOnEvent(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); } -void Unit::TriggerAurasProcOnEvent(std::list* myProcAuras, std::list* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) +void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { // prepare data for self trigger - ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - std::list myAurasTriggeringProc; - GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo); + ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + if (typeMaskActor) + { + AuraApplicationProcContainer myAurasTriggeringProc; + GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo); + + // needed for example for Cobra Strikes, pet does the attack, but aura is on owner + if (Player* modOwner = GetSpellModOwner()) + { + if (modOwner != this && spell) + { + AuraApplicationList modAuras; + for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr) + { + if (spell->m_appliedMods.count(itr->second->GetBase()) != 0) + modAuras.push_back(itr->second); + } + modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo); + } + } + + TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc); + } // prepare data for target trigger - ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - std::list targetAurasTriggeringProc; - if (typeMaskActionTarget) - GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo); - - TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc); - - if (typeMaskActionTarget) - TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc); + ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + if (typeMaskActionTarget && actionTarget) + { + AuraApplicationProcContainer targetAurasTriggeringProc; + actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo); + actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc); + } } -void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& aurasTriggeringProc) +void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc) { - for (std::list::iterator itr = aurasTriggeringProc.begin(); itr != aurasTriggeringProc.end(); ++itr) + for (auto const& aurAppProc : aurasTriggeringProc) { - if (!(*itr)->GetRemoveMode()) - (*itr)->GetBase()->TriggerProcOnEvent(*itr, eventInfo); + AuraApplication* aurApp; + uint8 procEffectMask; + std::tie(procEffectMask, aurApp) = aurAppProc; + + if (aurApp->GetRemoveMode()) + { + continue; + } + + SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo(); + if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC)) + { + SetCantProc(true); + } + + aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo); + + if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC)) + { + SetCantProc(false); + } } } @@ -16487,6 +12654,10 @@ void Unit::AddComboPoints(Unit* target, int8 count) return; } + // remove Premed-like effects + // (NB: this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore) + RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS); + if (target && target != m_comboTarget) { if (m_comboTarget) @@ -17054,280 +13225,7 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return true; } -bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo) -{ - SpellInfo const* spellProto = aura->GetSpellInfo(); - SpellInfo const* procSpell = eventInfo.GetSpellInfo(); - - // let the aura be handled by new proc system if it has new entry - if (sSpellMgr->GetSpellProcEntry(spellProto->Id)) - return false; - - // Get proc Event Entry - spellProcEvent = sSpellMgr->GetSpellProcEvent(spellProto->Id); - - // Get EventProcFlag - uint32 EventProcFlag; - if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags - EventProcFlag = spellProcEvent->procFlags; - else - EventProcFlag = spellProto->ProcFlags; // else get from spell proto - // Continue if no trigger exist - if (!EventProcFlag) - return false; - - // Additional checks for triggered spells (ignore trap casts) - //if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) - //{ - // if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_TRIGGERED)) - // return false; - //} - - // Xinef: additional check for player auras - only player spells can trigger player proc auras - // Xinef: skip victim auras - // Excluded player shoot spells - if (!isVictim && GetTypeId() == TYPEID_PLAYER) //spellProto->SpellFamilyName != SPELLFAMILY_GENERIC) - if (!(EventProcFlag & (PROC_FLAG_KILL | PROC_FLAG_DEATH)) && procSpell && procSpell->SpellFamilyName == SPELLFAMILY_GENERIC && procSpell->GetCategory() != 76 && - (!eventInfo.GetTriggerAuraSpell() || eventInfo.GetTriggerAuraSpell()->SpellFamilyName == SPELLFAMILY_GENERIC)) - return false; - - // Check spellProcEvent data requirements - if (!sSpellMgr->IsSpellProcEventCanTriggeredBy(spellProto, spellProcEvent, EventProcFlag, eventInfo, active)) - return false; - // In most cases req get honor or XP from kill - if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER) - { - bool allow = false; - - if (victim) - allow = ToPlayer()->isHonorOrXPTarget(victim); - - // Shadow Word: Death - can trigger from every kill - if (aura->GetId() == 32409 || aura->GetId() == 18372 || aura->GetId() == 18213) - allow = true; - if (!allow) - return false; - } - // Aura added by spell can`t trigger from self (prevent drop charges/do triggers) - // But except periodic and kill triggers (can triggered from self) - if (procSpell && procSpell->Id == spellProto->Id - && !(spellProto->ProcFlags & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL))) - return false; - - // Check if current equipment allows aura to proc - if (!isVictim && GetTypeId() == TYPEID_PLAYER && !spellProto->HasAttribute(SPELL_ATTR3_NO_PROC_EQUIP_REQUIREMENT)) - { - Player* player = ToPlayer(); - if (spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) - { - Item* item = nullptr; - if (attType == BASE_ATTACK) - item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - else if (attType == OFF_ATTACK) - item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - else - item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); - - if (player->IsInFeralForm()) - return false; - - if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->SubClass) & spellProto->EquippedItemSubClassMask)) - return false; - } - else if (spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) - { - // Check if player is wearing shield - Item* item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->SubClass) & spellProto->EquippedItemSubClassMask)) - return false; - } - } - // Get chance from spell - float chance = float(spellProto->ProcChance); - // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance; - if (spellProcEvent && spellProcEvent->customChance) - chance = spellProcEvent->customChance; - // If PPM exist calculate chance from PPM - if (spellProcEvent && spellProcEvent->ppmRate != 0) - { - if (!isVictim) - { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); - } - else if (victim) - { - uint32 WeaponSpeed = victim->GetAttackTime(attType); - chance = victim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); - } - } - - // Custom chances - switch (spellProto->SpellFamilyName) - { - case SPELLFAMILY_WARRIOR: - { - // Recklessness, allow to proc only once for whirlwind - if (spellProto->Id == 1719 && procSpell && procSpell->Id == 44949) - return false; - } - } - - if (eventInfo.GetProcChance()) - { - chance = *eventInfo.GetProcChance(); - } - - // Apply chance modifer aura - if (Player* modOwner = GetSpellModOwner()) - { - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance); - } - - return roll_chance_f(chance); -} - -bool Unit::HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura) -{ - // aura can be deleted at casts - SpellInfo const* spellProto = triggeredByAura->GetSpellInfo(); - int32 heal = triggeredByAura->GetAmount(); - ObjectGuid caster_guid = triggeredByAura->GetCasterGUID(); - - // Currently only Prayer of Mending - if (!(spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && spellProto->SpellFamilyFlags[1] & 0x20)) - { - LOG_DEBUG("spells.aura", "Unit::HandleAuraRaidProcFromChargeWithValue, received not handled spell: {}", spellProto->Id); - return false; - } - - // jumps - int32 jumps = triggeredByAura->GetBase()->GetCharges() - 1; - - // current aura expire - triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease - - // next target selection - if (jumps > 0) - { - if (Unit* caster = triggeredByAura->GetCaster()) - { - // smart healing - float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); - std::list nearMembers; - - Player* player = nullptr; - if (GetTypeId() == TYPEID_PLAYER) - player = ToPlayer(); - else if (GetOwner()) - player = GetOwner()->ToPlayer(); - - if (player) - { - Group* group = player->GetGroup(); - if (!group) - { - if (player != this) - { - if (IsWithinDistInMap(player, radius)) - nearMembers.push_back(player); - } - else if (Unit* pet = GetGuardianPet()) - { - if (IsWithinDistInMap(pet, radius)) - nearMembers.push_back(pet); - } - } - else - { - for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) - if (Player* Target = itr->GetSource()) - { - if (Target != this && !IsWithinDistInMap(Target, radius)) - continue; - - // IsHostileTo check duel and controlled by enemy - if (Target != this && Target->IsAlive() && !IsHostileTo(Target)) - nearMembers.push_back(Target); - - // Push player's pet to vector - if (Unit* pet = Target->GetGuardianPet()) - if (pet != this && pet->IsAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet)) - nearMembers.push_back(pet); - } - } - - if (!nearMembers.empty()) - { - nearMembers.sort(Acore::HealthPctOrderPred()); - if (Unit* target = nearMembers.front()) - { - CastSpell(target, 41637 /*Dummy visual effect triggered by main spell cast*/, true); - CastCustomSpell(target, spellProto->Id, &heal, nullptr, nullptr, true, nullptr, triggeredByAura, caster_guid); - if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID())) - aura->SetCharges(jumps); - } - } - } - } - } - - // heal - CastCustomSpell(this, 33110, &heal, nullptr, nullptr, true, nullptr, nullptr, caster_guid); - return true; -} -bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura) -{ - // aura can be deleted at casts - SpellInfo const* spellProto = triggeredByAura->GetSpellInfo(); - - uint32 damageSpellId; - switch (spellProto->Id) - { - case 57949: // shiver - damageSpellId = 57952; - //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637) - break; - case 59978: // shiver - damageSpellId = 59979; - break; - case 43593: // Cold Stare - damageSpellId = 43594; - break; - default: - LOG_ERROR("entities.unit", "Unit::HandleAuraRaidProcFromCharge, received unhandled spell: {}", spellProto->Id); - return false; - } - - ObjectGuid caster_guid = triggeredByAura->GetCasterGUID(); - - // jumps - int32 jumps = triggeredByAura->GetBase()->GetCharges() - 1; - - // current aura expire - triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease - - // next target selection - if (jumps > 0) - { - if (Unit* caster = triggeredByAura->GetCaster()) - { - float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); - if (Unit* target = GetNextRandomRaidMemberOrPet(radius)) - { - CastSpell(target, spellProto, true, nullptr, triggeredByAura, caster_guid); - if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID())) - aura->SetCharges(jumps); - } - } - } - - CastSpell(this, damageSpellId, true, nullptr, triggeredByAura, caster_guid); - - return true; -} - -void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackType attackType, SpellInfo const* spellProto, Spell const* spell /*= nullptr*/) +void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackType /* attackType */, SpellInfo const* /* spellProto */) { // Prevent killing unit twice (and giving reward from kill twice) if (!victim->GetHealth()) @@ -17442,17 +13340,22 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp // Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim if (killer && (killer->IsPet() || killer->IsTotem())) + { + // proc only once for victim if (Unit* owner = killer->GetOwner()) { - Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); - sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature()); + owner->ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + sScriptMgr->OnCreatureKilledByPet(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature()); } + } if (killer != victim && !victim->IsCritter()) - Unit::ProcDamageAndSpell(killer, victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); + { + killer->ProcSkillsAndAuras(victim, killer ? PROC_FLAG_KILL : PROC_FLAG_NONE, PROC_FLAG_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + } // Proc auras on death - must be before aura/combat remove - Unit::ProcDamageAndSpell(victim, nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); + victim->ProcSkillsAndAuras(victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras @@ -18618,7 +14521,7 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, i if (spellId) { if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, hitChance); + modOwner->ApplySpellMod(spellId, hitChance); } missChance += hitChance - 100.0f; @@ -19134,15 +15037,6 @@ void Unit::JumpTo(WorldObject* obj, float speedZ) bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) { - Creature* creature = ToCreature(); - if (creature && creature->IsAIEnabled) - { - if (!creature->AI()->BeforeSpellClick(clicker)) - { - return false; - } - } - bool result = false; uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry(); SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry); @@ -19211,6 +15105,7 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) result = true; } + Creature* creature = ToCreature(); if (creature && creature->IsAIEnabled) creature->AI()->OnSpellClick(clicker, result); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 383b45247..d15b141bf 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -702,13 +702,13 @@ struct DiminishingReturn : DRGroup(group), stack(0), hitTime(t), hitCount(count) {} - DiminishingGroup DRGroup: 16; - uint16 stack: 16; + DiminishingGroup DRGroup; + uint16 stack; uint32 hitTime; uint32 hitCount; }; -enum MeleeHitOutcome +enum MeleeHitOutcome : uint8 { MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY, MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL @@ -761,11 +761,12 @@ private: uint32 m_absorb; uint32 m_resist; uint32 m_block; + uint32 m_hitMask; uint32 m_cleanDamage; public: - explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0); + DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType, uint32 cleanDamage = 0); explicit DamageInfo(CalcDamageInfo& dmgInfo); - DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType); + DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask); void ModifyDamage(int32 amount); void AbsorbDamage(uint32 amount); @@ -784,6 +785,7 @@ public: [[nodiscard]] uint32 GetBlock() const { return m_block; }; [[nodiscard]] uint32 GetUnmitigatedDamage() const; + [[nodiscard]] uint32 GetHitMask() const; }; class HealInfo @@ -792,33 +794,33 @@ private: Unit* const m_healer; Unit* const m_target; uint32 m_heal; + uint32 m_effectiveHeal; uint32 m_absorb; SpellInfo const* const m_spellInfo; SpellSchoolMask const m_schoolMask; + uint32 m_hitMask; public: - explicit HealInfo(Unit* _healer, Unit* _target, uint32 _heal, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask) - : m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask) - { - m_absorb = 0; - } - void AbsorbHeal(uint32 amount) - { - amount = std::min(amount, GetHeal()); - m_absorb += amount; - m_heal -= amount; - } + explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask); + void AbsorbHeal(uint32 amount); void SetHeal(uint32 amount) { m_heal = amount; } + void SetEffectiveHeal(uint32 amount) + { + m_effectiveHeal = amount; + } + [[nodiscard]] Unit* GetHealer() const { return m_healer; } [[nodiscard]] Unit* GetTarget() const { return m_target; } [[nodiscard]] uint32 GetHeal() const { return m_heal; } + [[nodiscard]] uint32 GetEffectiveHeal() const { return m_effectiveHeal; } [[nodiscard]] uint32 GetAbsorb() const { return m_absorb; } [[nodiscard]] SpellInfo const* GetSpellInfo() const { return m_spellInfo; }; [[nodiscard]] SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }; + [[nodiscard]] uint32 GetHitMask() const; }; class ProcEventInfo @@ -923,7 +925,7 @@ struct SpellPeriodicAuraLogInfo }; void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bool positive, uint32& procAttacker, uint32& procVictim); -uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition); +uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition); struct RedirectThreatInfo { @@ -1288,6 +1290,7 @@ public: typedef std::list AuraList; typedef std::list AuraApplicationList; typedef std::list Diminishing; + typedef std::vector> AuraApplicationProcContainer; typedef GuidUnorderedSet ComboPointHolderSet; typedef std::map VisibleAuraMap; @@ -1439,10 +1442,10 @@ public: void setPowerType(Powers power); [[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast(UNIT_FIELD_POWER1) + power); } [[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast(UNIT_FIELD_MAXPOWER1) + power); } - void SetPower(Powers power, uint32 val, bool withPowerUpdate = true); + void SetPower(Powers power, uint32 val); void SetMaxPower(Powers power, uint32 val); // returns the change in power - int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true); + int32 ModifyPower(Powers power, int32 val); int32 ModifyPowerPct(Powers power, float pct, bool apply = true); [[nodiscard]] uint32 GetAttackTime(WeaponAttackType att) const @@ -1526,16 +1529,15 @@ public: uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb); static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr); - static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr); - static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth); + static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr); + static void DealHeal(HealInfo& healInfo); - static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/); - void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/); + void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); - void GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo); + void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo); void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo); - void TriggerAurasProcOnEvent(std::list* myProcAuras, std::list* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); - void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& procAuras); + void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); + void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras); void HandleEmoteCommand(uint32 emoteId); void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false); @@ -1543,12 +1545,7 @@ public: void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); - void HandleProcExtraAttackFor(Unit* victim, uint32 count); - void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; } - [[nodiscard]] uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; } - void AddExtraAttacks(uint32 count); - void SetLastDamagedTargetGuid(ObjectGuid const& guid) { _lastDamagedTargetGuid = guid; } - [[nodiscard]] ObjectGuid const& GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; } + void HandleProcExtraAttackFor(Unit* victim); void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false); void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell = nullptr); @@ -1700,7 +1697,7 @@ public: [[nodiscard]] virtual bool IsUnderWater() const; bool isInAccessiblePlaceFor(Creature const* c) const; - void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); + void SendHealSpellLog(HealInfo& healInfo, bool critical = false); int32 HealBySpell(HealInfo& healInfo, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); @@ -2515,14 +2512,6 @@ protected: bool _instantCast; private: - bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo); - bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr); - bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled); - bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo); - bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown); - bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura); - bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura); - void UpdateSplineMovement(uint32 t_diff); void UpdateSplinePosition(); @@ -2530,6 +2519,8 @@ private: [[nodiscard]] float GetCombatRatingReduction(CombatRating cr) const; [[nodiscard]] uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const; + void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType); + protected: void SetFeared(bool apply); void SetConfused(bool apply); @@ -2563,10 +2554,6 @@ private: bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed? [[nodiscard]] float processDummyAuras(float TakenTotalMod) const; - - uint32 _lastExtraAttackSpell; - std::unordered_map extraAttacksTargets; - ObjectGuid _lastDamagedTargetGuid; }; namespace Acore diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 70eb6ef98..9afe62860 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1186,7 +1186,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) { int32 i = 0; flag96 _mask = 0; - SpellModList const& spellMods = pCurrChar->GetSpellModList(opType); + SpellModContainer const& spellMods = pCurrChar->GetSpellModContainer(opType); if (spellMods.empty()) continue; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 94a6d72b6..46a5ef1e9 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -103,8 +103,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] = &AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY &AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY &AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY - &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell - &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor + &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc + &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc &AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES &AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES &AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a) @@ -323,7 +323,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] = &AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus &AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code &AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE - &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast + &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast &AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask &AuraEffect::HandleUnused, //264 unused (3.2.0) &AuraEffect::HandleUnused, //265 unused (3.2.0) @@ -631,7 +631,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) { // Apply periodic time mod if (modOwner) - modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude); + modOwner->ApplySpellMod(GetId(), m_amplitude); if (caster) { @@ -689,7 +689,6 @@ void AuraEffect::CalculateSpellMod() m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types m_spellmod->spellId = GetId(); m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; - m_spellmod->charges = GetBase()->GetCharges(); } m_spellmod->value = GetAmount(); break; @@ -1072,14 +1071,11 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const { if (!spell) return false; - // Check family name - if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName) + // Check family name and EffectClassMask + if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask)) return false; - // Check EffectClassMask - if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags) - return true; - return false; + return true; } bool AuraEffect::HasSpellClassMask() const @@ -1146,6 +1142,99 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const } } +bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const +{ + bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo); + if (!result) + return false; + + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + switch (GetAuraType()) + { + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + case SPELL_AURA_TRANSFORM: + { + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + { + return false; + } + + // Spell own damage at apply won't break CC + if (spellInfo && spellInfo == eventInfo.GetSpellInfo()) + { + Aura* aura = GetBase(); + // called from spellcast, should not have ticked yet + if (aura->GetDuration() == aura->GetMaxDuration()) + { + return false; + } + } + break; + } + break; + case SPELL_AURA_MECHANIC_IMMUNITY: + case SPELL_AURA_MOD_MECHANIC_RESISTANCE: + // Compare mechanic + if (!spellInfo || static_cast(spellInfo->Mechanic) != GetMiscValue()) + { + return false; + } + break; + case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: + // Skip melee hits and instant cast spells + if (!spellInfo || !spellInfo->CalcCastTime()) + { + return false; + } + break; + case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: + // Compare casters + if (GetCasterGUID() != eventInfo.GetActor()->GetGUID()) + { + return false; + } + break; + case SPELL_AURA_MOD_POWER_COST_SCHOOL: + case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: + // Skip melee hits and spells with wrong school or zero cost + if (!spellInfo || (!spellInfo->ManaCost && !spellInfo->ManaCostPercentage) || // Cost Check + !(spellInfo->GetSchoolMask() & GetMiscValue())) // School Check + { + return false; + } + break; + case SPELL_AURA_REFLECT_SPELLS_SCHOOL: + // Skip melee hits and spells with wrong school + if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue())) + { + return false; + } + break; + case SPELL_AURA_PROC_TRIGGER_SPELL: + case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: + { + // Don't proc extra attacks while already processing extra attack spell + uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell; + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + { + if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + { + return false; + } + } + break; + } + default: + break; + } + + return result; +} + void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo); @@ -1154,6 +1243,16 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) switch (GetAuraType()) { + // CC Auras which use their amount to drop + // Are there anyu more auras which need this? + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + case SPELL_AURA_TRANSFORM: + HandleBreakableCCAuraProc(aurApp, eventInfo); + break; + case SPELL_AURA_DUMMY: case SPELL_AURA_PROC_TRIGGER_SPELL: HandleProcTriggerSpellAuraProc(aurApp, eventInfo); break; @@ -2878,7 +2977,6 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo displayId = 0; } } - } target->Mount(displayId, vehicleId, GetMiscValue()); } @@ -5116,12 +5214,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use break; - case 71563: - { - if (Aura* newAura = target->AddAura(71564, target)) - newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); - return; - } } } // AT REMOVE @@ -6354,10 +6446,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const mitigatedDamage += resilienceReduction; } - damage = std::max(0, dmg); - cleanDamage.mitigated_damage = std::max(0, mitigatedDamage); + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage); - DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); @@ -6371,12 +6461,15 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; + uint32 hitMask = dmgInfo.GetHitMask(); if (absorb > 0) - procEx |= PROC_EX_ABSORB; + hitMask |= PROC_HIT_ABSORB; if (damage) + { procVictim |= PROC_FLAG_TAKEN_DAMAGE; + hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; + } int32 overkill = damage - target->GetHealth(); if (overkill < 0) @@ -6387,7 +6480,8 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); - Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); + // allow null caster to call this function + caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const @@ -6440,10 +6534,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c cleanDamageAmount += resilienceReduction; } - damage = std::max(0, dmg); - cleanDamage.mitigated_damage = std::max(0, cleanDamageAmount); + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage); - DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); @@ -6453,12 +6545,15 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; + uint32 hitMask = dmgInfo.GetHitMask(); if (absorb > 0) - procEx |= PROC_EX_ABSORB; + hitMask |= PROC_HIT_ABSORB; if (dmgInfo.GetDamage()) + { procVictim |= PROC_FLAG_TAKEN_DAMAGE; + hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; + } if (target->GetHealth() < dmgInfo.GetDamage()) { @@ -6476,7 +6571,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); - Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); + // allow null caster to call this function + caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dmgInfo, nullptr); if (!caster || !caster->IsAlive()) return; @@ -6489,6 +6585,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); int32 gain = caster->HealBySpell(healInfo); caster->getHostileRefMgr().threatAssist(caster, gain * 0.5f, GetSpellInfo()); + caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const @@ -6622,13 +6719,13 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); Unit::CalcHealAbsorb(healInfo); - int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal()); + Unit::DealHeal(healInfo); - SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit); + SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); if (caster) - target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo()); + target->getHostileRefMgr().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo()); bool haveCastItem = GetBase()->GetCastItemGUID(); @@ -6638,9 +6735,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST)) { uint32 manaPerSecond = GetSpellInfo()->ManaPerSecond; - if ((int32)manaPerSecond > gain && gain > 0) + if (manaPerSecond > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal() > 0) { - manaPerSecond = gain; + manaPerSecond = healInfo.GetEffectiveHeal(); } uint32 absorb2 = 0; @@ -6652,13 +6749,15 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; + uint32 hitMask = (crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL); if (healInfo.GetAbsorb() > 0) - procEx |= PROC_EX_ABSORB; + { + hitMask |= PROC_HIT_ABSORB; + } // ignore item heals if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot - Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo); + caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -6839,14 +6938,32 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT; + uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE); + uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL; if (damageInfo.damage) + { procVictim |= PROC_FLAG_TAKEN_DAMAGE; + spellTypeMask |= PROC_SPELL_TYPE_DAMAGE; + } caster->DealSpellDamage(&damageInfo, true); - DamageInfo dmgInfo(damageInfo, DOT); - Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo); + DamageInfo dmgInfo(damageInfo, DOT, BASE_ATTACK, hitMask); + caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr); +} + +void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) +{ + int32 const damageLeft = GetAmount() - static_cast(eventInfo.GetDamageInfo()->GetDamage()); + + if (damageLeft <= 0) + { + aurApp->GetTarget()->RemoveAura(aurApp); + } + else + { + SetAmount(damageLeft); + } } void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) @@ -6862,7 +6979,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve } else { - LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); + LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); } } @@ -6883,7 +7000,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp } else { - LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); + LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index b85984341..b7ff1e15f 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -49,7 +49,6 @@ public: Aura* GetBase() const { return m_base; } void GetTargetList(std::list& targetList) const; void GetApplicationList(std::list& applicationList) const; - SpellModifier* GetSpellModifier() const { return m_spellmod; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } uint32 GetId() const; @@ -96,6 +95,7 @@ public: void SendTickImmune(Unit* target, Unit* caster) const; void PeriodicTick(AuraApplication* aurApp, Unit* caster) const; + bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void CleanupTriggeredSpells(Unit* target); @@ -333,6 +333,7 @@ public: void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const; // aura effect proc handlers + void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 8d2add5c3..db70f3207 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -411,7 +411,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* m_castItemGuid(itemGUID ? itemGUID : castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(GameTime::GetGameTime().count()), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), - m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_triggeredByAuraSpellInfo(nullptr) + m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_procCooldown(std::chrono::steady_clock::time_point::min()), m_triggeredByAuraSpellInfo(nullptr) { if ((m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST)) m_timeCla = 1 * IN_MILLISECONDS; @@ -875,7 +875,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const // IsPermanent() checks max duration (which we are supposed to calculate here) if (maxDuration != -1 && modOwner) - modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration); + modOwner->ApplySpellMod(GetId(), maxDuration); return maxDuration; } @@ -885,7 +885,7 @@ void Aura::SetDuration(int32 duration, bool withMods) { if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration); + modOwner->ApplySpellMod(GetId(), duration); } m_duration = duration; SetNeedClientUpdateForTargets(); @@ -976,11 +976,11 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const { uint32 maxProcCharges = m_spellInfo->ProcCharges; if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId())) - maxProcCharges = procEntry->charges; + maxProcCharges = procEntry->Charges; if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges); + modOwner->ApplySpellMod(GetId(), maxProcCharges); return maxProcCharges; } @@ -1062,12 +1062,6 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode, bool periodicRes // reset charges SetCharges(CalcMaxCharges()); - // FIXME: not a best way to synchronize charges, but works - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (AuraEffect* aurEff = GetEffect(i)) - if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER) - if (SpellModifier* mod = aurEff->GetSpellModifier()) - mod->charges = GetCharges(); } SetStackAmount(stackAmount); @@ -1202,7 +1196,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const // Apply dispel mod from aura caster if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance); + modOwner->ApplySpellMod(GetId(), resistChance); // Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST // Only affects offensive dispels @@ -1260,7 +1254,7 @@ void Aura::HandleAllEffects(AuraApplication* aurApp, uint8 mode, bool apply) m_effects[i]->HandleEffect(aurApp, mode, apply); } -void Aura::GetApplicationList(std::list& applicationList) const +void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const { for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) { @@ -1439,6 +1433,9 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b } break; case 44544: // Fingers of Frost + // Refresh or add visual aura + target->CastCustomSpell(74396, SPELLVALUE_AURA_STACK, sSpellMgr->AssertSpellInfo(74396)->StackAmount, (Unit*)nullptr, true); + break; { // See if we already have the indicator aura. If not, create one. if (Aura* aur = target->GetAura(74396)) @@ -1663,10 +1660,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b target->CastSpell(target, 32612, true, nullptr, GetEffect(1)); target->CombatStop(); break; - case 74396: // Fingers of Frost - // Remove the IGNORE_AURASTATE aura - target->RemoveAurasDueToSpell(44544); - break; case 44401: // Missile Barrage case 48108: // Hot Streak case 57761: // Fireball! @@ -2192,22 +2185,17 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const return true; } -bool Aura::IsProcOnCooldown() const +bool Aura::IsProcOnCooldown(std::chrono::steady_clock::time_point now) const { - /*if (m_procCooldown) - { - if (m_procCooldown > GameTime::GetGameTime().count()) - return true; - }*/ - return false; + return m_procCooldown > now; } -void Aura::AddProcCooldown(uint32 /*msec*/) +void Aura::AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd) { - //m_procCooldown = GameTime::GetGameTime().count() + msec; + m_procCooldown = cooldownEnd; } -void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo) +void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) { bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo); if (!prepare) @@ -2225,47 +2213,101 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf ASSERT(procEntry); // cooldowns should be added to the whole aura (see 51698 area aura) - AddProcCooldown(procEntry->cooldown); + AddProcCooldown(now + procEntry->Cooldown); } -bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const +uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const { SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()); // only auras with spell proc entry can trigger proc if (!procEntry) - return false; + return 0; + + // check spell triggering us + if (Spell const* spell = eventInfo.GetProcSpell()) + { + // Do not allow auras to proc from effect triggered from itself + if (spell->IsTriggeredByAura(m_spellInfo)) + return 0; + + // check if aura can proc when spell is triggered (exception for hunter auto shot & wands) + if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK)) + if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED)) + return 0; + } + + // check don't break stealth attr present + if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH)) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) + return 0; + } // check if we have charges to proc with - if (IsUsingCharges() && !GetCharges()) - return false; + if (IsUsingCharges()) + { + if (!GetCharges()) + return 0; + + if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD) + { + if (Spell const* spell = eventInfo.GetProcSpell()) + { + if (!spell->m_appliedMods.count(const_cast(this))) + { + return 0; + } + } + } + } // check proc cooldown - if (IsProcOnCooldown()) - return false; - - // TODO: - // something about triggered spells triggering, and add extra attack effect + if (IsProcOnCooldown(now)) + return 0; // do checks against db data - if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) - return false; + if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) + return 0; // do checks using conditions table ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId()); ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget()); if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) - return false; + return 0; // AuraScript Hook bool check = const_cast(this)->CallScriptCheckProcHandlers(aurApp, eventInfo); if (!check) - return false; + return 0; + + // At least one effect has to pass checks to proc aura + uint8 procEffectMask = aurApp->GetEffectMask(); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (procEffectMask & (1 << i)) + if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo)) + procEffectMask &= ~(1 << i); + } + + if (!procEffectMask) + return 0; // TODO: // do allow additional requirements for procs // this is needed because this is the last moment in which you can prevent aura charge drop on proc // and possibly a way to prevent default checks (if there're going to be any) + // Aura added by spoell can't trigger from self (prevent drop charges/do triggers) + // But except periodic and kill triggers (can triggered from self) + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + { + if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL))) + { + return 0; + } + } + // Check if current equipment meets aura requirements // do that only for passive spells // TODO: this needs to be unified for all kinds of auras @@ -2278,7 +2320,7 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON) { if (target->ToPlayer()->IsInFeralForm()) - return false; + return 0; if (DamageInfo const* damageInfo = eventInfo.GetDamageInfo()) { @@ -2309,39 +2351,50 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI } } - return roll_chance_f(CalcProcChance(*procEntry, eventInfo)); + if (roll_chance_f(CalcProcChance(*procEntry, eventInfo))) + return procEffectMask; + + return 0; } float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const { - float chance = procEntry.chance; + float chance = procEntry.Chance; // calculate chances depending on unit with caster's data // so talents modifying chances and judgements will have properly calculated proc chance if (Unit* caster = GetCaster()) { // calculate ppm chance if present and we're using weapon - if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0) + if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0) { uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType()); - chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo()); + chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo()); } // apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance); + modOwner->ApplySpellMod(GetId(), chance); } return chance; } -void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) +void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo) { - CallScriptProcHandlers(aurApp, eventInfo); + bool prevented = CallScriptProcHandlers(aurApp, eventInfo); + + if (!prevented) + { + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (!(procEffectMask & (1 << i))) + continue; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (aurApp->HasEffect(i)) // OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc() - GetEffect(i)->HandleProc(aurApp, eventInfo); + if (aurApp->HasEffect(i)) + GetEffect(i)->HandleProc(aurApp, eventInfo); + } - CallScriptAfterProcHandlers(aurApp, eventInfo); + CallScriptAfterProcHandlers(aurApp, eventInfo); + } // Remove aura if we've used last charge to proc if (IsUsingCharges() && !GetCharges()) @@ -2637,30 +2690,14 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool result = true; - for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + for (auto & m_loadedScript : m_loadedScripts) { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); - std::list::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin(); + m_loadedScript->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); + auto hookItrEnd = m_loadedScript->DoCheckProc.end(), hookItr = m_loadedScript->DoCheckProc.begin(); for (; hookItr != hookItrEnd; ++hookItr) - result &= hookItr->Call(*scritr, eventInfo); + result &= hookItr->Call(m_loadedScript, eventInfo); - (*scritr)->_FinishScriptCall(); - } - - return result; -} - -bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) -{ - bool result = true; - for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) - { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp); - std::list::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin(); - for (; hookItr != hookItrEnd; ++hookItr) - result &= hookItr->Call(*scritr, eventInfo); - - (*scritr)->_FinishScriptCall(); + m_loadedScript->_FinishScriptCall(); } return result; @@ -2715,6 +2752,26 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI } } +bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + bool result = true; + + for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp); + std::list::iterator hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + { + if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + result &= hookItr->Call(*scritr, aurEff, eventInfo); + } + + (*scritr)->_FinishScriptCall(); + } + + return result; +} + bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool preventDefault = false; diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index d98f391dc..c33ac114d 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -191,18 +191,14 @@ public: bool CanStackWith(Aura const* checkAura, bool remove) const; bool IsAuraStronger(Aura const* newAura) const; - // Proc system - // this subsystem is not yet in use - the core of it is functional, but still some research has to be done - // and some dependant problems fixed before it can replace old proc system (for example cooldown handling) - // currently proc system functionality is implemented in Unit::ProcDamageAndSpell - bool IsProcOnCooldown() const; - void AddProcCooldown(uint32 msec); + bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const; + void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd); bool IsUsingCharges() const { return m_isUsingCharges; } void SetUsingCharges(bool val) { m_isUsingCharges = val; } - void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo); - bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; + void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now); + uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const; float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; - void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo); + void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo); // AuraScript void LoadScripts(); @@ -226,7 +222,7 @@ public: // Spell Proc Hooks bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); - bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); + bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); @@ -269,6 +265,8 @@ protected: bool m_isSingleTarget: 1; // true if it's a single target spell and registered at caster - can change at spell steal for example bool m_isUsingCharges: 1; + std::chrono::steady_clock::time_point m_procCooldown; + private: Unit::AuraApplicationList m_removedApplications; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 558cd54fc..937663428 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -640,7 +640,7 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, m_healing = 0; m_procAttacker = 0; m_procVictim = 0; - m_procEx = 0; + m_hitMask = 0; focusObject = nullptr; m_cast_count = 0; m_glyphIndex = 0; @@ -1811,7 +1811,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg { uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); + modOwner->ApplySpellMod(m_spellInfo->Id, maxTargets, this); if (maxTargets > 1) { @@ -2273,12 +2273,11 @@ void Spell::SearchChainTargets(std::list& targets, uint32 chainTar } } -void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) +void Spell::prepareDataForTriggerSystem() { //========================================================================================== // Now fill data for trigger system, need know: - // can spell trigger another or not (m_canTrigger) - // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx) + // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask) //========================================================================================== m_procVictim = m_procAttacker = 0; @@ -2317,7 +2316,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget // Because spell positivity is dependant on target } - m_procEx = PROC_EX_NONE; + m_hitMask = PROC_HIT_NONE; // Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && @@ -2326,10 +2325,11 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) m_spellInfo->SpellFamilyFlags[2] & 0x00064000)) // Explosive and Immolation Trap { m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION; - } - /* Effects which are result of aura proc from triggered spell cannot proc - to prevent chain proc of these spells */ + // also fill up other flags (DoAllEffectOnTarget only fills up flag if both are not set) + m_procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; + m_procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG; + } // Hellfire Effect - trigger as DOT if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040) @@ -2337,20 +2337,6 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) m_procAttacker = PROC_FLAG_DONE_PERIODIC; m_procVictim = PROC_FLAG_TAKEN_PERIODIC; } - - // Ranged autorepeat attack is set as triggered spell - ignore it - if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK)) - { - if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS && - (m_spellInfo->HasAttribute(SPELL_ATTR2_ACTIVE_THREAT) || - m_spellInfo->HasAttribute(SPELL_ATTR3_NOT_A_PROC))) - m_procEx |= PROC_EX_INTERNAL_CANT_PROC; - else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) - m_procEx |= PROC_EX_INTERNAL_TRIGGERED; - } - // Totem casts require spellfamilymask defined in spell_proc_event to proc - if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsTotem() && m_caster->IsControlledByPlayer()) - m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; } void Spell::CleanupTargetList() @@ -2362,6 +2348,32 @@ void Spell::CleanupTargetList() m_delayTrajectory = 0; } +class ProcReflectDelayed : public BasicEvent +{ +public: + ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { } + + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override + { + Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid); + if (!caster) + return true; + + uint32 const typeMaskActor = PROC_FLAG_NONE; + uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG; + uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL; + uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE; + uint32 const hitMask = PROC_HIT_REFLECT; + + caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr); + return true; + } + +private: + Unit* _victim; + ObjectGuid _casterGuid; +}; + void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/) { for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) @@ -2373,11 +2385,8 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; if (checkIfValid) - { - SpellCastResult res = m_spellInfo->CheckTarget(m_caster, target, implicit); - if (res != SPELL_CAST_OK) + if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE return; - } // Check for effect immune skip if immuned for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) @@ -2448,23 +2457,22 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= targetInfo.timeDelay = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f); // Calculate minimum incoming time - if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay) + if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay) m_delayMoment = targetInfo.timeDelay; } else - targetInfo.timeDelay = 0LL; + targetInfo.timeDelay = 0ULL; // If target reflect spell back to caster if (targetInfo.missCondition == SPELL_MISS_REFLECT) { // Calculate reflected spell result on caster - targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect); + targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice - if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell - targetInfo.reflectResult = SPELL_MISS_PARRY; + // Proc spell reflect aura when missile hits the original target + target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay)); // Increase time interval for reflected spells by 1.5 - m_caster->m_Events.AddEvent(new ReflectEvent(m_caster, targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay)); targetInfo.timeDelay += targetInfo.timeDelay >> 1; m_spellFlags |= SPELL_FLAG_REFLECTED; @@ -2545,7 +2553,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) if (dist < 5.0f) dist = 5.0f; target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); - if (m_delayMoment == 0 || m_delayMoment > target.timeDelay) + if (!m_delayMoment || m_delayMoment > target.timeDelay) m_delayMoment = target.timeDelay; } else @@ -2660,8 +2668,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(missInfo); - //Spells with this flag cannot trigger if effect is casted on self - bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2); + // Spells with this flag cannot trigger if effect is casted on self + bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2); bool reflectedSpell = missInfo == SPELL_MISS_REFLECT; Unit* spellHitTarget = nullptr; @@ -2699,18 +2707,14 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID) { m_needComboPoints = false; - // Restore spell mods for a miss/dodge/parry Cold Blood - // TODO: check how broad this rule should be - if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS || missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY)) - m_caster->ToPlayer()->RestoreSpellMods(this, 14177); } // Fill base trigger info uint32 procAttacker = m_procAttacker; uint32 procVictim = m_procVictim; - uint32 procEx = m_procEx; + uint32 hitMask = m_hitMask; - // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now + // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now if (canEffectTrigger && !procAttacker && !procVictim) { bool positive = true; @@ -2766,11 +2770,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (crit) { - procEx |= PROC_EX_CRITICAL_HIT; + hitMask |= PROC_HIT_CRITICAL; addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr); } else - procEx |= PROC_EX_NORMAL_HIT; + hitMask |= PROC_HIT_NORMAL; HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask()); @@ -2778,27 +2782,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (GetSpellValue()->ForcedCritResult) { crit = true; - procEx |= PROC_EX_CRITICAL_HIT; + hitMask |= PROC_HIT_CRITICAL; } int32 gain = caster->HealBySpell(healInfo, crit); unitTarget->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); m_healing = gain; - // Xinef: if heal acutally healed something, add no overheal flag - if (m_healing) - procEx |= PROC_EX_NO_OVERHEAL; - - // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) + // Do triggers for unit if (canEffectTrigger) - Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, - m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo); + caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo); } // Do damage and triggers else if (m_damage > 0) { - caster->SetLastDamagedTargetGuid(unitTarget->GetGUID()); - // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); @@ -2858,7 +2855,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (reflectedSpell) effectUnit->SendSpellNonMeleeReflectLog(&damageInfo, effectUnit); - procEx |= createProcExtendMask(&damageInfo, missInfo); + hitMask |= createProcHitMask(&damageInfo, missInfo); procVictim |= PROC_FLAG_TAKEN_DAMAGE; caster->DealSpellDamage(&damageInfo, true, this); @@ -2866,16 +2863,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // do procs after damage, eg healing effects // no need to check if target is alive, done in procdamageandspell - // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) + // Do triggers for unit if (canEffectTrigger) { - DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE); - Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, - m_triggeredByAuraSpell.effectIndex, this, &dmgInfo); + DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask); + caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &dmgInfo, nullptr); if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) - caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); + caster->ToPlayer()->CastItemCombatSpell(dmgInfo); } m_damage = damageInfo.damage; @@ -2885,19 +2881,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); - procEx |= createProcExtendMask(&damageInfo, missInfo); - // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) + hitMask |= createProcHitMask(&damageInfo, missInfo); + // Do triggers for unit if (canEffectTrigger) { - DamageInfo dmgInfo(damageInfo, NODAMAGE); - Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, - m_triggeredByAuraSpell.effectIndex, this, &dmgInfo); + DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask); + caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr); - // Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also - // Xinef: ofc count only spells that HIT the target, little hack used to fool the system - if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && - m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) - caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim | PROC_FLAG_TAKEN_DAMAGE, procEx); + if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) && + !m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) + caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo); } // Failed Pickpocket, reveal rogue @@ -3121,10 +3114,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, refreshPeriodic); - // xinef: if aura was not refreshed, add proc ex - if (!refresh) - m_procEx |= PROC_EX_NO_AURA_REFRESH; - if (m_spellAura) { // Set aura stack amount to desired value @@ -3253,8 +3242,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) // info confirmed with retail sniffs of permafrost and shadow weaving if (!m_hitTriggerSpells.empty()) { - int _duration = 0; - for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) + int32 _duration = 0; + for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) { if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { @@ -3380,7 +3369,7 @@ bool Spell::UpdateChanneledTargetList() } if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); + modOwner->ApplySpellMod(m_spellInfo->Id, range, this); // xinef: add little tolerance level range += std::min(3.0f, range * 0.1f); // 10% but no more than 3yd @@ -3543,7 +3532,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const } // Prepare data for triggers - prepareDataForTriggerSystem(triggeredByAura); + prepareDataForTriggerSystem(); // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) m_casttime = (_triggeredCastFlags & TRIGGERED_CAST_DIRECTLY) ? 0 : m_spellInfo->CalcCastTime(m_caster, this); @@ -3727,10 +3716,6 @@ void Spell::cancel(bool bySelf) if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->NeedSendSpectatorData()) ArenaSpectator::SendCommand_Spell(m_caster->FindMap(), m_caster->GetGUID(), "SPE", m_spellInfo->Id, bySelf ? 99998 : 99999); - // spell is canceled-take mods and clear list - if (Player* player = m_caster->GetSpellModOwner()) - player->RemoveSpellMods(this); - m_appliedMods.clear(); break; default: @@ -3955,26 +3940,14 @@ void Spell::_cast(bool skipCheck) } } - uint32 procEx = PROC_EX_NORMAL_HIT; + uint32 hitMask = m_hitMask; - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + if (!(hitMask & PROC_HIT_CRITICAL)) { - if (ihit->missCondition != SPELL_MISS_NONE) - { - continue; - } - - if (!ihit->crit) - { - continue; - } - - procEx |= PROC_EX_CRITICAL_HIT; - break; + hitMask |= PROC_HIT_NORMAL; } - Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo, - m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST); + m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); } if (modOwner) @@ -3995,11 +3968,6 @@ void Spell::_cast(bool skipCheck) if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true)) m_caster->ClearUnitState(UNIT_STATE_CASTING); - // remove all applied mods at this point - // dont allow user to use them twice in case spell did not reach current target - if (modOwner) - modOwner->RemoveSpellMods(this); - // Xinef: why do we keep focus after spell is sent to air? // Xinef: Because of this, in the middle of some animation after setting targetguid to 0 etc // Xinef: we get focused to it out of nowhere... @@ -4092,7 +4060,7 @@ void Spell::handle_immediate() // First mod_duration then haste - see Missile Barrage // Apply duration mod if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, duration); // Apply haste mods if (m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) @@ -4264,10 +4232,8 @@ void Spell::_handle_finish_phase() m_caster->AddComboPoints(m_comboTarget, m_comboPointGain); } - if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - { - m_caster->SetLastExtraAttackSpell(m_spellInfo->Id); - } + if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + m_caster->HandleProcExtraAttackFor(m_caster->GetVictim()); if (!IsAutoRepeat() && !IsNextMeleeSwingSpell()) if (m_caster->GetCharmerOrOwnerPlayerOrPlayerItself()) @@ -4296,25 +4262,13 @@ void Spell::_handle_finish_phase() } } - uint32 procEx = PROC_EX_NORMAL_HIT; - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + uint32 hitMask = m_hitMask; + if (!(hitMask & PROC_HIT_CRITICAL)) { - if (ihit->missCondition != SPELL_MISS_NONE) - { - continue; - } - - if (!ihit->crit) - { - continue; - } - - procEx |= PROC_EX_CRITICAL_HIT; - break; + hitMask |= PROC_HIT_NORMAL; } - Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo, - m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH); + m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr); } } @@ -4504,11 +4458,6 @@ void Spell::finish(bool ok) if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_triggeredByAuraSpell) m_caster->ToPlayer()->UpdatePotionCooldown(this); - // Take mods after trigger spell (needed for 14177 to affect 48664) - // mods are taken only on succesfull cast and independantly from targets of the spell - if (Player* player = m_caster->GetSpellModOwner()) - player->RemoveSpellMods(this); - // xinef: clear reactive auras states after spell cast if (m_spellInfo->CasterAuraState == AURA_STATE_DEFENSE || m_spellInfo->CasterAuraState == AURA_STATE_HUNTER_PARRY) m_caster->ModifyAuraState(AuraStateType(m_spellInfo->CasterAuraState), false); @@ -5293,7 +5242,7 @@ void Spell::TakePower() hit = false; //lower spell cost on fail (by talent aura) if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost, this); + modOwner->ApplySpellMod(m_spellInfo->Id, m_powerCost, this); } break; } @@ -5394,7 +5343,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID) { runeCost[i] = src->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this); + modOwner->ApplySpellMod(m_spellInfo->Id, runeCost[i], this); } runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later @@ -5434,7 +5383,7 @@ void Spell::TakeRunePower(bool didHit) { runeCost[i] = runeCostData->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this); + modOwner->ApplySpellMod(m_spellInfo->Id, runeCost[i], this); } runeCost[RUNE_DEATH] = 0; // calculated later @@ -5831,7 +5780,11 @@ SpellCastResult Spell::CheckCast(bool strict) // Xinef: do not check explicit target for triggered spell casted on self with targetflag enemy if (!m_triggeredByAuraSpell || m_targets.GetUnitTarget() != m_caster || !(m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY)) { - SpellCastResult castResult = m_spellInfo->CheckExplicitTarget((m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget()); + Unit* caster = m_caster; + if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts + caster = m_originalCaster; + + SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget()); if (castResult != SPELL_CAST_OK) return castResult; } @@ -5839,7 +5792,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (Unit* target = m_targets.GetUnitTarget()) { - SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false); + SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts if (castResult != SPELL_CAST_OK) return castResult; @@ -7035,7 +6988,7 @@ SpellCastResult Spell::CheckRange(bool strict) range_type = SPELL_RANGE_RANGED; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); + modOwner->ApplySpellMod(m_spellInfo->Id, max_range, this); // xinef: dont check max_range to strictly after cast if (range_type != SPELL_RANGE_MELEE && !strict) @@ -7749,7 +7702,7 @@ void Spell::Delayed() // only called in DealDamage() //check pushback reduce int32 delaytime = 500; // spellcasting delay is normally 500ms int32 delayReduce = 100; // must be initialized to 100 for percent modifiers - m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, delayReduce, this); delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -7787,7 +7740,7 @@ void Spell::DelayedChannel() int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit int32 delayReduce = 100; // must be initialized to 100 for percent modifiers - m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, delayReduce, this); delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -8167,14 +8120,6 @@ bool SpellEvent::IsDeletable() const return m_Spell->IsDeletable(); } -bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) -{ - Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID); - if (target && _caster->IsInMap(target)) - Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo); - return true; -} - bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const { if (target->IsAlive()) @@ -8750,26 +8695,24 @@ void Spell::PrepareTriggersExecutedOnHit() // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster // and to correctly calculate proc chance when combopoints are present Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER); - for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) + for (AuraEffect const* aurEff : targetTriggers) { - if (!(*i)->IsAffectedOnSpell(m_spellInfo)) + if (!aurEff->IsAffectedOnSpell(m_spellInfo)) continue; - SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); - uint32 auraSpellIdx = (*i)->GetEffIndex(); + + SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo(); + uint32 auraSpellIdx = aurEff->GetEffIndex(); if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell)) { // calculate the chance using spell base amount, because aura amount is not updated on combo-points change // this possibly needs fixing - int32 auraBaseAmount = (*i)->GetBaseAmount(); + int32 auraBaseAmount = aurEff->GetBaseAmount(); // proc chance is stored in effect amount int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + chance *= aurEff->GetBase()->GetStackAmount(); + // build trigger and add to the list - HitTriggerSpell spellTriggerInfo; - spellTriggerInfo.triggeredSpell = spellInfo; - spellTriggerInfo.triggeredByAura = auraSpellInfo; - spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex(); - spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); - m_hitTriggerSpells.push_back(spellTriggerInfo); + m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance); } } } @@ -8814,8 +8757,8 @@ void Spell::TriggerGlobalCooldown() if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD) { // gcd modifier auras are applied only to own spells and only players have such mods - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this); + if (Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, gcd, this); // Apply haste rating if (m_spellInfo->StartRecoveryCategory == 133 && m_spellInfo->StartRecoveryTime == 1500 && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && @@ -8824,10 +8767,7 @@ void Spell::TriggerGlobalCooldown() gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); } - if (gcd < MIN_GCD) - gcd = MIN_GCD; - else if (gcd > MAX_GCD) - gcd = MAX_GCD; + RoundToInterval(gcd, MIN_GCD, MAX_GCD); } // Only players or controlled units have global cooldown diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index f6e3e646f..a0e0410ac 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -414,7 +414,7 @@ public: void EffectCastButtons(SpellEffIndex effIndex); void EffectRechargeManaGem(SpellEffIndex effIndex); - typedef std::set UsedSpellMods; + typedef std::unordered_set UsedSpellMods; void InitExplicitTargets(SpellCastTargets const& targets); void SelectExplicitTargets(); @@ -554,6 +554,8 @@ public: bool IsAutoActionResetSpell() const; bool IsIgnoringCooldowns() const; + bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell.spellInfo); } + bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; } void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; } bool IsInterruptable() const { return !m_executedCurrently; } @@ -670,8 +672,8 @@ public: // ****************************************** uint32 m_procAttacker; // Attacker trigger flags uint32 m_procVictim; // Victim trigger flags - uint32 m_procEx; - void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura); + uint32 m_hitMask; + void prepareDataForTriggerSystem(); // ***************************************** // Spell target subsystem @@ -739,6 +741,9 @@ public: struct HitTriggerSpell { + HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) : + triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { } + SpellInfo const* triggeredSpell; SpellInfo const* triggeredByAura; uint8 triggeredByEffIdx; @@ -747,7 +752,7 @@ public: bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = nullptr) const; void PrepareTriggersExecutedOnHit(); - typedef std::list HitTriggerSpellList; + typedef std::vector HitTriggerSpellList; HitTriggerSpellList m_hitTriggerSpells; // effect helpers @@ -838,17 +843,4 @@ namespace Acore } typedef void(Spell::*pEffect)(SpellEffIndex effIndex); - -class ReflectEvent : public BasicEvent -{ - public: - ReflectEvent(Unit* caster, ObjectGuid targetGUID, SpellInfo const* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { } - bool Execute(uint64 e_time, uint32 p_time) override; - - protected: - Unit* _caster; - ObjectGuid _targetGUID; - SpellInfo const* _spellInfo; -}; - #endif diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index f3e08fc34..2d4c34a24 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -72,38 +72,38 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE), }; -enum SpellModOp +enum SpellModOp : uint8 { - SPELLMOD_DAMAGE = 0, - SPELLMOD_DURATION = 1, - SPELLMOD_THREAT = 2, - SPELLMOD_EFFECT1 = 3, - SPELLMOD_CHARGES = 4, - SPELLMOD_RANGE = 5, - SPELLMOD_RADIUS = 6, - SPELLMOD_CRITICAL_CHANCE = 7, - SPELLMOD_ALL_EFFECTS = 8, - SPELLMOD_NOT_LOSE_CASTING_TIME = 9, - SPELLMOD_CASTING_TIME = 10, - SPELLMOD_COOLDOWN = 11, - SPELLMOD_EFFECT2 = 12, - SPELLMOD_IGNORE_ARMOR = 13, - SPELLMOD_COST = 14, - SPELLMOD_CRIT_DAMAGE_BONUS = 15, - SPELLMOD_RESIST_MISS_CHANCE = 16, - SPELLMOD_JUMP_TARGETS = 17, - SPELLMOD_CHANCE_OF_SUCCESS = 18, - SPELLMOD_ACTIVATION_TIME = 19, - SPELLMOD_DAMAGE_MULTIPLIER = 20, - SPELLMOD_GLOBAL_COOLDOWN = 21, - SPELLMOD_DOT = 22, - SPELLMOD_EFFECT3 = 23, - SPELLMOD_BONUS_MULTIPLIER = 24, + SPELLMOD_DAMAGE = 0, + SPELLMOD_DURATION = 1, + SPELLMOD_THREAT = 2, + SPELLMOD_EFFECT1 = 3, + SPELLMOD_CHARGES = 4, + SPELLMOD_RANGE = 5, + SPELLMOD_RADIUS = 6, + SPELLMOD_CRITICAL_CHANCE = 7, + SPELLMOD_ALL_EFFECTS = 8, + SPELLMOD_NOT_LOSE_CASTING_TIME = 9, + SPELLMOD_CASTING_TIME = 10, + SPELLMOD_COOLDOWN = 11, + SPELLMOD_EFFECT2 = 12, + SPELLMOD_IGNORE_ARMOR = 13, + SPELLMOD_COST = 14, + SPELLMOD_CRIT_DAMAGE_BONUS = 15, + SPELLMOD_RESIST_MISS_CHANCE = 16, + SPELLMOD_JUMP_TARGETS = 17, + SPELLMOD_CHANCE_OF_SUCCESS = 18, + SPELLMOD_ACTIVATION_TIME = 19, + SPELLMOD_DAMAGE_MULTIPLIER = 20, + SPELLMOD_GLOBAL_COOLDOWN = 21, + SPELLMOD_DOT = 22, + SPELLMOD_EFFECT3 = 23, + SPELLMOD_BONUS_MULTIPLIER = 24, // spellmod 25 - SPELLMOD_PROC_PER_MINUTE = 26, - SPELLMOD_VALUE_MULTIPLIER = 27, - SPELLMOD_RESIST_DISPEL_CHANCE = 28, - SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell + SPELLMOD_PROC_PER_MINUTE = 26, + SPELLMOD_VALUE_MULTIPLIER = 27, + SPELLMOD_RESIST_DISPEL_CHANCE = 28, + SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30 }; @@ -143,7 +143,7 @@ enum TriggerCastFlags TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements - TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default) + // reuse 0x00020000 TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions TRIGGERED_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 87dbb64a6..0d544bf1f 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -310,7 +310,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); else { - DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE); + DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); uint32 absorb = dmgInfo.GetAbsorb(); uint32 resist = dmgInfo.GetResist(); @@ -2342,7 +2342,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, duration); TempSummon* summon = nullptr; @@ -3148,7 +3148,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex) int32 duration = m_spellInfo->GetDuration(); if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, duration); Player* owner = m_originalCaster->ToPlayer(); if (!owner && m_originalCaster->ToCreature()->IsTotem()) @@ -3722,6 +3722,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) { int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false, 1 << effIndex); unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), duration/*spellInfo->GetDuration()*/); + m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr); } ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id); unitTarget->InterruptSpell(CurrentSpellTypes(i), false); @@ -4682,18 +4683,17 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) - { return; - } - if (!unitTarget || !unitTarget->IsAlive()) - { + if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->GetVictim()) return; - } - unitTarget->AddExtraAttacks(damage); + if (unitTarget->m_extraAttacks) + return; - ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage); + unitTarget->m_extraAttacks = damage; + + ExecuteLogEffectExtraAttacks(effIndex, unitTarget->GetVictim(), damage); } void Spell::EffectParry(SpellEffIndex /*effIndex*/) @@ -5816,19 +5816,8 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) m_runesState = m_caster->ToPlayer()->GetRunesState(); uint32 count = damage; - if (count == 0) count = 1; - for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) - { - if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) - { - if (m_spellInfo->Id == 45529) - if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) - continue; - player->SetRuneCooldown(j, 0); - player->SetGracePeriod(j, player->IsInCombat()); // xinef: reset grace period - --count; - } - } + if (count == 0) + count = 1; // Blood Tap if (m_spellInfo->Id == 45529 && count > 0) @@ -5836,10 +5825,10 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) for (uint32 l = 0; l < MAX_RUNES && count > 0; ++l) { // Check if both runes are on cd as that is the only time when this needs to come into effect - if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB))) + if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RUNE_BLOOD)) { // Should always update the rune with the lowest cd - if (player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1)) + if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1)) l++; player->SetRuneCooldown(l, 0); player->SetGracePeriod(l, player->IsInCombat()); // xinef: reset grace period @@ -5850,6 +5839,15 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) } } + for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) + { + if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) + { + player->SetRuneCooldown(j, 0); + --count; + } + } + // Empower rune weapon if (m_spellInfo->Id == 47568) { @@ -5859,7 +5857,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) for (uint32 i = 0; i < MAX_RUNES; ++i) { - if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH)) + if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST)) { player->SetRuneCooldown(i, 0); player->SetGracePeriod(i, player->IsInCombat()); // xinef: reset grace period @@ -6061,7 +6059,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, duration); //TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; Map* map = caster->GetMap(); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index a9a73f07c..8d24dd6df 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -524,7 +524,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const { float multiplier = ValueMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell); + modOwner->ApplySpellMod(_spellInfo->Id, multiplier, spell); return multiplier; } @@ -532,7 +532,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const { float multiplier = DamageMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell); + modOwner->ApplySpellMod(_spellInfo->Id, multiplier, spell); return multiplier; } @@ -552,7 +552,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const radius += RadiusEntry->RadiusPerLevel * caster->getLevel(); radius = std::min(radius, RadiusEntry->RadiusMax); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell); + modOwner->ApplySpellMod(_spellInfo->Id, radius, spell); } return radius; @@ -831,7 +831,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry) SpellVisual = spellEntry->SpellVisual; SpellIconID = spellEntry->SpellIconID; ActiveIconID = spellEntry->ActiveIconID; - SpellPriority = spellEntry->SpellPriority; + Priority = spellEntry->SpellPriority; SpellName = spellEntry->SpellName; Rank = spellEntry->Rank; MaxTargetLevel = spellEntry->MaxTargetLevel; @@ -1268,6 +1268,26 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT; } +bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const +{ + if (!familyName) + { + return true; + } + + if (familyName != SpellFamilyName) + { + return false; + } + + if (familyFlags && !(familyFlags & SpellFamilyFlags)) + { + return false; + } + + return true; +} + bool SpellInfo::IsAffectedBySpellMods() const { return !(AttributesEx3 & SPELL_ATTR3_IGNORE_CASTER_MODIFIERS); @@ -1292,15 +1312,7 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const return true; } - // False if affect_spell == nullptr or spellFamily not equal - if (affectSpell->SpellFamilyName != SpellFamilyName) - return false; - - // true - if (mod->mask & SpellFamilyFlags) - return true; - - return false; + return IsAffected(affectSpell->SpellFamilyName, mod->mask); } bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const @@ -2311,7 +2323,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const range = RangeEntry->RangeMax[0]; if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell); + modOwner->ApplySpellMod(Id, range, spell); return range; } @@ -2446,7 +2458,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S // Apply cost mod by spell if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell); + modOwner->ApplySpellMod(Id, powerCost, spell); if (!caster->IsControlledByPlayer()) { diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index dc300600b..5b8ad7a9b 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -377,7 +377,7 @@ public: std::array SpellVisual; uint32 SpellIconID; uint32 ActiveIconID; - uint32 SpellPriority; + uint32 Priority; std::array SpellName; std::array Rank; uint32 MaxTargetLevel; @@ -463,6 +463,8 @@ public: bool IsRangedWeaponSpell() const; bool IsAutoRepeatRangedSpell() const; + bool IsAffected(uint32 familyName, flag96 const& familyFlags) const; + bool IsAffectedBySpellMods() const; bool IsAffectedBySpellMod(SpellModifier const* mod) const; diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index e9f247979..a9e80a5e1 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -171,7 +171,7 @@ void SpellMgr::LoadSpellInfoCorrections() 53232, // Rapid Killing (Rank 2) }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS; // Entries were not updated after spell effect change, we have to do that manually + spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; // Entries were not updated after spell effect change, we have to do that manually }); ApplySpellFix({ @@ -257,7 +257,7 @@ void SpellMgr::LoadSpellInfoCorrections() ApplySpellFix({ 57761 }, [](SpellInfo* spellInfo) { spellInfo->ProcCharges = 1; - spellInfo->SpellPriority = 50; + spellInfo->Priority = 50; }); // Tidal Wave @@ -272,10 +272,10 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE; }); - // Ascendance (Talisman of Ascendance trinket) - ApplySpellFix({ 28200 }, [](SpellInfo* spellInfo) + // Death and Decay + ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo) { - spellInfo->ProcCharges = 6; + spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_PHASE_SHIFT; }); // The Eye of Acherus (no spawn in phase 2 in db) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8d9524bf5..866a1a7b1 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -727,166 +727,6 @@ void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpe availableElixirs.insert(itr->first); // insert spell id } -SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const -{ - SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); - if (itr != mSpellProcEventMap.end()) - return &itr->second; - return nullptr; -} - -bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const -{ - // No extra req need - uint32 procEvent_procEx = PROC_EX_NONE; - uint32 procEvent_procPhase = PROC_SPELL_PHASE_HIT; - - uint32 procFlags = eventInfo.GetTypeMask(); - uint32 procExtra = eventInfo.GetHitMask(); - uint32 procPhase = eventInfo.GetSpellPhaseMask(); - SpellInfo const* procSpellInfo = eventInfo.GetSpellInfo(); - - // check prockFlags for condition - if ((procFlags & EventProcFlag) == 0) - return false; - - // Xinef: Always trigger for this, including TAKEN_DAMAGE - if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH | PROC_FLAG_TAKEN_DAMAGE)) - return true; - - bool hasFamilyMask = false; - - if (procFlags & PROC_FLAG_DONE_PERIODIC) - { - if (procExtra & PROC_EX_INTERNAL_HOT) - { - if (EventProcFlag == PROC_FLAG_DONE_PERIODIC) - { - /// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT. - if (!spellProto->SpellFamilyName) - return false; - } - /// Aura must have positive procflags for a HOT to proc - else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS))) - return false; - } - /// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc - else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC) - if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION))) - return false; - } - - if (procFlags & PROC_FLAG_TAKEN_PERIODIC) - { - if (procExtra & PROC_EX_INTERNAL_HOT) - { - /// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT. - if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC) - return false; - /// Aura must have positive procflags for a HOT to proc - if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS))) - return false; - } - /// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc - else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC) - if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG))) - return false; - } - - // Trap casts are active by default - if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) - active = true; - - if (spellProcEvent) // Exist event data - { - // Store extra req - procEvent_procEx = spellProcEvent->procEx; - procEvent_procPhase = spellProcEvent->procPhase; - - // For melee triggers - if (!procSpellInfo) - { - // Check (if set) for school (melee attack have Normal school) - if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) - return false; - } - else // For spells need check school/spell family/family mask - { - // Check (if set) for school - if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpellInfo->SchoolMask) == 0) - return false; - - // Check (if set) for spellFamilyName - if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpellInfo->SpellFamilyName)) - return false; - - // spellFamilyName is Ok need check for spellFamilyMask if present - if (spellProcEvent->spellFamilyMask) - { - if (!(spellProcEvent->spellFamilyMask & procSpellInfo->SpellFamilyFlags)) - return false; - hasFamilyMask = true; - // Some spells are not considered as active even with have spellfamilyflags - if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)) - active = true; - } - - // Check tick numbers - if (procEvent_procEx & PROC_EX_ONLY_FIRST_TICK) - { - if (Spell const* procSpell = eventInfo.GetProcSpell()) - { - if (procSpell->GetTriggeredByAuraTickNumber() > 1) - { - return false; - } - } - } - } - } - - if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY)) - { - if (!hasFamilyMask) - return false; - } - - if (!(procEvent_procPhase & procPhase)) - { - return false; - } - - // Check for extra req (if none) and hit/crit - if (procEvent_procEx == PROC_EX_NONE) - { - // No extra req, so can trigger only for hit/crit - spell has to be active - if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active) - return true; - } - else // Passive spells hits here only if resist/reflect/immune/evade - { - if (procExtra & AURA_SPELL_PROC_EX_MASK) - { - // if spell marked as procing only from not active spells - if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL) - return false; - // if spell marked as procing only from active spells - if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL) - return false; - // Exist req for PROC_EX_EX_TRIGGER_ALWAYS - if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS) - return true; - // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before - if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0)) - return true; - } - // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other) - if (procEvent_procEx & procExtra) - return true; - } - return false; -} - SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const { SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId); @@ -895,54 +735,78 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const return nullptr; } -bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const +bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) { // proc type doesn't match - if (!(eventInfo.GetTypeMask() & procEntry.typeMask)) + if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags)) return false; // check XP or honor target requirement - if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) + if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) if (Player* actor = eventInfo.GetActor()->ToPlayer()) if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget())) return false; + // check mana requirement + if (procEntry.AttributesMask & PROC_ATTR_REQ_MANA_COST) + if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo()) + if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage) + return false; + // always trigger for these types if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH)) return true; + // do triggered cast checks + // Do not consider autoattacks as triggered spells + if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK)) + { + if (Spell const* spell = eventInfo.GetProcSpell()) + { + if (spell->IsTriggered()) + { + SpellInfo const* spellInfo = spell->GetSpellInfo(); + if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) && + !spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC)) + return false; + } + } + } + // check school mask (if set) for other trigger types - if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask)) + if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask)) return false; // check spell family name/flags (if set) for spells - if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION)) + if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK)) { - if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName)) - return false; - - if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags)) - return false; + if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo()) + { + if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask)) + { + return false; + } + } } // check spell type mask (if set) if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)) { - if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask)) + if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask)) return false; } // check spell phase mask if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK) { - if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask)) + if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask)) return false; } // check hit mask (on taken hit or on done hit, but not on spell cast phase) if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST))) { - uint32 hitMask = procEntry.hitMask; + uint32 hitMask = procEntry.HitMask; // get default values if hit mask not set if (!hitMask) { @@ -1733,111 +1597,17 @@ void SpellMgr::LoadSpellGroupStackRules() LOG_INFO("server.loading", " "); } -void SpellMgr::LoadSpellProcEvents() -{ - uint32 oldMSTime = getMSTime(); - - mSpellProcEventMap.clear(); // need for reload case - - // 0 1 2 3 4 5 6 7 8 9 10 11 - QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, procPhase, ppmRate, CustomChance, Cooldown FROM spell_proc_event"); - if (!result) - { - LOG_WARN("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty."); - return; - } - - uint32 count = 0; - - do - { - Field* fields = result->Fetch(); - - int32 spellId = fields[0].Get(); - - bool allRanks = false; - if (spellId < 0) - { - allRanks = true; - spellId = -spellId; - } - - SpellInfo const* spellInfo = GetSpellInfo(spellId); - if (!spellInfo) - { - LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` does not exist", spellId); - continue; - } - - if (allRanks) - { - if (!spellInfo->IsRanked()) - LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId); - - if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) - { - LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` is not first rank of spell.", spellId); - continue; - } - } - - SpellProcEventEntry spellProcEvent; - - spellProcEvent.schoolMask = fields[1].Get(); - spellProcEvent.spellFamilyName = fields[2].Get(); - spellProcEvent.spellFamilyMask[0] = fields[3].Get(); - spellProcEvent.spellFamilyMask[1] = fields[4].Get(); - spellProcEvent.spellFamilyMask[2] = fields[5].Get(); - spellProcEvent.procFlags = fields[6].Get(); - spellProcEvent.procEx = fields[7].Get(); - spellProcEvent.procPhase = fields[8].Get(); - spellProcEvent.ppmRate = fields[9].Get(); - spellProcEvent.customChance = fields[10].Get(); - spellProcEvent.cooldown = fields[11].Get(); - - // PROC_SPELL_PHASE_NONE is by default PROC_SPELL_PHASE_HIT - if (spellProcEvent.procPhase == PROC_SPELL_PHASE_NONE) - { - spellProcEvent.procPhase = PROC_SPELL_PHASE_HIT; - } - - while (spellInfo) - { - if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end()) - { - LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id); - break; - } - - if (!spellInfo->ProcFlags && !spellProcEvent.procFlags) - LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` probally not triggered spell", spellInfo->Id); - - mSpellProcEventMap[spellInfo->Id] = spellProcEvent; - - if (allRanks) - spellInfo = spellInfo->GetNextRankSpell(); - else - break; - } - - ++count; - } while (result->NextRow()); - - LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); - LOG_INFO("server.loading", " "); -} - void SpellMgr::LoadSpellProcs() { uint32 oldMSTime = getMSTime(); mSpellProcMap.clear(); // need for reload case - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc"); if (!result) { - LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty."); + LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty."); LOG_INFO("server.loading", " "); return; } @@ -1874,21 +1644,20 @@ void SpellMgr::LoadSpellProcs() SpellProcEntry baseProcEntry; - baseProcEntry.schoolMask = fields[1].Get(); - baseProcEntry.spellFamilyName = fields[2].Get(); - baseProcEntry.spellFamilyMask[0] = fields[3].Get(); - baseProcEntry.spellFamilyMask[1] = fields[4].Get(); - baseProcEntry.spellFamilyMask[2] = fields[5].Get(); - baseProcEntry.typeMask = fields[6].Get(); - baseProcEntry.spellTypeMask = fields[7].Get(); - baseProcEntry.spellPhaseMask = fields[8].Get(); - baseProcEntry.hitMask = fields[9].Get(); - baseProcEntry.attributesMask = fields[10].Get(); - baseProcEntry.ratePerMinute = fields[11].Get(); - baseProcEntry.chance = fields[12].Get(); - float cooldown = fields[13].Get(); - baseProcEntry.cooldown = uint32(cooldown); - baseProcEntry.charges = fields[14].Get(); + baseProcEntry.SchoolMask = fields[1].Get(); + baseProcEntry.SpellFamilyName = fields[2].Get(); + baseProcEntry.SpellFamilyMask[0] = fields[3].Get(); + baseProcEntry.SpellFamilyMask[1] = fields[4].Get(); + baseProcEntry.SpellFamilyMask[2] = fields[5].Get(); + baseProcEntry.ProcFlags = fields[6].Get(); + baseProcEntry.SpellTypeMask = fields[7].Get(); + baseProcEntry.SpellPhaseMask = fields[8].Get(); + baseProcEntry.HitMask = fields[9].Get(); + baseProcEntry.AttributesMask = fields[10].Get(); + baseProcEntry.ProcsPerMinute = fields[11].Get(); + baseProcEntry.Chance = fields[12].Get(); + baseProcEntry.Cooldown = Milliseconds(fields[13].Get()); + baseProcEntry.Charges = fields[14].Get(); while (spellInfo) { @@ -1900,56 +1669,54 @@ void SpellMgr::LoadSpellProcs() SpellProcEntry procEntry = SpellProcEntry(baseProcEntry); // take defaults from dbcs - if (!procEntry.typeMask) - procEntry.typeMask = spellInfo->ProcFlags; - if (!procEntry.charges) - procEntry.charges = spellInfo->ProcCharges; - if (!procEntry.chance && !procEntry.ratePerMinute) - procEntry.chance = float(spellInfo->ProcChance); + if (!procEntry.ProcFlags) + procEntry.ProcFlags = spellInfo->ProcFlags; + if (!procEntry.Charges) + procEntry.Charges = spellInfo->ProcCharges; + if (!procEntry.Chance && !procEntry.ProcsPerMinute) + procEntry.Chance = float(spellInfo->ProcChance); // validate data - if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask); - if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16)) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName); - if (procEntry.chance < 0) + if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask); + if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16)) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName); + if (procEntry.Chance < 0) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId); - procEntry.chance = 0; + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId); + procEntry.Chance = 0; } - if (procEntry.ratePerMinute < 0) + if (procEntry.ProcsPerMinute < 0) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId); - procEntry.ratePerMinute = 0; + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId); + procEntry.ProcsPerMinute = 0; } - if (cooldown < 0) + if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId); + if (procEntry.Charges > 99) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId); - procEntry.cooldown = 0; + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId); + procEntry.Charges = 99; } - if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId); - if (procEntry.charges > 99) - { - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId); - procEntry.charges = 99; - } - if (!procEntry.typeMask) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId); - if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask); - if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId); - if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId); - if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask); - if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId); - if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask); - if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) - LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId); + if (!procEntry.ProcFlags) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId); + if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask); + if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId); + if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId); + if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask); + if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId); + if (procEntry.HitMask & ~PROC_HIT_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask); + if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) + LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura()) + LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has Attribute PROC_ATTR_DISABLE_EFF_{}, but effect {} is not an aura effect", spellInfo->Id, static_cast(i), static_cast(i)); mSpellProcMap[spellInfo->Id] = procEntry; @@ -1961,8 +1728,175 @@ void SpellMgr::LoadSpellProcs() ++count; } while (result->NextRow()); - LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); + + // Define can trigger auras + bool isTriggerAura[TOTAL_AURAS]; + // Triggered always, even from triggered spells + bool isAlwaysTriggeredAura[TOTAL_AURAS]; + // SpellTypeMask to add to the proc + uint32 spellTypeMask[TOTAL_AURAS]; + + // List of auras that CAN trigger but may not exist in spell_proc + // in most cases needed to drop charges + + // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check) + // see AuraEffect::CheckEffectProc + for (uint16 i = 0; i < TOTAL_AURAS; ++i) + { + isTriggerAura[i] = false; + isAlwaysTriggeredAura[i] = false; + spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL; + } + + isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311) + isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets" + isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus + isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger + isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; + isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; + isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; + isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; + isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger + isTriggerAura[SPELL_AURA_MOD_ROOT] = true; + isTriggerAura[SPELL_AURA_TRANSFORM] = true; + isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; + isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true; + isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true; + isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true; + isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true; + isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true; + isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true; + isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true; + isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true; + isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; + isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true; + isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true; + isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true; + isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; + isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true; + isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true; + isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true; + isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true; + + isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true; + isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true; + + spellTypeMask[SPELL_AURA_MOD_STEALTH] = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL; + spellTypeMask[SPELL_AURA_MOD_CONFUSE] = PROC_SPELL_TYPE_DAMAGE; + spellTypeMask[SPELL_AURA_MOD_FEAR] = PROC_SPELL_TYPE_DAMAGE; + spellTypeMask[SPELL_AURA_MOD_ROOT] = PROC_SPELL_TYPE_DAMAGE; + spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE; + spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE; + + // This generates default procs to retain compatibility with previous proc system + LOG_INFO("server.loading", "Generating spell proc data from SpellMap..."); + count = 0; + oldMSTime = getMSTime(); + + for (SpellInfo const* spellInfo : mSpellInfoMap) + { + if (!spellInfo) + continue; + + // Data already present in DB, overwrites default proc + if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end()) + continue; + + // Nothing to do if no flags set + if (!spellInfo->ProcFlags) + continue; + + bool addTriggerFlag = false; + uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (!spellInfo->Effects[i].IsEffect()) + continue; + + uint32 auraName = spellInfo->Effects[i].ApplyAuraName; + if (!auraName) + continue; + + if (!isTriggerAura[auraName]) + continue; + + procSpellTypeMask |= spellTypeMask[auraName]; + + if (isAlwaysTriggeredAura[auraName]) + addTriggerFlag = true; + + // many proc auras with taken procFlag mask don't have attribute "can proc with triggered" + // they should proc nevertheless (example mage armor spells with judgement) + if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0) + { + switch (auraName) + { + case SPELL_AURA_PROC_TRIGGER_SPELL: + case SPELL_AURA_PROC_TRIGGER_DAMAGE: + addTriggerFlag = true; + break; + default: + break; + } + } + + break; + } + + if (!procSpellTypeMask) + continue; + + SpellProcEntry procEntry; + procEntry.SchoolMask = 0; + procEntry.ProcFlags = spellInfo->ProcFlags; + procEntry.SpellFamilyName = 0; + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (spellInfo->Effects[i].IsEffect() && isTriggerAura[spellInfo->Effects[i].ApplyAuraName]) + procEntry.SpellFamilyMask |= spellInfo->Effects[i].SpellClassMask; + + if (procEntry.SpellFamilyMask) + procEntry.SpellFamilyName = spellInfo->SpellFamilyName; + + procEntry.SpellTypeMask = procSpellTypeMask; + procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT; + procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent + + // Reflect auras should only proc off reflects + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL)) + { + procEntry.HitMask = PROC_HIT_REFLECT; + break; + } + } + + procEntry.AttributesMask = 0; + if (spellInfo->ProcFlags & PROC_FLAG_KILL) + procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR; + if (addTriggerFlag) + procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC; + + procEntry.ProcsPerMinute = 0; + procEntry.Chance = spellInfo->ProcChance; + procEntry.Cooldown = Milliseconds::zero(); + procEntry.Charges = spellInfo->ProcCharges; + + mSpellProcMap[spellInfo->Id] = procEntry; + ++count; + } + + LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SpellMgr::LoadSpellBonuses() diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index d02342f11..c1bfb1d5f 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -154,13 +154,15 @@ enum ProcFlags | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS, SPELL_PROC_FLAG_MASK = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS + | PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS - | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, + | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG + | PROC_FLAG_DONE_TRAP_ACTIVATION, - SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION | RANGED_PROC_FLAG_MASK, + SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION, PERIODIC_PROC_FLAG_MASK = PROC_FLAG_DONE_PERIODIC | PROC_FLAG_TAKEN_PERIODIC, @@ -168,7 +170,8 @@ enum ProcFlags | PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG - | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK, + | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_TRAP_ACTIVATION + | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK, TAKEN_HIT_PROC_FLAG_MASK = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS @@ -188,46 +191,6 @@ enum ProcFlags PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS) -enum ProcFlagsExLegacy -{ - PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag) - PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells) - PROC_EX_CRITICAL_HIT = 0x0000002, - PROC_EX_MISS = 0x0000004, - PROC_EX_RESIST = 0x0000008, - PROC_EX_DODGE = 0x0000010, - PROC_EX_PARRY = 0x0000020, - PROC_EX_BLOCK = 0x0000040, - PROC_EX_EVADE = 0x0000080, - PROC_EX_IMMUNE = 0x0000100, - PROC_EX_DEFLECT = 0x0000200, - PROC_EX_ABSORB = 0x0000400, - PROC_EX_REFLECT = 0x0000800, - PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) - PROC_EX_FULL_BLOCK = 0x0002000, // block all attack damage - PROC_EX_RESERVED2 = 0x0004000, - PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc - PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result - PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet) - PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc - PROC_EX_NO_OVERHEAL = 0x0080000, // Proc if heal did some work - PROC_EX_NO_AURA_REFRESH = 0x0100000, // Proc if aura was not refreshed - PROC_EX_ONLY_FIRST_TICK = 0x0200000, // Proc only on first tick (in case of periodic spells) - - // Flags for internal use - do not use these in db! - PROC_EX_INTERNAL_CANT_PROC = 0x0800000, - PROC_EX_INTERNAL_DOT = 0x1000000, - PROC_EX_INTERNAL_HOT = 0x2000000, - PROC_EX_INTERNAL_TRIGGERED = 0x4000000, - PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 -}; - -#define AURA_SPELL_PROC_EX_MASK \ - (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \ - PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \ - PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \ - PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT) - enum ProcFlagsSpellType { PROC_SPELL_TYPE_NONE = 0x0000000, @@ -261,45 +224,37 @@ enum ProcFlagsHit PROC_HIT_DEFLECT = 0x0000200, PROC_HIT_ABSORB = 0x0000400, // partial or full absorb PROC_HIT_REFLECT = 0x0000800, - PROC_HIT_INTERRUPT = 0x0001000, // (not used atm) + PROC_HIT_INTERRUPT = 0x0001000, PROC_HIT_FULL_BLOCK = 0x0002000, - PROC_HIT_MASK_ALL = 0x2FFF, + PROC_HIT_MASK_ALL = 0x0002FFF, }; enum ProcAttributes { - PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010, -}; + PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc + PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells + PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc + PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges -struct SpellProcEventEntry -{ - uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2 - uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value - flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do) - uint32 procFlags; // bitmask for matching proc event - uint32 procEx; // proc Extend info (see ProcFlagsEx) - uint32 procPhase; // proc phase (see ProcFlagsSpellPhase) - float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc - float customChance; // Owerride chance (in most cases for debug only) - uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_ + PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC + PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere + PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed }; -typedef std::unordered_map SpellProcEventMap; - struct SpellProcEntry { - uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school - uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName - flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags - uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags - uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType - uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase - uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit - uint32 attributesMask; // bitmask, see ProcAttributes - float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 - float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set - uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura - uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite + uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school + uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName + flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags + uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags + uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType + uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase + uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit + uint32 AttributesMask; // bitmask, see ProcAttributes + float ProcsPerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 + float Chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set + Milliseconds Cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura + uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite }; typedef std::unordered_map SpellProcMap; @@ -669,13 +624,9 @@ public: SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const; void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set& availableElixirs) const; - // Spell proc event table - [[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const; - bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const; - // Spell proc table [[nodiscard]] SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; - bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; + static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo); // Spell bonus data table [[nodiscard]] SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; @@ -750,7 +701,6 @@ public: void LoadSpellTargetPositions(); void LoadSpellGroups(); void LoadSpellGroupStackRules(); - void LoadSpellProcEvents(); void LoadSpellProcs(); void LoadSpellBonuses(); void LoadSpellThreats(); @@ -779,7 +729,6 @@ private: SpellTargetPositionMap mSpellTargetPositions; SpellGroupMap mSpellGroupMap; SpellGroupStackMap mSpellGroupStackMap; - SpellProcEventMap mSpellProcEventMap; SpellProcMap mSpellProcMap; SpellBonusMap mSpellBonusMap; SpellThreatMap mSpellThreatMap; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 4842cede7..c44c5460a 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -733,6 +733,9 @@ bool AuraScript::_Validate(SpellInfo const* entry) if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); + for (std::list::iterator itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr) + if (!itr->GetAffectedEffectsMask(entry)) + LOG_ERROR("spells.scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString(), m_scriptName->c_str()); for (std::list::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr) if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); @@ -906,6 +909,17 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e return (auraScript->*_HandlerScript)(eventInfo); } +AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) + : AuraScript::EffectBase(effIndex, effName) +{ + _HandlerScript = handlerScript; +} + +bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) +{ + return (auraScript->*_HandlerScript)(aurEff, eventInfo); +} + AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript) { _HandlerScript = handlerScript; @@ -1167,6 +1181,7 @@ Unit* AuraScript::GetTarget() const case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD: case AURA_SCRIPT_HOOK_EFFECT_SPLIT: case AURA_SCRIPT_HOOK_CHECK_PROC: + case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC: case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC: case AURA_SCRIPT_HOOK_PREPARE_PROC: case AURA_SCRIPT_HOOK_PROC: diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index b52d2215b..54b8d009b 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -499,6 +499,7 @@ enum AuraScriptHookType AURA_SCRIPT_HOOK_AFTER_DISPEL, // Spell Proc Hooks AURA_SCRIPT_HOOK_CHECK_PROC, + AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, AURA_SCRIPT_HOOK_PREPARE_PROC, AURA_SCRIPT_HOOK_PROC, @@ -529,7 +530,8 @@ public: typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const*, SpellModifier* &); \ typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \ typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \ - typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \ + typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \ + typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \ typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \ typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \ @@ -639,6 +641,14 @@ public: private: AuraCheckProcFnType _HandlerScript; }; + class CheckEffectProcHandler : public EffectBase + { + public: + CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName); + bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo); + private: + AuraCheckEffectProcFnType _HandlerScript; + }; class AuraProcHandler { public: @@ -668,8 +678,9 @@ public: class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) {} }; \ - class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \ - class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \ + class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \ + class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \ + class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \ class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) {} }; \ #define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) @@ -811,6 +822,12 @@ public: HookList DoCheckAfterProc; #define AuraCheckProcFn(F) CheckProcHandlerFunction(&F) + // executed when aura effect checks if it can proc the aura + // example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo); + HookList DoCheckEffectProc; +#define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N) + // executed before aura procs (possibility to prevent charge drop/cooldown) // example: DoPrepareProc += AuraProcFn(class::function); // where function is: void function (ProcEventInfo& eventInfo); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a178af405..abfc1078f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1663,10 +1663,7 @@ void World::SetInitialWorldSettings() LOG_INFO("server.loading", "Loading Spell Learn Skills..."); sSpellMgr->LoadSpellLearnSkills(); // must be after LoadSpellRanks - LOG_INFO("server.loading", "Loading Spell Proc Event Conditions..."); - sSpellMgr->LoadSpellProcEvents(); - - LOG_INFO("server.loading", "Loading Spell Proc Conditions and Data..."); + LOG_INFO("server.loading", "Loading Spell Proc conditions and data..."); sSpellMgr->LoadSpellProcs(); LOG_INFO("server.loading", "Loading Spell Bonus Data..."); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 2fee7b3b6..948e18956 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -154,7 +154,6 @@ public: { "spell_loot_template", HandleReloadLootTemplatesSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_linked_spell", HandleReloadSpellLinkedSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_pet_auras", HandleReloadSpellPetAurasCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "spell_proc_event", HandleReloadSpellProcEventCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_proc", HandleReloadSpellProcsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_scripts", HandleReloadSpellScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_target_position", HandleReloadSpellTargetPositionCommand, SEC_ADMINISTRATOR, Console::Yes }, @@ -296,7 +295,6 @@ public: HandleReloadSpellAreaCommand(handler); HandleReloadSpellGroupsCommand(handler); HandleReloadSpellLinkedSpellCommand(handler); - HandleReloadSpellProcEventCommand(handler); HandleReloadSpellProcsCommand(handler); HandleReloadSpellBonusesCommand(handler); HandleReloadSpellTargetPositionCommand(handler); @@ -853,14 +851,6 @@ public: return true; } - static bool HandleReloadSpellProcEventCommand(ChatHandler* handler) - { - LOG_INFO("server.loading", "Re-Loading Spell Proc Event conditions..."); - sSpellMgr->LoadSpellProcEvents(); - handler->SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); - return true; - } - static bool HandleReloadSpellProcsCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Re-Loading Spell Proc conditions and data..."); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp index a87452598..55088fa48 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp @@ -17,17 +17,19 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "hyjal.h" #include "hyjal_trash.h" enum Spells { - SPELL_CARRION_SWARM = 31306, - SPELL_SLEEP = 31298, - SPELL_VAMPIRIC_AURA = 38196, - SPELL_INFERNO = 31299, - SPELL_IMMOLATION = 31303, - SPELL_INFERNO_EFFECT = 31302, + SPELL_CARRION_SWARM = 31306, + SPELL_SLEEP = 31298, + SPELL_VAMPIRIC_AURA = 38196, + SPELL_VAMPIRIC_AURA_HEAL = 31285, + SPELL_INFERNO = 31299, + SPELL_IMMOLATION = 31303, + SPELL_INFERNO_EFFECT = 31302 }; enum Texts @@ -265,8 +267,48 @@ public: }; }; +class spell_anetheron_vampiric_aura : public SpellScriptLoader +{ +public: + spell_anetheron_vampiric_aura() : SpellScriptLoader("spell_anetheron_vampiric_aura") { } + + class spell_anetheron_vampiric_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_anetheron_vampiric_aura_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_VAMPIRIC_AURA_HEAL)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 bp = damageInfo->GetDamage() * 3; + eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_anetheron_vampiric_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_anetheron_vampiric_aura_AuraScript(); + } +}; + void AddSC_boss_anetheron() { new boss_anetheron(); new npc_towering_infernal(); + new spell_anetheron_vampiric_aura(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index ec53af7ec..0aaf508bd 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -857,7 +857,7 @@ public: resilienceReduction = damage - resilienceReduction; damage -= resilienceReduction; uint32 mitigated_damage = resilienceReduction; - DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, mitigated_damage); + DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); Unit::DealDamageMods(plr, damage, &absorb); int32 overkill = damage - plr->GetHealth(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index 508653c07..d7f428db7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -1589,6 +1589,26 @@ public: { return new spell_taldaram_ball_of_inferno_flame_SpellScript(); } + + class spell_taldaram_ball_of_inferno_flame_AuraScript : public AuraScript + { + PrepareAuraScript(spell_taldaram_ball_of_inferno_flame_AuraScript); + + void HandleStackDrop(ProcEventInfo& /*eventInfo*/) + { + ModStackAmount(-1); + } + + void Register() override + { + OnProc += AuraProcFn(spell_taldaram_ball_of_inferno_flame_AuraScript::HandleStackDrop); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_taldaram_ball_of_inferno_flame_AuraScript(); + } }; class spell_valanar_kinetic_bomb : public SpellScriptLoader diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 86bc01d41..24bb93381 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1061,7 +1061,7 @@ public: { DamageInfo* damageInfo = eventInfo.GetDamageInfo(); SpellInfo const* procSpell = eventInfo.GetSpellInfo(); - return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion + return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion } void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) @@ -1115,7 +1115,7 @@ public: { DamageInfo* damageInfo = eventInfo.GetDamageInfo(); SpellInfo const* procSpell = eventInfo.GetSpellInfo(); - return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion + return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion } void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) @@ -1404,6 +1404,41 @@ public: } }; +// 72176 - Blood Beast's Blood Link +class spell_deathbringer_blood_beast_blood_link : public SpellScriptLoader +{ +public: + spell_deathbringer_blood_beast_blood_link() : SpellScriptLoader("spell_deathbringer_blood_beast_blood_link") { } + + class spell_deathbringer_blood_beast_blood_link_AuraScript : public AuraScript + { + PrepareAuraScript(spell_deathbringer_blood_beast_blood_link_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_BLOOD_LINK_DUMMY)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetProcTarget()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 3, (Unit*)nullptr, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_deathbringer_blood_beast_blood_link_AuraScript(); + } +}; + void AddSC_boss_deathbringer_saurfang() { new boss_deathbringer_saurfang(); @@ -1418,4 +1453,5 @@ void AddSC_boss_deathbringer_saurfang() new spell_deathbringer_boiling_blood(); new achievement_ive_gone_and_made_a_mess(); new npc_icc_blood_beast(); + new spell_deathbringer_blood_beast_blood_link(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 7e31e8550..6f8165d53 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1076,9 +1076,23 @@ public: caster->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, caster, false);*/ } + void HandleProc(ProcEventInfo& eventInfo) + { + uint32 stack = GetStackAmount(); + Unit* caster = eventInfo.GetActor(); + + int32 const mod = caster->GetMap()->Is25ManRaid() ? 1500 : 1250; + int32 dmg = 0; + for (uint8 i = 1; i <= stack; ++i) + dmg += mod * i; + + caster->CastCustomSpell(SPELL_EXPUNGED_GAS, SPELLVALUE_BASE_POINT0, dmg); + } + void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_gaseous_bloat_AuraScript::HandleExtraEffect, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + OnProc += AuraProcFn(spell_putricide_gaseous_bloat_AuraScript::HandleProc); } }; @@ -1707,6 +1721,45 @@ public: } }; +// 71770 - Ooze Spell Tank Protection +class spell_putricide_ooze_tank_protection : public SpellScriptLoader +{ +public: + spell_putricide_ooze_tank_protection() : SpellScriptLoader("spell_putricide_ooze_tank_protection") { } + + class spell_putricide_ooze_tank_protection_AuraScript : public AuraScript + { + PrepareAuraScript(spell_putricide_ooze_tank_protection_AuraScript); + + bool Validate(SpellInfo const* spellInfo) override + { + if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell) || + !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].TriggerSpell)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* actionTarget = eventInfo.GetActionTarget(); + actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_putricide_ooze_tank_protection_AuraScript(); + } +}; + void AddSC_boss_professor_putricide() { new boss_professor_putricide(); @@ -1731,4 +1784,5 @@ void AddSC_boss_professor_putricide() new spell_putricide_mutated_transformation_dmg(); new spell_putricide_eat_ooze(); new spell_putricide_regurgitated_ooze(); + new spell_putricide_ooze_tank_protection(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index b581decfc..625a96eea 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -952,7 +952,7 @@ public: } else { - Unit::DealHeal(me, me, me->CountPctFromMaxHealth(3)); + me->ModifyHealth(me->CountPctFromMaxHealth(5)); _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); } break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp index 21d21e3d7..d2c74139b 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -2987,6 +2987,8 @@ public: void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); if (!damageInfo || !damageInfo->GetDamage()) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp index 0664944a8..3f17f3048 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp @@ -89,6 +89,57 @@ public: }; }; +enum SecondWind +{ + SPELL_SECOND_WIND_TRIGGER = 42771 +}; + +// 42770 - Second Wind +class spell_uk_second_wind : public SpellScriptLoader +{ +public: + spell_uk_second_wind() : SpellScriptLoader("spell_uk_second_wind") { } + + class spell_uk_second_wind_AuraScript : public AuraScript + { + PrepareAuraScript(spell_uk_second_wind_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SECOND_WIND_TRIGGER)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActionTarget(); + caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_uk_second_wind_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_uk_second_wind_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_uk_second_wind_AuraScript(); + } +}; + enum EnslavedProtoDrake { TYPE_PROTODRAKE_AT = 28, @@ -247,4 +298,5 @@ void AddSC_utgarde_keep() new npc_enslaved_proto_drake(); new spell_ticking_time_bomb(); + new spell_uk_second_wind(); } diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp new file mode 100644 index 000000000..32fbe4d55 --- /dev/null +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ScriptMgr.h" +#include "SpellMgr.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Unit.h" + +enum Spells +{ + SPELL_MARK_OF_MALICE_TRIGGERED = 33494 +}; + +// 33493 - Mark of Malice +class spell_mark_of_malice : public AuraScript +{ + PrepareAuraScript(spell_mark_of_malice); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MARK_OF_MALICE_TRIGGERED }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + // just drop charges + if (aurEff->GetBase()->GetCharges() > 1) + return; + + GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mark_of_malice::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +void AddSC_shadow_labyrinth() +{ + RegisterSpellScript(spell_mark_of_malice); +} diff --git a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp index 24145c39b..0046dc91d 100644 --- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp +++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp @@ -33,16 +33,17 @@ enum Texts enum Spells { - SPELL_SHADOW_VOLLEY = 32963, - SPELL_CLEAVE = 31779, - SPELL_THUNDERCLAP = 36706, - SPELL_VOID_BOLT = 39329, - SPELL_MARK_OF_KAZZAK = 32960, - SPELL_MARK_OF_KAZZAK_DAMAGE = 32961, - SPELL_ENRAGE = 32964, - SPELL_CAPTURE_SOUL = 32966, - SPELL_TWISTED_REFLECTION = 21063, - SPELL_BERSERK = 32965, + SPELL_SHADOW_VOLLEY = 32963, + SPELL_CLEAVE = 31779, + SPELL_THUNDERCLAP = 36706, + SPELL_VOID_BOLT = 39329, + SPELL_MARK_OF_KAZZAK = 32960, + SPELL_MARK_OF_KAZZAK_DAMAGE = 32961, + SPELL_ENRAGE = 32964, + SPELL_CAPTURE_SOUL = 32966, + SPELL_TWISTED_REFLECTION = 21063, + SPELL_TWISTED_REFLECTION_HEAL = 21064, + SPELL_BERSERK = 32965, }; enum Events @@ -219,8 +220,47 @@ public: } }; +class spell_twisted_reflection : public SpellScriptLoader +{ +public: + spell_twisted_reflection() : SpellScriptLoader("spell_twisted_reflection") { } + + class spell_twisted_reflection_AuraScript : public AuraScript + { + PrepareAuraScript(spell_twisted_reflection_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_TWISTED_REFLECTION_HEAL)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_twisted_reflection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_twisted_reflection_AuraScript(); + } +}; + void AddSC_boss_doomlordkazzak() { new boss_doomlord_kazzak(); new spell_mark_of_kazzak(); + new spell_twisted_reflection(); } diff --git a/src/server/scripts/Outland/outland_script_loader.cpp b/src/server/scripts/Outland/outland_script_loader.cpp index df02e86d3..255252585 100644 --- a/src/server/scripts/Outland/outland_script_loader.cpp +++ b/src/server/scripts/Outland/outland_script_loader.cpp @@ -29,6 +29,7 @@ void AddSC_boss_ambassador_hellmaw(); void AddSC_boss_blackheart_the_inciter(); void AddSC_boss_grandmaster_vorpil(); void AddSC_boss_murmur(); +void AddSC_shadow_labyrinth(); void AddSC_boss_illidan(); //Black Temple void AddSC_boss_shade_of_akama(); void AddSC_boss_supremus(); @@ -122,6 +123,7 @@ void AddOutlandScripts() AddSC_boss_blackheart_the_inciter(); AddSC_boss_grandmaster_vorpil(); AddSC_boss_murmur(); + AddSC_shadow_labyrinth(); AddSC_boss_illidan(); //Black Temple AddSC_boss_shade_of_akama(); AddSC_boss_supremus(); diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 2533462a5..6e44ce98a 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -21,7 +21,11 @@ */ #include "ScriptMgr.h" +#include "CreatureAIImpl.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "TemporarySummon.h" enum HunterSpells { @@ -32,6 +36,26 @@ enum HunterSpells SPELL_HUNTER_PET_SCALING = 62915 }; +enum HunterCreatures +{ + NPC_HUNTER_VIPER = 19921 +}; + +enum PetSpellsMisc +{ + SPELL_PET_GUARD_DOG_HAPPINESS = 54445, + SPELL_PET_SILVERBACK_RANK_1 = 62800, + SPELL_PET_SILVERBACK_RANK_2 = 62801, + + SPELL_PET_SWOOP = 52825, + SPELL_PET_CHARGE = 61685, + + PET_ICON_ID_GROWL = 201, + PET_ICON_ID_CLAW = 262, + PET_ICON_ID_BITE = 1680, + PET_ICON_ID_SMACK = 473 +}; + struct npc_pet_hunter_snake_trap : public ScriptedAI { npc_pet_hunter_snake_trap(Creature* creature) : ScriptedAI(creature) { _init = false; } @@ -138,7 +162,156 @@ private: uint32 _spellTimer; }; +// 57627 - Charge +class spell_pet_charge : public AuraScript +{ + PrepareAuraScript(spell_pet_charge); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PET_SWOOP, + SPELL_PET_CHARGE + }); + } + + void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + // Remove +% AP aura + Unit* pet = eventInfo.GetActor(); + Aura* aura = pet->GetAura(SPELL_PET_SWOOP, pet->GetGUID()); + if (!aura) + aura = pet->GetAura(SPELL_PET_CHARGE, pet->GetGUID()); + + if (!aura) + return; + + aura->DropCharge(AURA_REMOVE_BY_EXPIRE); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pet_charge::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -53178 - Guard Dog +class spell_pet_guard_dog : public AuraScript +{ + PrepareAuraScript(spell_pet_guard_dog); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + // Growl shares family flags with other spells + // filter by spellIcon instead + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL) + return false; + + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true); + + float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); + eventInfo.GetProcTarget()->AddThreat(caster, addThreat); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pet_guard_dog::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pet_guard_dog::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -62764 - Silverback +class spell_pet_silverback : public AuraScript +{ + PrepareAuraScript(spell_pet_silverback); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + // Growl shares family flags with other spells + // filter by spellIcon instead + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL) + return false; + + return true; + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 }; + + PreventDefaultAction(); + + uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pet_silverback::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pet_silverback::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -61680 - Culling the Herd +class spell_pet_culling_the_herd : public AuraScript +{ + PrepareAuraScript(spell_pet_culling_the_herd); + + bool CheckProc(ProcEventInfo& eventInfo) + { + // Claw, Bite and Smack share FamilyFlags with other spells + // filter by spellIcon instead + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + switch (spellInfo->SpellIconID) + { + case PET_ICON_ID_CLAW: + case PET_ICON_ID_BITE: + case PET_ICON_ID_SMACK: + break; + default: + return false; + } + + return true; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pet_culling_the_herd::CheckProc); + } +}; + void AddSC_hunter_pet_scripts() { RegisterCreatureAI(npc_pet_hunter_snake_trap); + RegisterSpellScript(spell_pet_charge); + RegisterSpellScript(spell_pet_guard_dog); + RegisterSpellScript(spell_pet_silverback); + RegisterSpellScript(spell_pet_culling_the_herd); } diff --git a/src/server/scripts/Pet/pet_priest.cpp b/src/server/scripts/Pet/pet_priest.cpp index 1f6b2f964..732943444 100644 --- a/src/server/scripts/Pet/pet_priest.cpp +++ b/src/server/scripts/Pet/pet_priest.cpp @@ -29,7 +29,7 @@ enum PriestSpells { SPELL_PRIEST_GLYPH_OF_SHADOWFIEND = 58228, - SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227, + SPELL_PRIEST_SHADOWFIEND_DEATH = 57989, SPELL_PRIEST_SHADOWFIEND_DODGE = 8273, SPELL_PRIEST_LIGHTWELL_CHARGES = 59907 }; @@ -67,12 +67,10 @@ struct npc_pet_pri_shadowfiend : public PetAI AttackStart(target); } - void JustDied(Unit* /*killer*/) override + void IsSummonedBy(Unit* summoner) override { - if (me->IsSummon()) - if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) - if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) - owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true); + if (summoner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) + DoCastAOE(SPELL_PRIEST_SHADOWFIEND_DEATH); } }; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 88ed7bec2..1648ca722 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -33,6 +33,13 @@ enum DeathKnightSpells { + SPELL_DK_ACCLIMATION_HOLY = 50490, + SPELL_DK_ACCLIMATION_FIRE = 50362, + SPELL_DK_ACCLIMATION_FROST = 50485, + SPELL_DK_ACCLIMATION_ARCANE = 50486, + SPELL_DK_ACCLIMATION_SHADOW = 50489, + SPELL_DK_ACCLIMATION_NATURE = 50488, + SPELL_DK_ADVANTAGE_T10_4P_MELEE = 70657, SPELL_DK_DEATH_AND_DECAY_TRIGGER = 52212, SPELL_DK_GLYPH_OF_SCOURGE_STRIKE = 58642, SPELL_DK_WANDERING_PLAGUE_TRIGGER = 50526, @@ -59,6 +66,7 @@ enum DeathKnightSpells SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365, SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_R1 = 50391, + SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL = 50475, SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED = 63611, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622, SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962, @@ -72,7 +80,23 @@ enum DeathKnightSpells SPELL_DK_UNHOLY_PRESENCE = 48265, SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772, SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, - SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284 + SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, + SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT = 69961, + SPELL_DK_BUTCHERY_RUNIC_POWER = 50163, + SPELL_DK_MARK_OF_BLOOD_HEAL = 61607, + SPELL_DK_UNHOLY_BLIGHT_DAMAGE = 50536, + SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT = 63332, + SPELL_DK_VENDETTA_HEAL = 50181, + SPELL_DK_NECROSIS_DAMAGE = 51460, + SPELL_DK_OBLITERATE_OFF_HAND_R1 = 66198, + SPELL_DK_FROST_STRIKE_OFF_HAND_R1 = 66196, + SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1 = 66216, + SPELL_DK_DEATH_STRIKE_OFF_HAND_R1 = 66188, + SPELL_DK_RUNE_STRIKE_OFF_HAND_R1 = 66217, + SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 = 66215, + SPELL_DK_RUNIC_RETURN = 61258, + SPELL_DK_WANDERING_PLAGUE_DAMAGE = 50526, + SPELL_DK_DEATH_COIL_R1 = 47541, }; enum DeathKnightSpellIcons @@ -82,7 +106,130 @@ enum DeathKnightSpellIcons enum Misc { - NPC_DK_GHOUL = 26125 + NPC_DK_GHOUL = 26125, + NPC_DK_DANCING_RUNE_WEAPON = 27893, + SPELL_CATEGORY_HOWLING_BLAST = 1248 +}; + +// -49200 - Acclimation +class spell_dk_acclimation : public AuraScript +{ + PrepareAuraScript(spell_dk_acclimation); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_HOLY) || + !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FIRE) || + !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FROST) || + !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_NATURE) || + !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_SHADOW) || + !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_ARCANE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetDamageInfo()) + { + switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) + { + case SPELL_SCHOOL_HOLY: + case SPELL_SCHOOL_FIRE: + case SPELL_SCHOOL_NATURE: + case SPELL_SCHOOL_FROST: + case SPELL_SCHOOL_SHADOW: + case SPELL_SCHOOL_ARCANE: + return true; + default: + break; + } + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + uint32 triggerspell = 0; + + switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) + { + case SPELL_SCHOOL_HOLY: + triggerspell = SPELL_DK_ACCLIMATION_HOLY; + break; + case SPELL_SCHOOL_FIRE: + triggerspell = SPELL_DK_ACCLIMATION_FIRE; + break; + case SPELL_SCHOOL_NATURE: + triggerspell = SPELL_DK_ACCLIMATION_NATURE; + break; + case SPELL_SCHOOL_FROST: + triggerspell = SPELL_DK_ACCLIMATION_FROST; + break; + case SPELL_SCHOOL_SHADOW: + triggerspell = SPELL_DK_ACCLIMATION_SHADOW; + break; + case SPELL_SCHOOL_ARCANE: + triggerspell = SPELL_DK_ACCLIMATION_ARCANE; + break; + default: + return; + } + + if (Unit* target = eventInfo.GetActionTarget()) + { + target->CastSpell(target, triggerspell, true, nullptr, aurEff); + } + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dk_acclimation::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dk_acclimation::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 70656 - Advantage (T10 4P Melee Bonus) +class spell_dk_advantage_t10_4p : public AuraScript +{ + PrepareAuraScript(spell_dk_advantage_t10_4p); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_ADVANTAGE_T10_4P_MELEE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (Unit* caster = eventInfo.GetActor()) + { + if (caster->GetTypeId() != TYPEID_PLAYER || caster->getClass() != CLASS_DEATH_KNIGHT) + { + return false; + } + + for (uint8 i = 0; i < MAX_RUNES; ++i) + { + if (caster->ToPlayer()->GetRuneCooldown(i) == 0) + { + return false; + } + } + + return true; + } + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dk_advantage_t10_4p::CheckProc); + } }; // 50526 - Wandering Plague @@ -438,19 +585,38 @@ class spell_dk_summon_gargoyle : public SpellScript } }; -// 63611 - Improved Blood Presence +// 63611 - Improved Blood Presence Triggered class spell_dk_improved_blood_presence_proc : public AuraScript { PrepareAuraScript(spell_dk_improved_blood_presence_proc); + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL)) + return false; + return true; + } + bool CheckProc(ProcEventInfo& eventInfo) { - return eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage(); + if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER) + return true; + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo()) + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL, SPELLVALUE_BASE_POINT0, CalculatePct(int32(dmgInfo->GetDamage()), aurEff->GetAmount()), + eventInfo.GetActor(), true, nullptr, aurEff); } void Register() override { DoCheckProc += AuraCheckProcFn(spell_dk_improved_blood_presence_proc::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dk_improved_blood_presence_proc::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -693,7 +859,7 @@ class spell_dk_scent_of_blood_trigger : public AuraScript bool CheckProc(ProcEventInfo& eventInfo) { - return (eventInfo.GetHitMask() & (PROC_EX_DODGE | PROC_EX_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage()); + return (eventInfo.GetHitMask() & (PROC_HIT_DODGE | PROC_HIT_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage()); } void Register() override @@ -2135,8 +2301,287 @@ class spell_dk_will_of_the_necropolis : public AuraScript } }; +// -49182 - Blade Barrier +class spell_dk_blade_barrier : public AuraScript +{ + PrepareAuraScript(spell_dk_blade_barrier); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetSpellInfo() != nullptr) + if (Player* player = eventInfo.GetActor()->ToPlayer()) + if (player->getClass() == CLASS_DEATH_KNIGHT && player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dk_blade_barrier::CheckProc); + } +}; + +// -48979 - Butchery +class spell_dk_butchery : public AuraScript +{ + PrepareAuraScript(spell_dk_butchery); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_BUTCHERY_RUNIC_POWER }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_butchery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 58642 - Glyph of Scourge Strike +class spell_dk_glyph_of_scourge_strike : public AuraScript +{ + PrepareAuraScript(spell_dk_glyph_of_scourge_strike); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_glyph_of_scourge_strike::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 61257 - Runic Power Back on Snare/Root +class spell_dk_pvp_4p_bonus : public AuraScript +{ + PrepareAuraScript(spell_dk_pvp_4p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_RUNIC_RETURN }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0; + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dk_pvp_4p_bonus::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dk_pvp_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 49005 - Mark of Blood +class spell_dk_mark_of_blood : public AuraScript +{ + PrepareAuraScript(spell_dk_mark_of_blood); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_MARK_OF_BLOOD_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_mark_of_blood::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -51459 - Necrosis +class spell_dk_necrosis : public AuraScript +{ + PrepareAuraScript(spell_dk_necrosis); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_NECROSIS_DAMAGE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_necrosis::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -49018 - Sudden Doom +class spell_dk_sudden_doom : public AuraScript +{ + PrepareAuraScript(spell_dk_sudden_doom); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_DEATH_COIL_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DK_DEATH_COIL_R1); + uint32 spellId = 0; + + while (spellInfo) + { + if (!caster->HasSpell(spellInfo->Id)) + break; + + spellId = spellInfo->Id; + spellInfo = spellInfo->GetNextRankSpell(); + } + + if (!spellId) + return; + + caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_sudden_doom::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -65661 Threat of Thassarian +class spell_dk_threat_of_thassarian : public AuraScript +{ + PrepareAuraScript(spell_dk_threat_of_thassarian); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DK_OBLITERATE_OFF_HAND_R1, + SPELL_DK_FROST_STRIKE_OFF_HAND_R1, + SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1, + SPELL_DK_DEATH_STRIKE_OFF_HAND_R1, + SPELL_DK_RUNE_STRIKE_OFF_HAND_R1, + SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + if (!roll_chance_i(aurEff->GetAmount())) + return; + + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + // Must dual wield + Unit* caster = eventInfo.GetActor(); + if (!caster->haveOffhandWeapon()) + return; + + uint32 spellId = 0; + // Plague Strike + if (spellInfo->SpellFamilyFlags[0] & 0x00000001) + spellId = SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1; + // Death Strike + else if (spellInfo->SpellFamilyFlags[0] & 0x00000010) + spellId = SPELL_DK_DEATH_STRIKE_OFF_HAND_R1; + // Blood Strike + else if (spellInfo->SpellFamilyFlags[0] & 0x00400000) + spellId = SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1; + // Frost Strike + else if (spellInfo->SpellFamilyFlags[1] & 0x00000004) + spellId = SPELL_DK_FROST_STRIKE_OFF_HAND_R1; + // Obliterate + else if (spellInfo->SpellFamilyFlags[1] & 0x00020000) + spellId = SPELL_DK_OBLITERATE_OFF_HAND_R1; + // Rune Strike + else if (spellInfo->SpellFamilyFlags[1] & 0x20000000) + spellId = SPELL_DK_RUNE_STRIKE_OFF_HAND_R1; + + if (!spellId) + return; + + spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank()); + caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_threat_of_thassarian::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -49015 - Vendetta +class spell_dk_vendetta : public AuraScript +{ + PrepareAuraScript(spell_dk_vendetta); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DK_VENDETTA_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dk_vendetta::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + void AddSC_deathknight_spell_scripts() { + RegisterSpellScript(spell_dk_acclimation); + RegisterSpellScript(spell_dk_advantage_t10_4p); RegisterSpellScript(spell_dk_wandering_plague); RegisterSpellScript(spell_dk_raise_ally); RegisterSpellScript(spell_dk_raise_ally_trigger); @@ -2181,4 +2626,13 @@ void AddSC_deathknight_spell_scripts() RegisterSpellScript(spell_dk_spell_deflection); RegisterSpellScript(spell_dk_vampiric_blood); RegisterSpellScript(spell_dk_will_of_the_necropolis); + RegisterSpellScript(spell_dk_blade_barrier); + RegisterSpellScript(spell_dk_butchery); + RegisterSpellScript(spell_dk_glyph_of_scourge_strike); + RegisterSpellScript(spell_dk_pvp_4p_bonus); + RegisterSpellScript(spell_dk_mark_of_blood); + RegisterSpellScript(spell_dk_necrosis); + RegisterSpellScript(spell_dk_sudden_doom); + RegisterSpellScript(spell_dk_threat_of_thassarian); + RegisterSpellScript(spell_dk_vendetta); } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index d7f697a33..4e286aa5b 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -55,12 +55,45 @@ enum DruidSpells SPELL_DRUID_SURVIVAL_INSTINCTS = 50322, SPELL_DRUID_SAVAGE_ROAR = 62071, SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178, + SPELL_DRUID_T9_FERAL_RELIC_BEAR = 67354, + SPELL_DRUID_T9_FERAL_RELIC_CAT = 67355, SPELL_DRUID_ITEM_T8_BALANCE_RELIC = 64950, SPELL_DRUID_BEAR_FORM_PASSIVE = 1178, SPELL_DRUID_DIRE_BEAR_FORM_PASSIVE = 9635, + SPELL_DRUID_FORMS_TRINKET_BEAR = 37340, + SPELL_DRUID_FORMS_TRINKET_CAT = 37341, + SPELL_DRUID_FORMS_TRINKET_MOONKIN = 37343, + SPELL_DRUID_FORMS_TRINKET_NONE = 37344, + SPELL_DRUID_FORMS_TRINKET_TREE = 37342, SPELL_DRUID_ENRAGE = 5229, SPELL_DRUID_ENRAGED_DEFENSE = 70725, SPELL_DRUID_ITEM_T10_FERAL_4P_BONUS = 70726, + SPELL_DRUID_T3_PROC_ENERGIZE_MANA = 28722, + SPELL_DRUID_T3_PROC_ENERGIZE_RAGE = 28723, + SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY = 28724, + SPELL_DRUID_BLESSING_OF_THE_CLAW = 28750, + SPELL_DRUID_REVITALIZE_ENERGIZE_MANA = 48542, + SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE = 48541, + SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY = 48540, + SPELL_DRUID_REVITALIZE_ENERGIZE_RP = 48543, + SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN = 54833, + SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT = 54846, + SPELL_DRUID_GLYPH_OF_RIP = 54818, + SPELL_DRUID_RIP_DURATION_LACERATE_DMG = 60141, + SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED = 54820, + SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1 = 34297, + SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL = 34299, + SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA = 68285, + SPELL_DRUID_EXHILARATE = 28742, + SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL = 54755, + SPELL_DRUID_INFUSION = 37238, + SPELL_DRUID_BLESSING_OF_REMULOS = 40445, + SPELL_DRUID_BLESSING_OF_ELUNE = 40446, + SPELL_DRUID_BLESSING_OF_CENARIUS = 40452, + SPELL_DRUID_LANGUISH = 71023, + SPELL_DRUID_REJUVENATION_T10_PROC = 70691, + SPELL_DRUID_BALANCE_T10_BONUS = 70718, + SPELL_DRUID_BALANCE_T10_BONUS_PROC = 70721 }; // 1178 - Bear Form (Passive) @@ -239,7 +272,7 @@ class spell_dru_brambles_treant : public AuraScript { int32 amount = 0; if (player->HasAura(SPELL_DRUID_BARKSKIN, player->GetGUID())) - player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount); + player->ApplySpellMod(SPELL_DRUID_BARKSKIN, amount); return roll_chance_i(amount); } @@ -254,7 +287,7 @@ class spell_dru_brambles_treant : public AuraScript if (GetUnitOwner()->IsSummon()) if (Unit* owner = GetUnitOwner()->ToTempSummon()->GetSummonerUnit()) if (Player* player = owner->GetSpellModOwner()) - player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount); + player->ApplySpellMod(SPELL_DRUID_BARKSKIN, amount); } void Register() override @@ -445,6 +478,80 @@ class spell_dru_enrage : public AuraScript } }; +// 37336 - Druid Forms Trinket +class spell_dru_forms_trinket : public AuraScript +{ + PrepareAuraScript(spell_dru_forms_trinket); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_BEAR) || + !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_CAT) || + !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_MOONKIN) || + !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_NONE) || + !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_TREE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Unit* target = eventInfo.GetActor(); + + switch (target->GetShapeshiftForm()) + { + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_CAT: + case FORM_MOONKIN: + case FORM_NONE: + case FORM_TREE: + return true; + default: + break; + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* target = eventInfo.GetActor(); + uint32 triggerspell = 0; + + switch (target->GetShapeshiftForm()) + { + case FORM_BEAR: + case FORM_DIREBEAR: + triggerspell = SPELL_DRUID_FORMS_TRINKET_BEAR; + break; + case FORM_CAT: + triggerspell = SPELL_DRUID_FORMS_TRINKET_CAT; + break; + case FORM_MOONKIN: + triggerspell = SPELL_DRUID_FORMS_TRINKET_MOONKIN; + break; + case FORM_NONE: + triggerspell = SPELL_DRUID_FORMS_TRINKET_NONE; + break; + case FORM_TREE: + triggerspell = SPELL_DRUID_FORMS_TRINKET_TREE; + break; + default: + return; + } + + target->CastSpell(target, triggerspell, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_forms_trinket::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_forms_trinket::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 54846 - Glyph of Starfire class spell_dru_glyph_of_starfire : public SpellScript { @@ -797,35 +904,27 @@ class spell_dru_rip : public AuraScript } }; -// 62606 - Savage Defense +// 62600 - Savage Defense class spell_dru_savage_defense : public AuraScript { PrepareAuraScript(spell_dru_savage_defense); - uint32 absorbPct; - - bool Load() override + bool Validate(SpellInfo const* spellInfo) override { - absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); - return true; + return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); } - void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { - // Set absorbtion amount to unlimited - amount = -1; - } - - void Absorb(AuraEffect* aurEff, DamageInfo& /*dmgInfo*/, uint32& absorbAmount) - { - absorbAmount = uint32(CalculatePct(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct)); - aurEff->SetAmount(0); + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + int32 amount = static_cast(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount())); + caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); } void Register() override { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_savage_defense::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_dru_savage_defense::Absorb, EFFECT_0); + OnEffectProc += AuraEffectProcFn(spell_dru_savage_defense::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -1033,6 +1132,66 @@ class spell_dru_typhoon : public SpellScript } }; +// 67353 - T9 Feral Relic (Idol of Mutilation) +class spell_dru_t9_feral_relic : public AuraScript +{ + PrepareAuraScript(spell_dru_t9_feral_relic); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_BEAR) || + !sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_CAT)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Unit* target = eventInfo.GetActor(); + + switch (target->GetShapeshiftForm()) + { + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_CAT: + return true; + default: + break; + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + uint32 triggerspell = 0; + + Unit* target = eventInfo.GetActor(); + + switch (target->GetShapeshiftForm()) + { + case FORM_BEAR: + case FORM_DIREBEAR: + triggerspell = SPELL_DRUID_T9_FERAL_RELIC_BEAR; + break; + case FORM_CAT: + triggerspell = SPELL_DRUID_T9_FERAL_RELIC_CAT; + break; + default: + return; + } + + target->CastSpell(target, triggerspell, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_t9_feral_relic::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_t9_feral_relic::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 70691 - Rejuvenation class spell_dru_t10_restoration_4p_bonus : public SpellScript { @@ -1150,6 +1309,441 @@ class spell_dru_berserk : public SpellScript } }; +// 54832 - Glyph of Innervate +class spell_dru_glyph_of_innervate : public AuraScript +{ + PrepareAuraScript(spell_dru_glyph_of_innervate); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN); + int32 amount = CalculatePct(static_cast(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount()); + amount /= spellInfo->GetMaxTicks(); + + caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_innervate::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 54821 - Glyph of Rake +class spell_dru_glyph_of_rake : public AuraScript +{ + PrepareAuraScript(spell_dru_glyph_of_rake); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget()->GetTypeId() == TYPEID_UNIT; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rake::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rake::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 54754 - Glyph of Rejuvenation +class spell_dru_glyph_of_rejuvenation : public AuraScript +{ + PrepareAuraScript(spell_dru_glyph_of_rejuvenation); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget()->HealthBelowPct(50); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rejuvenation::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rejuvenation::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 54815 - Glyph of Shred +class spell_dru_glyph_of_shred : public AuraScript +{ + PrepareAuraScript(spell_dru_glyph_of_shred); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DRUID_GLYPH_OF_RIP, + SPELL_DRUID_RIP_DURATION_LACERATE_DMG + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + // try to find spell Rip on the target + if (AuraEffect const* rip = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, caster->GetGUID())) + { + // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip + uint32 countMin = rip->GetBase()->GetMaxDuration(); + + // just Rip's max duration without other spells + uint32 countMax = rip->GetSpellInfo()->GetMaxDuration(); + + // add possible auras' and Glyph of Shred's max duration + countMax += 3 * aurEff->GetAmount() * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds + countMax += caster->HasAura(SPELL_DRUID_GLYPH_OF_RIP) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds + countMax += caster->HasAura(SPELL_DRUID_RIP_DURATION_LACERATE_DMG) ? 4 * IN_MILLISECONDS : 0; // T7 set bonus -> +4 seconds + + // if min < max -> that means caster didn't cast 3 shred yet + // so set Rip's duration and max duration + if (countMin < countMax) + { + rip->GetBase()->SetDuration(rip->GetBase()->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS); + rip->GetBase()->SetMaxDuration(countMin + aurEff->GetAmount() * IN_MILLISECONDS); + } + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_shred::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 54845 - Glyph of Starfire +class spell_dru_glyph_of_starfire_dummy : public AuraScript +{ + PrepareAuraScript(spell_dru_glyph_of_starfire_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_starfire_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -48539 - Revitalize +class spell_dru_revitalize : public AuraScript +{ + PrepareAuraScript(spell_dru_revitalize); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DRUID_REVITALIZE_ENERGIZE_MANA, + SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE, + SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY, + SPELL_DRUID_REVITALIZE_ENERGIZE_RP + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (!roll_chance_i(aurEff->GetAmount())) + return; + + Unit* target = eventInfo.GetProcTarget(); + uint32 spellId; + + switch (target->getPowerType()) + { + case POWER_MANA: + spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_MANA; + break; + case POWER_RAGE: + spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE; + break; + case POWER_ENERGY: + spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY; + break; + case POWER_RUNIC_POWER: + spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RP; + break; + default: + return; + } + + eventInfo.GetActor()->CastSpell(target, spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_revitalize::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + } +}; + +// 28716 - Rejuvenation +class spell_dru_t3_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_dru_t3_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DRUID_T3_PROC_ENERGIZE_MANA, + SPELL_DRUID_T3_PROC_ENERGIZE_RAGE, + SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY + }); + } + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + if (!roll_chance_i(50)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* target = eventInfo.GetProcTarget(); + uint32 spellId; + + switch (target->getPowerType()) + { + case POWER_MANA: + spellId = SPELL_DRUID_T3_PROC_ENERGIZE_MANA; + break; + case POWER_RAGE: + spellId = SPELL_DRUID_T3_PROC_ENERGIZE_RAGE; + break; + case POWER_ENERGY: + spellId = SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY; + break; + default: + return; + } + + eventInfo.GetActor()->CastSpell(target, spellId, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_t3_2p_bonus::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_t3_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + } +}; + +// 28744 - Regrowth +class spell_dru_t3_6p_bonus : public AuraScript +{ + PrepareAuraScript(spell_dru_t3_6p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_BLESSING_OF_THE_CLAW }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + } +}; + +// 28719 - Healing Touch +class spell_dru_t3_8p_bonus : public AuraScript +{ + PrepareAuraScript(spell_dru_t3_8p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_EXHILARATE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + Unit* caster = eventInfo.GetActor(); + int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_t3_8p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 37288 - Mana Restore +// 37295 - Mana Restore +class spell_dru_t4_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_dru_t4_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_INFUSION }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 40442 - Druid Tier 6 Trinket +class spell_dru_item_t6_trinket : public AuraScript +{ + PrepareAuraScript(spell_dru_item_t6_trinket); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DRUID_BLESSING_OF_REMULOS, + SPELL_DRUID_BLESSING_OF_ELUNE, + SPELL_DRUID_BLESSING_OF_CENARIUS + }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + uint32 spellId; + int32 chance; + + // Starfire + if (spellInfo->SpellFamilyFlags[0] & 0x00000004) + { + spellId = SPELL_DRUID_BLESSING_OF_REMULOS; + chance = 25; + } + // Rejuvenation + else if (spellInfo->SpellFamilyFlags[0] & 0x00000010) + { + spellId = SPELL_DRUID_BLESSING_OF_ELUNE; + chance = 25; + } + // Mangle (Bear) and Mangle (Cat) + else if (spellInfo->SpellFamilyFlags[1] & 0x00000440) + { + spellId = SPELL_DRUID_BLESSING_OF_CENARIUS; + chance = 40; + } else + return; + + if (roll_chance_i(chance)) + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_dru_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 70664 - Druid T10 Restoration 4P Bonus (Rejuvenation) +class spell_dru_t10_restoration_4p_bonus_dummy : public AuraScript +{ + PrepareAuraScript(spell_dru_t10_restoration_4p_bonus_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DRUID_REJUVENATION_T10_PROC }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->Id == SPELL_DRUID_REJUVENATION_T10_PROC) + return false; + + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return false; + + Player* caster = eventInfo.GetActor()->ToPlayer(); + if (!caster) + return false; + + return caster->GetGroup() || caster != eventInfo.GetProcTarget(); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 amount = static_cast(eventInfo.GetHealInfo()->GetHeal()); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_dru_t10_restoration_4p_bonus_dummy::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dru_t10_restoration_4p_bonus_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 24905 - Moonkin Form (Passive) class spell_dru_moonkin_form_passive_proc : public AuraScript { @@ -1184,6 +1778,7 @@ void AddSC_druid_spell_scripts() RegisterSpellScript(spell_dru_berserk); RegisterSpellScript(spell_dru_dash); RegisterSpellScript(spell_dru_enrage); + RegisterSpellScript(spell_dru_forms_trinket); RegisterSpellScript(spell_dru_glyph_of_starfire); RegisterSpellScript(spell_dru_idol_lifebloom); RegisterSpellScript(spell_dru_innervate); @@ -1204,7 +1799,20 @@ void AddSC_druid_spell_scripts() RegisterSpellScript(spell_dru_swift_flight_passive); RegisterSpellScript(spell_dru_tiger_s_fury); RegisterSpellScript(spell_dru_typhoon); + RegisterSpellScript(spell_dru_t9_feral_relic); RegisterSpellScript(spell_dru_t10_restoration_4p_bonus); RegisterSpellScript(spell_dru_wild_growth); + RegisterSpellScript(spell_dru_glyph_of_innervate); + RegisterSpellScript(spell_dru_glyph_of_rake); + RegisterSpellScript(spell_dru_glyph_of_rejuvenation); + RegisterSpellScript(spell_dru_glyph_of_shred); + RegisterSpellScript(spell_dru_glyph_of_starfire_dummy); + RegisterSpellScript(spell_dru_revitalize); + RegisterSpellScript(spell_dru_t3_2p_bonus); + RegisterSpellScript(spell_dru_t3_6p_bonus); + RegisterSpellScript(spell_dru_t3_8p_bonus); + RegisterSpellScript(spell_dru_t4_2p_bonus); + RegisterSpellScript(spell_dru_item_t6_trinket); + RegisterSpellScript(spell_dru_t10_restoration_4p_bonus_dummy); RegisterSpellScript(spell_dru_moonkin_form_passive_proc); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 7e16ae4f6..b01f9ad21 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -848,8 +848,7 @@ class spell_gen_fixate_aura : public AuraScript } }; -/* 64440 - Blade Warding - 64568 - Blood Reserve */ +// 64440 - Blade Warding class spell_gen_proc_above_75 : public AuraScript { PrepareAuraScript(spell_gen_proc_above_75); @@ -3634,6 +3633,53 @@ class spell_gen_bandage : public SpellScript } }; +// Blood Reserve - 64568 +enum BloodReserve +{ + SPELL_GEN_BLOOD_RESERVE_AURA = 64568, + SPELL_GEN_BLOOD_RESERVE_HEAL = 64569 +}; + +class spell_gen_blood_reserve : public AuraScript +{ + PrepareAuraScript(spell_gen_blood_reserve); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_GEN_BLOOD_RESERVE_HEAL)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (Unit* caster = eventInfo.GetActionTarget()) + { + if (caster->HealthBelowPct(35)) + { + return true; + } + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActionTarget(); + caster->CastCustomSpell(SPELL_GEN_BLOOD_RESERVE_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), caster, TRIGGERED_FULL_MASK, nullptr, aurEff); + caster->RemoveAura(SPELL_GEN_BLOOD_RESERVE_AURA); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_gen_blood_reserve::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_gen_blood_reserve::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + enum ParalyticPoison { SPELL_PARALYSIS = 35202 diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index bead12996..df6c63631 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -61,15 +61,25 @@ enum HunterSpells SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711, SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED = 54045, + SPELL_HUNTER_PIERCING_SHOTS = 63468, SPELL_HUNTER_READINESS = 23989, SPELL_HUNTER_SNIPER_TRAINING_R1 = 53302, SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 = 64418, + SPELL_HUNTER_T9_4P_GREATNESS = 68130, SPELL_HUNTER_VICIOUS_VIPER = 61609, SPELL_HUNTER_VIPER_ATTACK_SPEED = 60144, SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543, SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389, SPELL_LOCK_AND_LOAD_TRIGGER = 56453, - SPELL_LOCK_AND_LOAD_MARKER = 67544 + SPELL_LOCK_AND_LOAD_MARKER = 67544, + SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER = 56453, + SPELL_HUNTER_LOCK_AND_LOAD_MARKER = 67544, + SPELL_HUNTER_KILL_COMMAND_HUNTER = 34027, + SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA = 34720, + SPELL_REPLENISHMENT = 57669, + SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1 = 56654, + SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 = 58882, + SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS = 57894 }; class spell_hun_check_pet_los : public SpellScript @@ -416,7 +426,7 @@ class spell_hun_ascpect_of_the_viper : public AuraScript } }; -// 53209 Chimera Shot +// 53209 - Chimera Shot class spell_hun_chimera_shot : public SpellScript { PrepareSpellScript(spell_hun_chimera_shot); @@ -433,8 +443,8 @@ class spell_hun_chimera_shot : public SpellScript { uint32 spellId = 0; int32 basePoint = 0; - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) + Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) { Aura* aura = i->second->GetBase(); if (aura->GetCasterGUID() != caster->GetGUID()) @@ -444,53 +454,47 @@ class spell_hun_chimera_shot : public SpellScript flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags; if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) continue; - if (AuraEffect* aurEff = aura->GetEffect(0)) + if (AuraEffect const* aurEff = aura->GetEffect(EFFECT_0)) { // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. if (familyFlag[0] & 0x4000) { - int32 TickCount = aurEff->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; - basePoint = aurEff->GetAmount(); - ApplyPct(basePoint, TickCount * 40); - basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); + + // calculate damage of basic tick (bonuses are already factored in AuraEffect) + basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks(); + ApplyPct(basePoint, 40); } - // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. + // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. else if (familyFlag[1] & 0x00000080) { - int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER; - // Amount of one aura tick - basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount())); - int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; // TODO: Caster uses unitTarget? - if (basePoint > casterBasePoint) - basePoint = casterBasePoint; - ApplyPct(basePoint, TickCount * 60); + // % of mana drained in max duration + basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks(); + + // max value + int32 maxManaReturn = CalculatePct(static_cast(caster->GetMaxPower(POWER_MANA)), basePoint * 2); + ApplyPct(basePoint, unitTarget->GetMaxPower(POWER_MANA)); + if (basePoint > maxManaReturn) + basePoint = maxManaReturn; + + ApplyPct(basePoint, 60); } - // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. + // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. else if (familyFlag[0] & 0x00008000) - { - if (caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown - { - if (caster->ToPlayer()->HasSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID)) - break; - - caster->ToPlayer()->AddSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID, 0, 60000); - } - spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID; - } // Refresh aura duration aura->RefreshDuration(); - aurEff->ChangeAmount(aurEff->CalculateAmount(caster), false); } break; } if (spellId) + { caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); + } } } @@ -808,6 +812,49 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScript } }; +// -53234 - Piercing Shots +class spell_hun_piercing_shots : public AuraScript +{ + PrepareAuraScript(spell_hun_piercing_shots); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PIERCING_SHOTS)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetActionTarget()) + return true; + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetActionTarget(); + + if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo()) + { + SpellInfo const* piercingShots = sSpellMgr->AssertSpellInfo(SPELL_HUNTER_PIERCING_SHOTS); + uint32 dmg = dmgInfo->GetDamage(); + + uint32 bp = CalculatePct(int32(dmg), aurEff->GetAmount()) / static_cast(piercingShots->GetMaxTicks()); + + caster->CastCustomSpell(SPELL_HUNTER_PIERCING_SHOTS, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); + } + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_hun_piercing_shots::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_hun_piercing_shots::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 54044 - Pet Carrion Feeder class spell_hun_pet_carrion_feeder : public SpellScript { @@ -1008,6 +1055,43 @@ class spell_hun_tame_beast : public SpellScript } }; +// 67151 - T9 4P Bonus +class spell_hun_t9_4p_bonus : public AuraScript +{ + PrepareAuraScript(spell_hun_t9_4p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_T9_4P_GREATNESS)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER && eventInfo.GetActor()->ToPlayer()->GetPet()) + { + return true; + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + + caster->CastSpell(caster->ToPlayer()->GetPet(), SPELL_HUNTER_T9_4P_GREATNESS, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_hun_t9_4p_bonus::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_hun_t9_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 60144 - Viper Attack Speed class spell_hun_viper_attack_speed : public AuraScript { @@ -1308,6 +1392,172 @@ class spell_hun_bestial_wrath : public SpellScript } }; +// 57870 - Glyph of Mend Pet +class spell_hun_glyph_of_mend_pet : public AuraScript +{ + PrepareAuraScript(spell_hun_glyph_of_mend_pet); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_mend_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -53290 - Hunting Party +class spell_hun_hunting_party : public AuraScript +{ + PrepareAuraScript(spell_hun_hunting_party); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_REPLENISHMENT }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_hunting_party::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 58914 - Kill Command +class spell_hun_kill_command_pet : public AuraScript +{ + PrepareAuraScript(spell_hun_kill_command_pet); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HUNTER_KILL_COMMAND_HUNTER }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + // prevent charge drop (aura has both proc charge and stacks) + PreventDefaultAction(); + + if (Unit* owner = eventInfo.GetActor()->GetOwner()) + owner->RemoveAuraFromStack(SPELL_HUNTER_KILL_COMMAND_HUNTER); + + ModStackAmount(-1); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_kill_command_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -53228 - Rapid Recuperation (talent aura) +class spell_hun_rapid_recuperation_trigger : public AuraScript +{ + PrepareAuraScript(spell_hun_rapid_recuperation_trigger); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, + SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 + }); + } + + void HandleRapidFireProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + // Proc only from Rapid Fire + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000020)) + { + PreventDefaultAction(); + return; + } + } + + void HandleRapidKillingProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 }; + + PreventDefaultAction(); + + // Proc only from Rapid Killing + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || !(spellInfo->SpellFamilyFlags[1] & 0x01000000)) + return; + + uint8 rank = GetSpellInfo()->GetRank(); + uint32 spellId = triggerSpells[rank - 1]; + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidFireProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidKillingProc, EFFECT_1, SPELL_AURA_DUMMY); + } +}; + +// -34497 - Thrill of the Hunt +class spell_hun_thrill_of_the_hunt : public AuraScript +{ + PrepareAuraScript(spell_hun_thrill_of_the_hunt); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + Unit* caster = eventInfo.GetActor(); + int32 amount = 0; + + // Explosive Shot + if (spellInfo->SpellFamilyFlags[2] & 0x200) + { + if (AuraEffect const* explosiveShot = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x00000000, 0x80000000, 0x00000000, caster->GetGUID())) + { + // due to Lock and Load SpellInfo::CalcPowerCost might return 0, so just calculate it manually + amount = CalculatePct(static_cast(CalculatePct(caster->GetCreateMana(), explosiveShot->GetSpellInfo()->ManaCostPercentage)), aurEff->GetAmount()); + + ASSERT(explosiveShot->GetSpellInfo()->GetMaxTicks() > 0); + amount /= explosiveShot->GetSpellInfo()->GetMaxTicks(); + } + } + else + amount = CalculatePct(static_cast(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask())), aurEff->GetAmount()); + + if (!amount) + return; + + caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_hun_thrill_of_the_hunt::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + void AddSC_hunter_spell_scripts() { RegisterSpellScript(spell_hun_check_pet_los); @@ -1329,13 +1579,20 @@ void AddSC_hunter_spell_scripts() RegisterSpellScript(spell_hun_misdirection_proc); RegisterSpellScript(spell_hun_pet_carrion_feeder); RegisterSpellScript(spell_hun_pet_heart_of_the_phoenix); + RegisterSpellScript(spell_hun_piercing_shots); RegisterSpellScript(spell_hun_readiness); RegisterSpellScript(spell_hun_scatter_shot); RegisterSpellScript(spell_hun_sniper_training); RegisterSpellScript(spell_hun_tame_beast); + RegisterSpellScript(spell_hun_t9_4p_bonus); RegisterSpellScript(spell_hun_viper_attack_speed); RegisterSpellScript(spell_hun_volley_trigger); RegisterSpellScript(spell_hun_lock_and_load); RegisterSpellScript(spell_hun_intimidation); RegisterSpellScript(spell_hun_bestial_wrath); + RegisterSpellScript(spell_hun_glyph_of_mend_pet); + RegisterSpellScript(spell_hun_hunting_party); + RegisterSpellScript(spell_hun_kill_command_pet); + RegisterSpellScript(spell_hun_rapid_recuperation_trigger); + RegisterSpellScript(spell_hun_thrill_of_the_hunt); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 3476fb1e3..68ca1f4e2 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -536,13 +536,13 @@ class spell_item_essence_of_life : public AuraScript }; const uint32 crazyAlchemistTable[5] = -{ - 53909, // Wild Magic - 53908, // Potion of Speed - 53762, // Indestructible Potion - 43185, // Runic Healing Potion - 43186 // Runic Mana Potion -}; + { + 53909, // Wild Magic + 53908, // Potion of Speed + 53762, // Indestructible Potion + 43185, // Runic Healing Potion + 43186 // Runic Mana Potion + }; class spell_item_crazy_alchemists_potion : public SpellScript { @@ -883,7 +883,7 @@ class spell_item_fetch_ball : public SpellScript if (Creature* creature = (*itr)->ToCreature()) { if (creature->GetOwnerGUID() == GetCaster()->GetOwnerGUID() && !creature->IsNonMeleeSpellCast(false) && - creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) { target = creature; break; @@ -923,11 +923,11 @@ class spell_item_oracle_ablutions : public SpellScript caster->CastSpell(caster, SPELL_ABLUTION_RUNIC, true); break; case POWER_MANA: - { - int32 mana = CalculatePct(caster->GetMaxPower(POWER_MANA), 5.0f); - caster->CastCustomSpell(SPELL_ABLUTION_MANA, SPELLVALUE_BASE_POINT0, mana, caster, true); - break; - } + { + int32 mana = CalculatePct(caster->GetMaxPower(POWER_MANA), 5.0f); + caster->CastCustomSpell(SPELL_ABLUTION_MANA, SPELLVALUE_BASE_POINT0, mana, caster, true); + break; + } case POWER_RAGE: caster->CastSpell(caster, SPELL_ABLUTION_RAGE, true); break; @@ -992,37 +992,6 @@ class spell_item_blade_ward_enchant : public AuraScript } }; -class spell_item_blood_draining_enchant : public AuraScript -{ - PrepareAuraScript(spell_item_blood_draining_enchant); - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (!eventInfo.GetActionTarget() || !eventInfo.GetDamageInfo() || (eventInfo.GetActionTarget()->GetHealth() - eventInfo.GetDamageInfo()->GetDamage()) >= eventInfo.GetActionTarget()->CountPctFromMaxHealth(35)) - { - return; - } - - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/)) - { - int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); - eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/); - int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); - eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_blood_draining_enchant::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - class spell_item_dragon_kite_summon_lightning_bunny : public SpellScript { PrepareSpellScript(spell_item_dragon_kite_summon_lightning_bunny); @@ -1191,12 +1160,12 @@ class spell_item_eye_of_gruul_healing_discount : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_DRUID_ITEM_HEALING_TRANCE, - SPELL_PALADIN_ITEM_HEALING_TRANCE, - SPELL_PRIEST_ITEM_HEALING_TRANCE, - SPELL_SHAMAN_ITEM_HEALING_TRANCE - }); + { + SPELL_DRUID_ITEM_HEALING_TRANCE, + SPELL_PALADIN_ITEM_HEALING_TRANCE, + SPELL_PRIEST_ITEM_HEALING_TRANCE, + SPELL_SHAMAN_ITEM_HEALING_TRANCE + }); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) @@ -1783,13 +1752,13 @@ class spell_item_make_a_wish : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_MR_PINCHYS_BLESSING, - SPELL_SUMMON_MIGHTY_MR_PINCHY, - SPELL_SUMMON_FURIOUS_MR_PINCHY, - SPELL_TINY_MAGICAL_CRAWDAD, - SPELL_MR_PINCHYS_GIFT - }); + { + SPELL_MR_PINCHYS_BLESSING, + SPELL_SUMMON_MIGHTY_MR_PINCHY, + SPELL_SUMMON_FURIOUS_MR_PINCHY, + SPELL_TINY_MAGICAL_CRAWDAD, + SPELL_MR_PINCHYS_GIFT + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -1845,12 +1814,12 @@ enum MingoFortune }; std::array const CreateFortuneSpells = -{ - SPELL_CREATE_FORTUNE_1, SPELL_CREATE_FORTUNE_2, SPELL_CREATE_FORTUNE_3, SPELL_CREATE_FORTUNE_4, SPELL_CREATE_FORTUNE_5, - SPELL_CREATE_FORTUNE_6, SPELL_CREATE_FORTUNE_7, SPELL_CREATE_FORTUNE_8, SPELL_CREATE_FORTUNE_9, SPELL_CREATE_FORTUNE_10, - SPELL_CREATE_FORTUNE_11, SPELL_CREATE_FORTUNE_12, SPELL_CREATE_FORTUNE_13, SPELL_CREATE_FORTUNE_14, SPELL_CREATE_FORTUNE_15, - SPELL_CREATE_FORTUNE_16, SPELL_CREATE_FORTUNE_17, SPELL_CREATE_FORTUNE_18, SPELL_CREATE_FORTUNE_19, SPELL_CREATE_FORTUNE_20 -}; + { + SPELL_CREATE_FORTUNE_1, SPELL_CREATE_FORTUNE_2, SPELL_CREATE_FORTUNE_3, SPELL_CREATE_FORTUNE_4, SPELL_CREATE_FORTUNE_5, + SPELL_CREATE_FORTUNE_6, SPELL_CREATE_FORTUNE_7, SPELL_CREATE_FORTUNE_8, SPELL_CREATE_FORTUNE_9, SPELL_CREATE_FORTUNE_10, + SPELL_CREATE_FORTUNE_11, SPELL_CREATE_FORTUNE_12, SPELL_CREATE_FORTUNE_13, SPELL_CREATE_FORTUNE_14, SPELL_CREATE_FORTUNE_15, + SPELL_CREATE_FORTUNE_16, SPELL_CREATE_FORTUNE_17, SPELL_CREATE_FORTUNE_18, SPELL_CREATE_FORTUNE_19, SPELL_CREATE_FORTUNE_20 + }; // 26465 - Mercurial Shield enum MercurialShield @@ -1953,11 +1922,11 @@ class spell_item_net_o_matic : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_NET_O_MATIC_TRIGGERED1, - SPELL_NET_O_MATIC_TRIGGERED2, - SPELL_NET_O_MATIC_TRIGGERED3 - }); + { + SPELL_NET_O_MATIC_TRIGGERED1, + SPELL_NET_O_MATIC_TRIGGERED2, + SPELL_NET_O_MATIC_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2002,11 +1971,11 @@ class spell_item_noggenfogger_elixir : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED1, - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2, - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED3 - }); + { + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED1, + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2, + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2087,7 +2056,7 @@ class spell_item_savory_deviate_delight : public SpellScript case 1: spellId = (caster->getGender() == GENDER_MALE ? SPELL_FLIP_OUT_MALE : SPELL_FLIP_OUT_FEMALE); break; - // Yaaarrrr - pirate + // Yaaarrrr - pirate case 2: spellId = (caster->getGender() == GENDER_MALE ? SPELL_YAAARRRR_MALE : SPELL_YAAARRRR_FEMALE); break; @@ -2328,11 +2297,11 @@ class spell_item_shadowmourne : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, - SPELL_SHADOWMOURNE_SOUL_FRAGMENT, - SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF - }); + { + SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, + SPELL_SHADOWMOURNE_SOUL_FRAGMENT, + SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF + }); } bool CheckProc(ProcEventInfo& eventInfo) @@ -2454,14 +2423,14 @@ class spell_item_six_demon_bag : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_FROSTBOLT, - SPELL_POLYMORPH, - SPELL_SUMMON_FELHOUND_MINION, - SPELL_FIREBALL, - SPELL_CHAIN_LIGHTNING, - SPELL_ENVELOPING_WINDS - }); + { + SPELL_FROSTBOLT, + SPELL_POLYMORPH, + SPELL_SUMMON_FELHOUND_MINION, + SPELL_FIREBALL, + SPELL_CHAIN_LIGHTNING, + SPELL_ENVELOPING_WINDS + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2540,11 +2509,11 @@ class spell_item_underbelly_elixir : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_UNDERBELLY_ELIXIR_TRIGGERED1, - SPELL_UNDERBELLY_ELIXIR_TRIGGERED2, - SPELL_UNDERBELLY_ELIXIR_TRIGGERED3 - }); + { + SPELL_UNDERBELLY_ELIXIR_TRIGGERED1, + SPELL_UNDERBELLY_ELIXIR_TRIGGERED2, + SPELL_UNDERBELLY_ELIXIR_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2629,8 +2598,8 @@ class spell_item_map_of_the_geyser_fields : public SpellScript { Unit* caster = GetCaster(); if (caster->FindNearestCreature(NPC_SOUTH_SINKHOLE, 30.0f, true) || - caster->FindNearestCreature(NPC_NORTHEAST_SINKHOLE, 30.0f, true) || - caster->FindNearestCreature(NPC_NORTHWEST_SINKHOLE, 30.0f, true)) + caster->FindNearestCreature(NPC_NORTHEAST_SINKHOLE, 30.0f, true) || + caster->FindNearestCreature(NPC_NORTHWEST_SINKHOLE, 30.0f, true)) return SPELL_CAST_OK; SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_SINKHOLE); @@ -2657,11 +2626,11 @@ class spell_item_vanquished_clutches : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_CRUSHER, - SPELL_CONSTRICTOR, - SPELL_CORRUPTOR - }); + { + SPELL_CRUSHER, + SPELL_CONSTRICTOR, + SPELL_CORRUPTOR + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2866,13 +2835,13 @@ class spell_item_reindeer_transformation : public SpellScript bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( - { - SPELL_FLYING_REINDEER_310, - SPELL_FLYING_REINDEER_280, - SPELL_FLYING_REINDEER_60, - SPELL_REINDEER_100, - SPELL_REINDEER_60 - }); + { + SPELL_FLYING_REINDEER_310, + SPELL_FLYING_REINDEER_280, + SPELL_FLYING_REINDEER_60, + SPELL_REINDEER_100, + SPELL_REINDEER_60 + }); } void HandleDummy(SpellEffIndex /* effIndex */) @@ -3142,12 +3111,12 @@ class spell_item_brewfest_mount_transformation : public SpellScript bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( - { - SPELL_MOUNT_RAM_100, - SPELL_MOUNT_RAM_60, - SPELL_MOUNT_KODO_100, - SPELL_MOUNT_KODO_60 - }); + { + SPELL_MOUNT_RAM_100, + SPELL_MOUNT_RAM_60, + SPELL_MOUNT_KODO_100, + SPELL_MOUNT_KODO_60 + }); } void HandleDummy(SpellEffIndex /* effIndex */) @@ -3166,20 +3135,20 @@ class spell_item_brewfest_mount_transformation : public SpellScript switch (GetSpellInfo()->Id) { - case SPELL_BREWFEST_MOUNT_TRANSFORM: - if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; - else - spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; - break; - case SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE: - if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; - else - spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; - break; - default: - return; + case SPELL_BREWFEST_MOUNT_TRANSFORM: + if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; + else + spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; + break; + case SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE: + if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; + else + spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; + break; + default: + return; } caster->CastSpell(caster, spell_id, true); } @@ -3689,6 +3658,1323 @@ class spell_item_mirrens_drinking_hat : public SpellScript } }; +enum SoulPreserver +{ + SPELL_SOUL_PRESERVER_DRUID = 60512, + SPELL_SOUL_PRESERVER_PALADIN = 60513, + SPELL_SOUL_PRESERVER_PRIEST = 60514, + SPELL_SOUL_PRESERVER_SHAMAN = 60515, +}; + +class spell_item_soul_preserver : public AuraScript +{ + PrepareAuraScript(spell_item_soul_preserver); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SOUL_PRESERVER_DRUID, SPELL_SOUL_PRESERVER_PALADIN, SPELL_SOUL_PRESERVER_PRIEST, SPELL_SOUL_PRESERVER_SHAMAN }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + + switch (caster->getClass()) + { + case CLASS_DRUID: + caster->CastSpell(caster, SPELL_SOUL_PRESERVER_DRUID, true, nullptr, aurEff); + break; + case CLASS_PALADIN: + caster->CastSpell(caster, SPELL_SOUL_PRESERVER_PALADIN, true, nullptr, aurEff); + break; + case CLASS_PRIEST: + caster->CastSpell(caster, SPELL_SOUL_PRESERVER_PRIEST, true, nullptr, aurEff); + break; + case CLASS_SHAMAN: + caster->CastSpell(caster, SPELL_SOUL_PRESERVER_SHAMAN, true, nullptr, aurEff); + break; + default: + break; + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_soul_preserver::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +enum DeathChoiceSpells +{ + SPELL_DEATH_CHOICE_NORMAL_AURA = 67702, + SPELL_DEATH_CHOICE_NORMAL_AGILITY = 67703, + SPELL_DEATH_CHOICE_NORMAL_STRENGTH = 67708, + SPELL_DEATH_CHOICE_HEROIC_AURA = 67771, + SPELL_DEATH_CHOICE_HEROIC_AGILITY = 67772, + SPELL_DEATH_CHOICE_HEROIC_STRENGTH = 67773 +}; + +class spell_item_death_choice : public AuraScript +{ + PrepareAuraScript(spell_item_death_choice); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEATH_CHOICE_NORMAL_STRENGTH, SPELL_DEATH_CHOICE_NORMAL_AGILITY, SPELL_DEATH_CHOICE_HEROIC_STRENGTH, SPELL_DEATH_CHOICE_HEROIC_AGILITY }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + float str = caster->GetStat(STAT_STRENGTH); + float agi = caster->GetStat(STAT_AGILITY); + + switch (aurEff->GetId()) + { + case SPELL_DEATH_CHOICE_NORMAL_AURA: + { + if (str > agi) + { + caster->CastSpell(caster, SPELL_DEATH_CHOICE_NORMAL_STRENGTH, true, nullptr, aurEff); + } + else + { + caster->CastSpell(caster, SPELL_DEATH_CHOICE_NORMAL_AGILITY, true, nullptr, aurEff); + } + break; + } + case SPELL_DEATH_CHOICE_HEROIC_AURA: + { + if (str > agi) + { + caster->CastSpell(caster, SPELL_DEATH_CHOICE_HEROIC_STRENGTH, true, nullptr, aurEff); + } + else + { + caster->CastSpell(caster, SPELL_DEATH_CHOICE_HEROIC_AGILITY, true, nullptr, aurEff); + } + break; + } + default: + break; + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_death_choice::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +enum TrinketStackSpells +{ + SPELL_LIGHTNING_CAPACITOR_AURA = 37657, // Lightning Capacitor + SPELL_LIGHTNING_CAPACITOR_STACK = 37658, + SPELL_LIGHTNING_CAPACITOR_TRIGGER = 37661, + SPELL_THUNDER_CAPACITOR_AURA = 54841, // Thunder Capacitor + SPELL_THUNDER_CAPACITOR_STACK = 54842, + SPELL_THUNDER_CAPACITOR_TRIGGER = 54843, + SPELL_TOC25_CASTER_TRINKET_NORMAL_AURA = 67712, // Item - Coliseum 25 Normal Caster Trinket + SPELL_TOC25_CASTER_TRINKET_NORMAL_STACK = 67713, + SPELL_TOC25_CASTER_TRINKET_NORMAL_TRIGGER = 67714, + SPELL_TOC25_CASTER_TRINKET_HEROIC_AURA = 67758, // Item - Coliseum 25 Heroic Caster Trinket + SPELL_TOC25_CASTER_TRINKET_HEROIC_STACK = 67759, + SPELL_TOC25_CASTER_TRINKET_HEROIC_TRIGGER = 67760, +}; + +class spell_item_trinket_stack : public SpellScriptLoader +{ +public: + spell_item_trinket_stack(char const* scriptName, uint32 stackSpell, uint32 triggerSpell) : SpellScriptLoader(scriptName), + _stackSpell(stackSpell), _triggerSpell(triggerSpell) + { + } + + class spell_item_trinket_stack_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_trinket_stack_AuraScript); + + public: + spell_item_trinket_stack_AuraScript(uint32 stackSpell, uint32 triggerSpell) : _stackSpell(stackSpell), _triggerSpell(triggerSpell) + { + } + + private: + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ _stackSpell, _triggerSpell }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + + caster->CastSpell(caster, _stackSpell, true, nullptr, aurEff); // cast the stack + + Aura* dummy = caster->GetAura(_stackSpell); // retrieve aura + + //dont do anything if it's not the right amount of stacks; + if (!dummy || dummy->GetStackAmount() < aurEff->GetAmount()) + return; + + // if right amount, remove the aura and cast real trigger + caster->RemoveAurasDueToSpell(_stackSpell); + if (Unit* target = eventInfo.GetActionTarget()) + { + caster->CastSpell(target, _triggerSpell, true, nullptr, aurEff); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(_stackSpell); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_trinket_stack_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + AfterEffectRemove += AuraEffectRemoveFn(spell_item_trinket_stack_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + + private: + uint32 _stackSpell; + uint32 _triggerSpell; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_trinket_stack_AuraScript(_stackSpell, _triggerSpell); + } + +private: + uint32 _stackSpell; + uint32 _triggerSpell; +}; + +// 57345 - Darkmoon Card: Greatness +enum DarkmoonCardSpells +{ + SPELL_DARKMOON_CARD_STRENGHT = 60229, + SPELL_DARKMOON_CARD_AGILITY = 60233, + SPELL_DARKMOON_CARD_INTELLECT = 60234, + SPELL_DARKMOON_CARD_SPIRIT = 60235, +}; + +class spell_item_darkmoon_card_greatness : public AuraScript +{ + PrepareAuraScript(spell_item_darkmoon_card_greatness); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DARKMOON_CARD_AGILITY, SPELL_DARKMOON_CARD_STRENGHT, SPELL_DARKMOON_CARD_INTELLECT, SPELL_DARKMOON_CARD_SPIRIT }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + float str = caster->GetStat(STAT_STRENGTH); + float agi = caster->GetStat(STAT_AGILITY); + float intl = caster->GetStat(STAT_INTELLECT); + float spi = caster->GetStat(STAT_SPIRIT); + float stat = 0.0f; + + uint32 spellTrigger = SPELL_DARKMOON_CARD_STRENGHT; + + if (str > stat) + { + spellTrigger = SPELL_DARKMOON_CARD_STRENGHT; + stat = str; + } + + if (agi > stat) + { + spellTrigger = SPELL_DARKMOON_CARD_AGILITY; + stat = agi; + } + + if (intl > stat) + { + spellTrigger = SPELL_DARKMOON_CARD_INTELLECT; + stat = intl; + } + + if (spi > stat) + { + spellTrigger = SPELL_DARKMOON_CARD_SPIRIT; + stat = spi; + } + + caster->CastSpell(caster, spellTrigger, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_darkmoon_card_greatness::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 43820 - Amani Charm of the Witch Doctor +enum CharmWitchDoctor +{ + SPELL_CHARM_WITCH_DOCTOR_PROC = 43821 +}; + +class spell_item_charm_witch_doctor : public AuraScript +{ + PrepareAuraScript(spell_item_charm_witch_doctor); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_CHARM_WITCH_DOCTOR_PROC }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetActionTarget(); + + if (target) + { + int32 bp = CalculatePct(target->GetCreateHealth(), aurEff->GetSpellInfo()->Effects[1].CalcValue()); + caster->CastCustomSpell(target, SPELL_CHARM_WITCH_DOCTOR_PROC, &bp, nullptr, nullptr, true, nullptr, aurEff); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_charm_witch_doctor::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +enum ManaDrainSpells +{ + SPELL_MANA_DRAIN_ENERGIZE = 29471, + SPELL_MANA_DRAIN_LEECH = 27526 +}; + +// 27522, 40336 - Mana Drain +class spell_item_mana_drain : public AuraScript +{ + PrepareAuraScript(spell_item_mana_drain); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MANA_DRAIN_ENERGIZE, SPELL_MANA_DRAIN_LEECH }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetActionTarget(); + + if (caster->IsAlive()) + { + caster->CastSpell(caster, SPELL_MANA_DRAIN_ENERGIZE, true, nullptr, aurEff); + } + + if (target && target->IsAlive()) + { + caster->CastSpell(target, SPELL_MANA_DRAIN_LEECH, true, nullptr, aurEff); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_mana_drain::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// Item - 12846: Argent Dawn Commission +// Item - 13209: Seal of the Dawn +// Item - 19812: Rune of the Dawn + +enum AlchemistStone +{ + SPELL_ALCHEMISTS_STONE_EXTRA_HEAL = 21399, + SPELL_ALCHEMISTS_STONE_EXTRA_MANA = 21400 +}; + +// Item - 13503: Alchemist's Stone +// Item - 35748: Guardian's Alchemist Stone +// Item - 35749: Sorcerer's Alchemist Stone +// Item - 35750: Redeemer's Alchemist Stone +// Item - 35751: Assassin's Alchemist Stone +// Item - 44322: Mercurial Alchemist Stone +// Item - 44323: Indestructible Alchemist's Stone +// Item - 44324: Mighty Alchemist's Stone + +// 17619 - Alchemist's Stone +class spell_item_alchemists_stone : public AuraScript +{ + PrepareAuraScript(spell_item_alchemists_stone); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_ALCHEMISTS_STONE_EXTRA_HEAL, + SPELL_ALCHEMISTS_STONE_EXTRA_MANA + }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + Unit* caster = eventInfo.GetActionTarget(); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + uint32 spellId; + switch (spellInfo->Effects[i].Effect) + { + case SPELL_EFFECT_HEAL: + spellId = SPELL_ALCHEMISTS_STONE_EXTRA_HEAL; + break; + case SPELL_EFFECT_ENERGIZE: + spellId = SPELL_ALCHEMISTS_STONE_EXTRA_MANA; + break; + default: + continue; + } + + int32 amount = CalculatePct(spellInfo->Effects[i].CalcValue(caster), 40); + caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_alchemists_stone::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum AngerCapacitor +{ + SPELL_MOTE_OF_ANGER = 71432, + SPELL_MANIFEST_ANGER_MAIN_HAND = 71433, + SPELL_MANIFEST_ANGER_OFF_HAND = 71434 +}; + +// Item - 50351: Tiny Abomination in a Jar +// 71406 - Anger Capacitor + +// Item - 50706: Tiny Abomination in a Jar (Heroic) +// 71545 - Anger Capacitor +template +class spell_item_anger_capacitor : public SpellScriptLoader +{ +public: + spell_item_anger_capacitor(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_item_anger_capacitor_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_anger_capacitor_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_MOTE_OF_ANGER, + SPELL_MANIFEST_ANGER_MAIN_HAND, + SPELL_MANIFEST_ANGER_OFF_HAND + }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + caster->CastSpell((Unit*)nullptr, SPELL_MOTE_OF_ANGER, true); + Aura const* motes = caster->GetAura(SPELL_MOTE_OF_ANGER); + if (!motes || motes->GetStackAmount() < Stacks) + return; + + caster->RemoveAurasDueToSpell(SPELL_MOTE_OF_ANGER); + uint32 spellId = SPELL_MANIFEST_ANGER_MAIN_HAND; + if (Player* player = caster->ToPlayer()) + if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) + spellId = SPELL_MANIFEST_ANGER_OFF_HAND; + + caster->CastSpell(target, spellId, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_MOTE_OF_ANGER); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_anger_capacitor_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_item_anger_capacitor_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_anger_capacitor_AuraScript(); + } +}; + +enum AuraOfMadness +{ + SPELL_SOCIOPATH = 39511, // Sociopath: +35 strength(Paladin, Rogue, Druid, Warrior) + SPELL_DELUSIONAL = 40997, // Delusional: +70 attack power(Rogue, Hunter, Paladin, Warrior, Druid) + SPELL_KLEPTOMANIA = 40998, // Kleptomania: +35 agility(Warrior, Rogue, Paladin, Hunter, Druid) + SPELL_MEGALOMANIA = 40999, // Megalomania: +41 damage / healing(Druid, Shaman, Priest, Warlock, Mage, Paladin) + SPELL_PARANOIA = 41002, // Paranoia: +35 spell / melee / ranged crit strike rating(All classes) + SPELL_MANIC = 41005, // Manic: +35 haste(spell, melee and ranged) (All classes) + SPELL_NARCISSISM = 41009, // Narcissism: +35 intellect(Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) + SPELL_MARTYR_COMPLEX = 41011, // Martyr Complex: +35 stamina(All classes) + SPELL_DEMENTIA = 41404, // Dementia: Every 5 seconds either gives you +5/-5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + + SPELL_DEMENTIA_POS = 41406, + SPELL_DEMENTIA_NEG = 41409, + + SAY_MADNESS = 21954 +}; + +// Item - 31859: Darkmoon Card: Madness +// 39446 - Aura of Madness +class spell_item_aura_of_madness : public AuraScript +{ + PrepareAuraScript(spell_item_aura_of_madness); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SOCIOPATH, + SPELL_DELUSIONAL, + SPELL_KLEPTOMANIA, + SPELL_MEGALOMANIA, + SPELL_PARANOIA, + SPELL_MANIC, + SPELL_NARCISSISM, + SPELL_MARTYR_COMPLEX, + SPELL_DEMENTIA + }) && sObjectMgr->GetBroadcastText(SAY_MADNESS); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + static std::vector const triggeredSpells[MAX_CLASSES] = + { + //CLASS_NONE + { }, + //CLASS_WARRIOR + { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, + //CLASS_PALADIN + { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_HUNTER + { SPELL_DELUSIONAL, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_ROGUE + { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, + //CLASS_PRIEST + { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_DEATH_KNIGHT + { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, + //CLASS_SHAMAN + { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_MAGE + { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_WARLOCK + { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, + //CLASS_UNK + { }, + //CLASS_DRUID + { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA } + }; + + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + uint32 spellId = Acore::Containers::SelectRandomContainerElement(triggeredSpells[caster->getClass()]); + caster->CastSpell(caster, spellId, aurEff); + + if (roll_chance_i(10)) + caster->Unit::Say(SAY_MADNESS); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_aura_of_madness::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 41404 - Dementia +class spell_item_dementia : public AuraScript +{ + PrepareAuraScript(spell_item_dementia); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_DEMENTIA_POS, + SPELL_DEMENTIA_NEG + }); + } + + void HandlePeriodicDummy(AuraEffect const* aurEff) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), RAND(SPELL_DEMENTIA_POS, SPELL_DEMENTIA_NEG), aurEff); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_item_dementia::HandlePeriodicDummy, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +enum DeadlyPrecision +{ + SPELL_DEADLY_PRECISION = 71564 +}; + +// 71564 - Deadly Precision +class spell_item_deadly_precision : public AuraScript +{ + PrepareAuraScript(spell_item_deadly_precision); + + void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->RemoveAuraFromStack(GetId(), GetTarget()->GetGUID()); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_deadly_precision::HandleStackDrop, EFFECT_0, SPELL_AURA_MOD_RATING); + } +}; + +// 71563 - Deadly Precision Dummy +class spell_item_deadly_precision_dummy : public SpellScript +{ + PrepareSpellScript(spell_item_deadly_precision_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DEADLY_PRECISION }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DEADLY_PRECISION); + GetCaster()->CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_STACK, spellInfo->StackAmount, GetCaster(), true); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_item_deadly_precision_dummy::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } +}; + +enum DeathbringersWill +{ + SPELL_STRENGTH_OF_THE_TAUNKA = 71484, // +600 Strength + SPELL_AGILITY_OF_THE_VRYKUL = 71485, // +600 Agility + SPELL_POWER_OF_THE_TAUNKA = 71486, // +1200 Attack Power + SPELL_AIM_OF_THE_IRON_DWARVES = 71491, // +600 Critical + SPELL_SPEED_OF_THE_VRYKUL = 71492, // +600 Haste + + SPELL_AGILITY_OF_THE_VRYKUL_HERO = 71556, // +700 Agility + SPELL_POWER_OF_THE_TAUNKA_HERO = 71558, // +1400 Attack Power + SPELL_AIM_OF_THE_IRON_DWARVES_HERO = 71559, // +700 Critical + SPELL_SPEED_OF_THE_VRYKUL_HERO = 71560, // +700 Haste + SPELL_STRENGTH_OF_THE_TAUNKA_HERO = 71561 // +700 Strength +}; + +// Item - 50362: Deathbringer's Will +// 71519 - Item - Icecrown 25 Normal Melee Trinket + +// Item - 50363: Deathbringer's Will +// 71562 - Item - Icecrown 25 Heroic Melee Trinket +template +class spell_item_deathbringers_will : public SpellScriptLoader +{ +public: + spell_item_deathbringers_will(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_item_deathbringers_will_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_deathbringers_will_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + Strength, + Agility, + AttackPower, + Critical, + Haste + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + static std::vector const triggeredSpells[MAX_CLASSES] = + { + //CLASS_NONE + { }, + //CLASS_WARRIOR + { Strength, Critical, Haste }, + //CLASS_PALADIN + { Strength, Critical, Haste }, + //CLASS_HUNTER + { Agility, Critical, AttackPower }, + //CLASS_ROGUE + { Agility, Haste, AttackPower }, + //CLASS_PRIEST + { }, + //CLASS_DEATH_KNIGHT + { Strength, Critical, Haste }, + //CLASS_SHAMAN + { Agility, Haste, AttackPower }, + //CLASS_MAGE + { }, + //CLASS_WARLOCK + { }, + //CLASS_UNK + { }, + //CLASS_DRUID + { Strength, Agility, Haste } + }; + + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + std::vector const& randomSpells = triggeredSpells[caster->getClass()]; + if (randomSpells.empty()) + return; + + uint32 spellId = Acore::Containers::SelectRandomContainerElement(randomSpells); + caster->CastSpell(caster, spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_deathbringers_will_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_deathbringers_will_AuraScript(); + } +}; + +enum DiscerningEyeBeastMisc +{ + SPELL_DISCERNING_EYE_BEAST = 59914 +}; + +// 59915 - Discerning Eye of the Beast Dummy +class spell_item_discerning_eye_beast_dummy : public AuraScript +{ + PrepareAuraScript(spell_item_discerning_eye_beast_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DISCERNING_EYE_BEAST }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DISCERNING_EYE_BEAST, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_discerning_eye_beast_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum FrozenShadoweave +{ + SPELL_SHADOWMEND = 39373 +}; + +// 39372 - Frozen Shadoweave +// Frozen Shadoweave set 3p bonus +class spell_item_frozen_shadoweave : public AuraScript +{ + PrepareAuraScript(spell_item_frozen_shadoweave); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHADOWMEND }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + Unit* caster = eventInfo.GetActor(); + caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_frozen_shadoweave::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// Item 23004 - Idol of Longevity +// 28847 - Healing Touch Refund +enum IdolOfLongevity +{ + SPELL_HEALING_TOUCH_MANA = 28848 +}; + +class spell_item_healing_touch_refund : public AuraScript +{ + PrepareAuraScript(spell_item_healing_touch_refund); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HEALING_TOUCH_MANA }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_healing_touch_refund::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum Heartpierce +{ + SPELL_INVIGORATION_MANA = 71881, + SPELL_INVIGORATION_ENERGY = 71882, + SPELL_INVIGORATION_RAGE = 71883, + SPELL_INVIGORATION_RP = 71884, + + SPELL_INVIGORATION_RP_HERO = 71885, + SPELL_INVIGORATION_RAGE_HERO = 71886, + SPELL_INVIGORATION_ENERGY_HERO = 71887, + SPELL_INVIGORATION_MANA_HERO = 71888 +}; + +// Item - 49982: Heartpierce +// 71880 - Item - Icecrown 25 Normal Dagger Proc + +// Item - 50641: Heartpierce (Heroic) +// 71892 - Item - Icecrown 25 Heroic Dagger Proc +template +class spell_item_heartpierce : public SpellScriptLoader +{ +public: + spell_item_heartpierce(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_item_heartpierce_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_heartpierce_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + Energy, + Mana, + Rage, + RunicPower + }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + + uint32 spellId; + switch (caster->getPowerType()) + { + case POWER_MANA: + spellId = Mana; + break; + case POWER_ENERGY: + spellId = Energy; + break; + case POWER_RAGE: + spellId = Rage; + break; + // Death Knights can't use daggers, but oh well + case POWER_RUNIC_POWER: + spellId = RunicPower; + break; + default: + return; + } + + caster->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_heartpierce_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_heartpierce_AuraScript(); + } +}; + +// 40971 - Bonus Healing (Crystal Spire of Karabor) +class spell_item_crystal_spire_of_karabor : public AuraScript +{ + PrepareAuraScript(spell_item_crystal_spire_of_karabor); + + bool CheckProc(ProcEventInfo& eventInfo) + { + int32 pct = GetSpellInfo()->Effects[EFFECT_0].BasePoints; + if (HealInfo* healInfo = eventInfo.GetHealInfo()) + if (Unit* healTarget = healInfo->GetTarget()) + if (healTarget->GetHealth() - healInfo->GetEffectiveHeal() <= healTarget->CountPctFromMaxHealth(pct)) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_item_crystal_spire_of_karabor::CheckProc); + } +}; + +enum MarkOfConquest +{ + SPELL_MARK_OF_CONQUEST_ENERGIZE = 39599 +}; + +// Item - 27920: Mark of Conquest +// Item - 27921: Mark of Conquest +// 33510 - Health Restore +class spell_item_mark_of_conquest : public AuraScript +{ + PrepareAuraScript(spell_item_mark_of_conquest); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MARK_OF_CONQUEST_ENERGIZE }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + if (eventInfo.GetTypeMask() & (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)) + { + // in that case, do not cast heal spell + PreventDefaultAction(); + // but mana instead + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_mark_of_conquest::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +enum PersistentShieldMisc +{ + SPELL_PERSISTENT_SHIELD_TRIGGERED = 26470 +}; + +// 26467 - Persistent Shield +class spell_item_persistent_shield : public AuraScript +{ + PrepareAuraScript(spell_item_persistent_shield); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PERSISTENT_SHIELD_TRIGGERED }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetHeal(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + int32 bp0 = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15); + + // Scarab Brooch does not replace stronger shields + if (AuraEffect const* shield = target->GetAuraEffect(SPELL_PERSISTENT_SHIELD_TRIGGERED, EFFECT_0, caster->GetGUID())) + if (shield->GetAmount() > bp0) + return; + + caster->CastCustomSpell(SPELL_PERSISTENT_SHIELD_TRIGGERED, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_item_persistent_shield::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_item_persistent_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +enum PetHealing +{ + SPELL_HEALTH_LINK = 37382 +}; + +// 37381 - Pet Healing +// Hunter T5 2P Bonus +// Warlock T5 2P Bonus +class spell_item_pet_healing : public AuraScript +{ + PrepareAuraScript(spell_item_pet_healing); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HEALTH_LINK }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + Unit* caster = eventInfo.GetActor(); + caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_pet_healing::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum SwiftHandJusticeMisc +{ + SPELL_SWIFT_HAND_OF_JUSTICE_HEAL = 59913 +}; + +// 59906 - Swift Hand of Justice Dummy +class spell_item_swift_hand_justice_dummy : public AuraScript +{ + PrepareAuraScript(spell_item_swift_hand_justice_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SWIFT_HAND_OF_JUSTICE_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_swift_hand_justice_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum TotemOfFlowingWater +{ + SPELL_LESSER_HEALING_WAVE_MANA = 28850 +}; + +// Item - 23005: Totem of Flowing Water +// 28849 - Lesser Healing Wave +class spell_item_totem_of_flowing_water : public AuraScript +{ + PrepareAuraScript(spell_item_totem_of_flowing_water); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_LESSER_HEALING_WAVE_MANA }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_totem_of_flowing_water::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +enum ShardOfTheScale +{ + SPELL_PURIFIED_CAUTERIZING_HEAL = 69733, + SPELL_PURIFIED_SEARING_FLAMES = 69729, + + SPELL_SHINY_CAUTERIZING_HEAL = 69734, + SPELL_SHINY_SEARING_FLAMES = 69730 +}; + +// Item - 49310: Purified Shard of the Scale +// 69755 - Purified Shard of the Scale - Equip Effect + +// Item - 49488: Shiny Shard of the Scale +// 69739 - Shiny Shard of the Scale - Equip Effect +template +class spell_item_shard_of_the_scale : public SpellScriptLoader +{ +public: + spell_item_shard_of_the_scale(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_item_shard_of_the_scale_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_shard_of_the_scale_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + HealProc, + DamageProc + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) + caster->CastSpell(target, HealProc, aurEff); + + if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG) + caster->CastSpell(target, DamageProc, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_shard_of_the_scale_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_shard_of_the_scale_AuraScript(); + } +}; + +enum ExaltedSunwellNeck +{ + SPELL_LIGHTS_WRATH = 45479, // Light's Wrath if Exalted by Aldor + SPELL_ARCANE_BOLT = 45429, // Arcane Bolt if Exalted by Scryers + + SPELL_LIGHTS_STRENGTH = 45480, // Light's Strength if Exalted by Aldor + SPELL_ARCANE_STRIKE = 45428, // Arcane Strike if Exalted by Scryers + + SPELL_LIGHTS_WARD = 45432, // Light's Ward if Exalted by Aldor + SPELL_ARCANE_INSIGHT = 45431, // Arcane Insight if Exalted by Scryers + + SPELL_LIGHTS_SALVATION = 45478, // Light's Salvation if Exalted by Aldor + SPELL_ARCANE_SURGE = 45430, // Arcane Surge if Exalted by Scryers + + FACTION_ALDOR = 932, + FACTION_SCRYERS = 934 +}; + +// Item - 34678: Shattered Sun Pendant of Acumen +// 45481 - Sunwell Exalted Caster Neck + +// Item - 34679: Shattered Sun Pendant of Might +// 45482 - Sunwell Exalted Melee Neck + +// Item - 34680: Shattered Sun Pendant of Resolve +// 45483 - Sunwell Exalted Tank Neck + +// Item - 34677: Shattered Sun Pendant of Restoration +// 45484 Sunwell Exalted Healer Neck +template +class spell_item_sunwell_neck : public SpellScriptLoader +{ +public: + spell_item_sunwell_neck(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_item_sunwell_neck_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_sunwell_neck_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ Aldors, Scryers }) && + sFactionStore.LookupEntry(FACTION_ALDOR) && + sFactionStore.LookupEntry(FACTION_SCRYERS); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetActor()->GetTypeId() != TYPEID_PLAYER) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Player* player = eventInfo.GetActor()->ToPlayer(); + Unit* target = eventInfo.GetProcTarget(); + + // Aggression checks are in the spell system... just cast and forget + if (player->GetReputationRank(FACTION_ALDOR) == REP_EXALTED) + player->CastSpell(target, Aldors, aurEff); + + if (player->GetReputationRank(FACTION_SCRYERS) == REP_EXALTED) + player->CastSpell(target, Scryers, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_item_sunwell_neck_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_item_sunwell_neck_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_sunwell_neck_AuraScript(); + } +}; + +enum ZandalarianCharms +{ + SPELL_UNSTABLE_POWER_AURA_STACK = 24659, + SPELL_RESTLESS_STRENGTH_AURA_STACK = 24662 +}; + +// Item - 19950: Zandalarian Hero Charm +// 24658 - Unstable Power + +// Item - 19949: Zandalarian Hero Medallion +// 24661 - Restless Strength +class spell_item_zandalarian_charm : public SpellScriptLoader +{ +public: + spell_item_zandalarian_charm(char const* ScriptName, uint32 SpellId) : SpellScriptLoader(ScriptName), _spellId(SpellId) { } + + class spell_item_zandalarian_charm_AuraScript : public AuraScript + { + friend class spell_item_zandalarian_charm; + spell_item_zandalarian_charm_AuraScript(uint32 SpellId) : AuraScript(), _spellId(SpellId) { } + + PrepareAuraScript(spell_item_zandalarian_charm_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ _spellId }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (spellInfo->Id != m_scriptSpellId) + return true; + + return false; + } + + void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->RemoveAuraFromStack(_spellId); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_item_zandalarian_charm_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_item_zandalarian_charm_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_DUMMY); + } + + uint32 _spellId; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_item_zandalarian_charm_AuraScript(_spellId); + } + +private: + uint32 _spellId; +}; + +class spell_item_blood_draining_enchant : public AuraScript +{ + PrepareAuraScript(spell_item_blood_draining_enchant); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (!eventInfo.GetActionTarget() || !eventInfo.GetDamageInfo() || (eventInfo.GetActionTarget()->GetHealth() - eventInfo.GetDamageInfo()->GetDamage()) >= eventInfo.GetActionTarget()->CountPctFromMaxHealth(35)) + { + return; + } + + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/)) + { + int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); + eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/); + int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); + eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_blood_draining_enchant::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + class spell_item_snowman : public SpellScript { PrepareSpellScript(spell_item_snowman); @@ -3851,6 +5137,43 @@ void AddSC_item_spell_scripts() RegisterSpellScript(spell_item_recall); RegisterSpellScript(spell_item_wraith_scythe_drain_life); RegisterSpellScript(spell_item_mirrens_drinking_hat); + RegisterSpellScript(spell_item_soul_preserver); + RegisterSpellScript(spell_item_death_choice); + new spell_item_trinket_stack("spell_item_lightning_capacitor", SPELL_LIGHTNING_CAPACITOR_STACK, SPELL_LIGHTNING_CAPACITOR_TRIGGER); + new spell_item_trinket_stack("spell_item_thunder_capacitor", SPELL_THUNDER_CAPACITOR_STACK, SPELL_THUNDER_CAPACITOR_TRIGGER); + new spell_item_trinket_stack("spell_item_toc25_normal_caster_trinket", SPELL_TOC25_CASTER_TRINKET_NORMAL_STACK, SPELL_TOC25_CASTER_TRINKET_NORMAL_TRIGGER); + new spell_item_trinket_stack("spell_item_toc25_heroic_caster_trinket", SPELL_TOC25_CASTER_TRINKET_HEROIC_STACK, SPELL_TOC25_CASTER_TRINKET_HEROIC_TRIGGER); + RegisterSpellScript(spell_item_darkmoon_card_greatness); + RegisterSpellScript(spell_item_charm_witch_doctor); + RegisterSpellScript(spell_item_mana_drain); + RegisterSpellScript(spell_item_alchemists_stone); + new spell_item_anger_capacitor<8>("spell_item_tiny_abomination_in_a_jar"); + new spell_item_anger_capacitor<7>("spell_item_tiny_abomination_in_a_jar_hero"); + RegisterSpellScript(spell_item_aura_of_madness); + RegisterSpellScript(spell_item_dementia); + RegisterSpellScript(spell_item_deadly_precision); + RegisterSpellScript(spell_item_deadly_precision_dummy); + new spell_item_deathbringers_will("spell_item_deathbringers_will_normal"); + new spell_item_deathbringers_will("spell_item_deathbringers_will_heroic"); + RegisterSpellScript(spell_item_discerning_eye_beast_dummy); + RegisterSpellScript(spell_item_frozen_shadoweave); + RegisterSpellScript(spell_item_healing_touch_refund); + new spell_item_heartpierce("spell_item_heartpierce"); + new spell_item_heartpierce("spell_item_heartpierce_hero"); + RegisterSpellScript(spell_item_crystal_spire_of_karabor); + RegisterSpellScript(spell_item_mark_of_conquest); + RegisterSpellScript(spell_item_persistent_shield); + RegisterSpellScript(spell_item_pet_healing); + RegisterSpellScript(spell_item_swift_hand_justice_dummy); + RegisterSpellScript(spell_item_totem_of_flowing_water); + new spell_item_shard_of_the_scale("spell_item_purified_shard_of_the_scale"); + new spell_item_shard_of_the_scale("spell_item_shiny_shard_of_the_scale"); + new spell_item_sunwell_neck("spell_item_sunwell_exalted_caster_neck"); + new spell_item_sunwell_neck("spell_item_sunwell_exalted_melee_neck"); + new spell_item_sunwell_neck("spell_item_sunwell_exalted_tank_neck"); + new spell_item_sunwell_neck("spell_item_sunwell_exalted_healer_neck"); + new spell_item_zandalarian_charm("spell_item_unstable_power", SPELL_UNSTABLE_POWER_AURA_STACK); + new spell_item_zandalarian_charm("spell_item_restless_strength", SPELL_RESTLESS_STRENGTH_AURA_STACK); RegisterSpellScript(spell_item_snowman); RegisterSpellScript(spell_item_freeze_rookery_egg); } diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index 699ae8ff4..e54941ec2 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -31,12 +31,11 @@ enum MageSpells { - // Ours + SPELL_MAGE_BLAZING_SPEED = 31643, SPELL_MAGE_BURNOUT_TRIGGER = 44450, SPELL_MAGE_IMPROVED_BLIZZARD_CHILLED = 12486, SPELL_MAGE_COMBUSTION = 11129, - // Theirs SPELL_MAGE_COLD_SNAP = 11958, SPELL_MAGE_FOCUS_MAGIC_PROC = 54648, SPELL_MAGE_FROST_WARDING_R1 = 11189, @@ -55,9 +54,49 @@ enum MageSpells SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907, SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126, + + SPELL_MAGE_CHILLED = 12484, + SPELL_MAGE_MANA_SURGE = 37445, + SPELL_MAGE_MAGIC_ABSORPTION_MANA = 29442, + SPELL_MAGE_ARCANE_POTENCY_RANK_1 = 57529, + SPELL_MAGE_ARCANE_POTENCY_RANK_2 = 57531, + SPELL_MAGE_HOT_STREAK_PROC = 48108, + SPELL_MAGE_ARCANE_SURGE = 37436, + SPELL_MAGE_COMBUSTION_PROC = 28682, + SPELL_MAGE_EMPOWERED_FIRE_PROC = 67545, + SPELL_MAGE_T10_2P_BONUS = 70752, + SPELL_MAGE_T10_2P_BONUS_EFFECT = 70753, + SPELL_MAGE_T8_4P_BONUS = 64869, + SPELL_MAGE_MISSILE_BARRAGE = 44401, + SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA = 44544, SPELL_MAGE_FINGERS_OF_FROST = 44543 }; +// -31641 - Blazing Speed +class spell_mage_blazing_speed : public AuraScript +{ + PrepareAuraScript(spell_mage_blazing_speed); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_BLAZING_SPEED }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (Unit* target = eventInfo.GetActionTarget()) + { + target->CastSpell(target, SPELL_MAGE_BLAZING_SPEED, true, nullptr, aurEff); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_blazing_speed::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + class spell_mage_arcane_blast : public SpellScript { PrepareSpellScript(spell_mage_arcane_blast); @@ -100,7 +139,7 @@ class spell_mage_burning_determination : public AuraScript return false; // Xinef: immuned effect should just eat charge - if (eventInfo.GetHitMask() & PROC_EX_IMMUNE) + if (eventInfo.GetHitMask() & PROC_HIT_IMMUNE) { eventInfo.GetActionTarget()->RemoveAurasDueToSpell(54748); return false; @@ -933,6 +972,349 @@ class spell_mage_summon_water_elemental : public SpellScript } }; +// -31571 - Arcane Potency +class spell_mage_arcane_potency : public AuraScript +{ + PrepareAuraScript(spell_mage_arcane_potency); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_MAGE_ARCANE_POTENCY_RANK_1, + SPELL_MAGE_ARCANE_POTENCY_RANK_2 + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + static uint32 const triggerSpell[2] = { SPELL_MAGE_ARCANE_POTENCY_RANK_1, SPELL_MAGE_ARCANE_POTENCY_RANK_2 }; + + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; + caster->CastSpell(caster, spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_arcane_potency::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 11129 - Combustion +class spell_mage_combustion : public AuraScript +{ + PrepareAuraScript(spell_mage_combustion); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_COMBUSTION_PROC }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + // Do not take charges, add a stack of crit buff + if (!(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)) + { + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_COMBUSTION_PROC, true); + return false; + } + + return true; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_mage_combustion::CheckProc); + } +}; + +// -11185 - Improved Blizzard +class spell_mage_imp_blizzard : public AuraScript +{ + PrepareAuraScript(spell_mage_imp_blizzard); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_CHILLED }); + } + + void HandleChill(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + uint32 triggerSpellId = sSpellMgr->GetSpellWithRank(SPELL_MAGE_CHILLED, GetSpellInfo()->GetRank()); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_imp_blizzard::HandleChill, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + } +}; + +// 37447 - Improved Mana Gems +// 61062 - Improved Mana Gems +class spell_mage_imp_mana_gems : public AuraScript +{ + PrepareAuraScript(spell_mage_imp_mana_gems); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_MANA_SURGE }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_imp_mana_gems::HandleProc, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + } +}; + +// -31656 - Empowered Fire +class spell_mage_empowered_fire : public AuraScript +{ + PrepareAuraScript(spell_mage_empowered_fire); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_EMPOWERED_FIRE_PROC }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (spellInfo->Id == SPELL_MAGE_IGNITE) + return true; + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + Unit* target = GetTarget(); + int32 bp0 = int32(CalculatePct(target->GetCreateMana(), aurEff->GetAmount())); + target->CastCustomSpell(SPELL_MAGE_EMPOWERED_FIRE_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_mage_empowered_fire::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_mage_empowered_fire::HandleProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER); + } +}; + +// 74396 - Fingers of Frost +class spell_mage_fingers_of_frost : public AuraScript +{ + PrepareAuraScript(spell_mage_fingers_of_frost); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA }); + } + + void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->RemoveAuraFromStack(GetId()); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_mage_fingers_of_frost::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + +// 48108 - Hot Streak +// 57761 - Fireball! +class spell_mage_gen_extra_effects : public AuraScript +{ + PrepareAuraScript(spell_mage_gen_extra_effects); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_MAGE_T10_2P_BONUS, + SPELL_MAGE_T10_2P_BONUS_EFFECT, + SPELL_MAGE_T8_4P_BONUS + }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Unit* caster = eventInfo.GetActor(); + // Prevent double proc for Arcane missiles + if (caster == eventInfo.GetProcTarget()) + return false; + + // Proc chance is unknown, we'll just use dummy aura amount + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_MAGE_T8_4P_BONUS, EFFECT_0)) + if (roll_chance_i(aurEff->GetAmount())) + return false; + + return true; + } + + void HandleProc(ProcEventInfo& eventInfo) + { + Unit* caster = eventInfo.GetActor(); + + if (caster->HasAura(SPELL_MAGE_T10_2P_BONUS)) + caster->CastSpell((Unit*)nullptr, SPELL_MAGE_T10_2P_BONUS_EFFECT, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_mage_gen_extra_effects::CheckProc); + OnProc += AuraProcFn(spell_mage_gen_extra_effects::HandleProc); + } +}; + +// 56375 - Glyph of Polymorph +class spell_mage_glyph_of_polymorph : public AuraScript +{ + PrepareAuraScript(spell_mage_glyph_of_polymorph); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* target = eventInfo.GetProcTarget(); + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed. + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); + target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_polymorph::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 56374 - Glyph of Icy Veins +class spell_mage_glyph_of_icy_veins : public AuraScript +{ + PrepareAuraScript(spell_mage_glyph_of_icy_veins); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + caster->RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false); + caster->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_icy_veins::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -44445 - Hot Streak +class spell_mage_hot_streak : public AuraScript +{ + PrepareAuraScript(spell_mage_hot_streak); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_HOT_STREAK_PROC }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + AuraEffect* counter = GetEffect(EFFECT_1); + if (!counter) + return; + + // Count spell criticals in a row in second aura + if (eventInfo.GetHitMask() & PROC_HIT_CRITICAL) + { + counter->SetAmount(counter->GetAmount() * 2); + if (counter->GetAmount() < 100) // not enough + return; + + // roll chance + if (!roll_chance_i(aurEff->GetAmount())) + return; + + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, aurEff); + } + + // reset counter + counter->SetAmount(25); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_hot_streak::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -29441 - Magic Absorption +class spell_mage_magic_absorption : public AuraScript +{ + PrepareAuraScript(spell_mage_magic_absorption); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MAGE_MAGIC_ABSORPTION_MANA }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActionTarget(); + int32 bp = CalculatePct(static_cast(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_mage_magic_absorption::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -44404 - Missile Barrage +class spell_mage_missile_barrage : public AuraScript +{ + PrepareAuraScript(spell_mage_missile_barrage); + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + // Arcane Blast - full chance + if (spellInfo->SpellFamilyFlags[0] & 0x20000000) + return true; + + // Rest of spells have half chance + return roll_chance_i(50); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_mage_missile_barrage::CheckProc); + } +}; + #define FingersOfFrostScriptName "spell_mage_fingers_of_frost_proc_aura" class spell_mage_fingers_of_frost_proc_aura : public AuraScript { PrepareAuraScript(spell_mage_fingers_of_frost_proc_aura); @@ -1043,6 +1425,7 @@ class spell_mage_fingers_of_frost_proc : public AuraScript void AddSC_mage_spell_scripts() { + RegisterSpellScript(spell_mage_blazing_speed); RegisterSpellScript(spell_mage_arcane_blast); RegisterSpellScript(spell_mage_burning_determination); RegisterSpellScript(spell_mage_molten_armor); @@ -1064,6 +1447,18 @@ void AddSC_mage_spell_scripts() RegisterSpellScript(spell_mage_master_of_elements); RegisterSpellScript(spell_mage_polymorph_cast_visual); RegisterSpellScript(spell_mage_summon_water_elemental); + RegisterSpellScript(spell_mage_arcane_potency); + RegisterSpellScript(spell_mage_combustion); + RegisterSpellScript(spell_mage_imp_blizzard); + RegisterSpellScript(spell_mage_imp_mana_gems); + RegisterSpellScript(spell_mage_empowered_fire); + RegisterSpellScript(spell_mage_fingers_of_frost); + RegisterSpellScript(spell_mage_gen_extra_effects); + RegisterSpellScript(spell_mage_glyph_of_polymorph); + RegisterSpellScript(spell_mage_glyph_of_icy_veins); + RegisterSpellScript(spell_mage_hot_streak); + RegisterSpellScript(spell_mage_magic_absorption); + RegisterSpellScript(spell_mage_missile_barrage); RegisterSpellScript(spell_mage_fingers_of_frost_proc_aura); RegisterSpellScript(spell_mage_fingers_of_frost_proc); } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index a3588b7d1..032ed12d2 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -28,6 +28,7 @@ #include "SpellMgr.h" #include "SpellScript.h" #include "UnitAI.h" +#include "GameTime.h" enum PaladinSpells { @@ -38,6 +39,7 @@ enum PaladinSpells SPELL_PALADIN_HOLY_SHOCK_R1 = 20473, SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912, SPELL_PALADIN_HOLY_SHOCK_R1_HEALING = 25914, + SPELL_PALADIN_ILLUMINATION_ENERGIZE = 20272, SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID = 37878, SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN = 37879, @@ -81,7 +83,44 @@ enum PaladinSpells SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364, SPELL_GENERIC_ARENA_DAMPENING = 74410, - SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411 + SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411, + + SPELL_PALADIN_SACRED_SHIELD = 53601, + SPELL_PALADIN_T9_HOLY_4P_BONUS = 67191, + SPELL_PALADIN_FLASH_OF_LIGHT_PROC = 66922, + + SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC = 68055, + + SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC = 54986, + + SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA = 31930, + SPELL_REPLENISHMENT = 57669, + SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE = 61840, + SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL = 54203, + SPELL_PALADIN_SACRED_SHIELD_TRIGGER = 58597, + SPELL_PALADIN_T8_HOLY_4P_BONUS = 64895, + SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 = 21183, + + SPELL_PALADIN_HOLY_POWER_ARMOR = 28790, + SPELL_PALADIN_HOLY_POWER_ATTACK_POWER = 28791, + SPELL_PALADIN_HOLY_POWER_SPELL_POWER = 28793, + SPELL_PALADIN_HOLY_POWER_MP5 = 28795, + + SPELL_PALADIN_HOLY_VENGEANCE = 31803, + SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE = 42463, + SPELL_PALADIN_BLOOD_CORRUPTION = 53742, + SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE = 53739, + + SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA = 31786, + + SPELL_PALADIN_ENDURING_LIGHT = 40471, + SPELL_PALADIN_ENDURING_JUDGEMENT = 40472, + + SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL = 54968, + SPELL_PALADIN_HOLY_MENDING = 64891, + + SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL = 20267, + SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA = 20268 }; enum PaladinSpellIcons @@ -218,13 +257,6 @@ class spell_pal_sacred_shield_base : public AuraScript } } - bool CheckProc(ProcEventInfo& eventInfo) - { - HealInfo* healinfo = eventInfo.GetHealInfo(); - DamageInfo* damageinfo = eventInfo.GetDamageInfo(); - return !(eventInfo.GetHitMask() & PROC_EX_INTERNAL_HOT) && ((healinfo && healinfo->GetHeal() > 0) || (damageinfo && damageinfo->GetDamage() > 0)); - } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -280,7 +312,6 @@ class spell_pal_sacred_shield_base : public AuraScript void Register() override { DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_sacred_shield_base::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY); - DoCheckProc += AuraCheckProcFn(spell_pal_sacred_shield_base::CheckProc); OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_base::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; @@ -838,6 +869,51 @@ class spell_pal_holy_shock : public SpellScript } }; +// -20210 - Illumination +class spell_pal_illumination : public AuraScript +{ + PrepareAuraScript(spell_pal_illumination); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_HOLY_SHOCK_R1_HEALING, SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELL_PALADIN_HOLY_SHOCK_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + // this script is valid only for the Holy Shock procs of illumination + if (eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetSpellInfo()) + { + SpellInfo const* originalSpell = nullptr; + + // if proc comes from the Holy Shock heal, need to get mana cost of original spell - else it's the original heal itself + if (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[1] & 0x00010000) + { + originalSpell = sSpellMgr->GetSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1, eventInfo.GetHealInfo()->GetSpellInfo()->GetRank())); + } + else + { + originalSpell = eventInfo.GetHealInfo()->GetSpellInfo(); + } + + if (originalSpell && aurEff->GetSpellInfo()) + { + Unit* target = eventInfo.GetActor(); // Paladin is the target of the energize + + uint32 bp = CalculatePct(originalSpell->CalcPowerCost(target, originalSpell->GetSchoolMask()), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue()); + target->CastCustomSpell(SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); + } + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_illumination::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 53407 - Judgement of Justice // 20271 - Judgement of Light // 53408 - Judgement of Wisdom @@ -1043,7 +1119,7 @@ class spell_pal_seal_of_righteousness : public AuraScript return false; } - return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_EX_ABSORB)); + return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_HIT_ABSORB)); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) @@ -1071,6 +1147,593 @@ class spell_pal_seal_of_righteousness : public AuraScript } }; +// -31871 - Divine Purpose +class spell_pal_divine_purpose : public AuraScript +{ + PrepareAuraScript(spell_pal_divine_purpose); + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (!roll_chance_i(aurEff->GetAmount())) + return; + + eventInfo.GetProcTarget()->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_divine_purpose::HandleProc, EFFECT_2, SPELL_AURA_DUMMY); + } +}; + +// 54939 - Glyph of Divinity +class spell_pal_glyph_of_divinity : public AuraScript +{ + PrepareAuraScript(spell_pal_glyph_of_divinity); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC }); + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + // Lay on Hands (Rank 1) does not have mana effect + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->Effects[EFFECT_1].Effect != SPELL_EFFECT_ENERGIZE) + return; + + Unit* caster = eventInfo.GetActor(); + if (caster == eventInfo.GetProcTarget()) + return; + + int32 mana = spellInfo->Effects[EFFECT_1].CalcValue() * 2; + caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC, SPELLVALUE_BASE_POINT1, mana, (Unit*)nullptr, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_divinity::OnProc, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER); + } +}; + +// 54937 - Glyph of Holy Light (dummy aura) +class spell_pal_glyph_of_holy_light_dummy : public AuraScript +{ + PrepareAuraScript(spell_pal_glyph_of_holy_light_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); + + caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_holy_light_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -20335 - Heart of the Crusader +class spell_pal_heart_of_the_crusader : public AuraScript +{ + PrepareAuraScript(spell_pal_heart_of_the_crusader); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank()); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_heart_of_the_crusader::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -20234 - Improved Lay on Hands +class spell_pal_improved_lay_of_hands : public AuraScript +{ + PrepareAuraScript(spell_pal_improved_lay_of_hands); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, GetTarget()->GetGUID()); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_improved_lay_of_hands::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// -53569 - Infusion of Light +class spell_pal_infusion_of_light : public AuraScript +{ + PrepareAuraScript(spell_pal_infusion_of_light); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PALADIN_SACRED_SHIELD, + SPELL_PALADIN_T9_HOLY_4P_BONUS, + SPELL_PALADIN_FLASH_OF_LIGHT_PROC + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + { + // Flash of Light HoT on Flash of Light when Sacred Shield active + if (spellInfo->SpellFamilyFlags[0] & 0x40000000 && spellInfo->SpellIconID == 242) + { + PreventDefaultAction(); + + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + Unit* procTarget = eventInfo.GetActionTarget(); + if (procTarget && procTarget->HasAura(SPELL_PALADIN_SACRED_SHIELD)) + { + Unit* target = GetTarget(); + int32 duration = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC)->GetMaxDuration() / 1000; + int32 pct = GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + int32 bp0 = CalculatePct(healInfo->GetHeal() / duration, pct); + + // Item - Paladin T9 Holy 4P Bonus + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_PALADIN_T9_HOLY_4P_BONUS, 0)) + AddPct(bp0, aurEff->GetAmount()); + + target->CastCustomSpell(SPELL_PALADIN_FLASH_OF_LIGHT_PROC, SPELLVALUE_BASE_POINT0, bp0, procTarget, true, nullptr, aurEff); + } + } + // but should not proc on non-critical Holy Shocks + else if ((spellInfo->SpellFamilyFlags[0] & 0x200000 || spellInfo->SpellFamilyFlags[1] & 0x10000) && !(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)) + PreventDefaultAction(); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_infusion_of_light::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 40470 - Paladin Tier 6 Trinket +class spell_pal_item_t6_trinket : public AuraScript +{ + PrepareAuraScript(spell_pal_item_t6_trinket); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PALADIN_ENDURING_LIGHT, + SPELL_PALADIN_ENDURING_JUDGEMENT + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + uint32 spellId; + int32 chance; + + // Holy Light & Flash of Light + if (spellInfo->SpellFamilyFlags[0] & 0xC0000000) + { + spellId = SPELL_PALADIN_ENDURING_LIGHT; + chance = 15; + } + // Judgements + else if (spellInfo->SpellFamilyFlags[0] & 0x00800000) + { + spellId = SPELL_PALADIN_ENDURING_JUDGEMENT; + chance = 50; + } + else + return; + + if (roll_chance_i(chance)) + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 20185 - Judgement of Light +class spell_pal_judgement_of_light_heal : public AuraScript +{ + PrepareAuraScript(spell_pal_judgement_of_light_heal); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetProcTarget(); + int32 amount = static_cast(caster->CountPctFromMaxHealth(aurEff->GetAmount())); + + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_light_heal::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 20186 - Judgement of Wisdom +class spell_pal_judgement_of_wisdom_mana : public AuraScript +{ + PrepareAuraScript(spell_pal_judgement_of_wisdom_mana); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget()->getPowerType() == POWER_MANA; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetProcTarget(); + int32 amount = CalculatePct(static_cast(caster->GetCreateMana()), aurEff->GetAmount()); + + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pal_judgement_of_wisdom_mana::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_wisdom_mana::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -53695 - Judgements of the Just +class spell_pal_judgements_of_the_just : public AuraScript +{ + PrepareAuraScript(spell_pal_judgements_of_the_just); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC }); + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + GetTarget()->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_just::OnProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER); + } +}; + +// -31876 - Judgements of the Wise +class spell_pal_judgements_of_the_wise : public AuraScript +{ + PrepareAuraScript(spell_pal_judgements_of_the_wise); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_REPLENISHMENT, + SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA + }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true); + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_wise::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 53601 - Sacred Shield (dummy) +class spell_pal_sacred_shield_dummy : public AuraScript +{ + PrepareAuraScript(spell_pal_sacred_shield_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PALADIN_SACRED_SHIELD_TRIGGER, + SPELL_PALADIN_T8_HOLY_4P_BONUS + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = GetCaster(); + if (!caster) + return; + + TimePoint now = GameTime::Now(); + if (_cooldownEnd > now) + return; + + Seconds cooldown(aurEff->GetAmount()); + if (AuraEffect const* bonus = caster->GetAuraEffect(SPELL_PALADIN_T8_HOLY_4P_BONUS, EFFECT_0, caster->GetGUID())) + cooldown = Seconds(bonus->GetAmount()); + + _cooldownEnd = now + cooldown; + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + + // Cooldown tracking can't be done in DB because of T8 bonus + TimePoint _cooldownEnd = std::chrono::steady_clock::time_point::min(); +}; + +// 31801 - Seal of Vengeance +// 53736 - Seal of Corruption +template +class spell_pal_seal_of_vengeance : public SpellScriptLoader +{ +public: + spell_pal_seal_of_vengeance(char const* ScriptName) : SpellScriptLoader(ScriptName) { } + + template + class spell_pal_seal_of_vengeance_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_seal_of_vengeance_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + DoTSpell, + DamageSpell + }); + } + + /* + When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system). + + 1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..) + 2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided. + + Remember #2 happens regardless of #1 landing, it just requires the initial attack (autos, cs, etc) to land. + + Stack Number % of Weapon Damage % with SotP + 0 0% 0% + 1 6.6% 7.6% + 2 13.2% 15.2% + 3 19.8% 22.8% + 4 26.4% 30.4% + 5 33% 38% + */ + + void HandleApplyDoT(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MELEE_AUTO_ATTACK)) + return; + + // don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, false); + } + + void HandleSeal(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); + if (!aurEff) + return; + + uint8 stacks = aurEff->GetBase()->GetStackAmount(); + uint8 maxStacks = aurEff->GetSpellInfo()->StackAmount; + + if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS)) + return; + + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(DamageSpell); + int32 amount = spellInfo->Effects[EFFECT_0].CalcValue(); + amount *= stacks; + amount /= maxStacks; + + caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleApplyDoT, EFFECT_0, SPELL_AURA_DUMMY); + OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleSeal, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_pal_seal_of_vengeance_AuraScript(); + } +}; + +// 20375 - Seal of Command +// 21084 - Seal of Righteousness +// 31801 - Seal of Vengeance +// 31892 - Seal of Blood +// 33127 - Seal of Command +// 38008 - Seal of Blood +// 41459 - Seal of Blood +// 53720 - Seal of the Martyr +// 53736 - Seal of Corruption +class spell_pal_seals : public AuraScript +{ + PrepareAuraScript(spell_pal_seals); + + // Effect 2 is used by Judgement code, we prevent the proc to avoid console logging of unknown spell trigger + bool CheckDummyProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + return false; + } + + void Register() override + { + DoCheckEffectProc += AuraCheckEffectProcFn(spell_pal_seals::CheckDummyProc, EFFECT_2, SPELL_AURA_DUMMY); + } +}; + +// -31785 - Spiritual Attunement +class spell_pal_spiritual_attunement : public AuraScript +{ + PrepareAuraScript(spell_pal_spiritual_attunement); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + // "when healed by other friendly targets' spells" + if (eventInfo.GetProcTarget() == eventInfo.GetActionTarget()) + return false; + + return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetEffectiveHeal(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + HealInfo* healInfo = eventInfo.GetHealInfo(); + int32 amount = CalculatePct(static_cast(healInfo->GetEffectiveHeal()), aurEff->GetAmount()); + + eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pal_spiritual_attunement::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pal_spiritual_attunement::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 28789 - Holy Power +class spell_pal_t3_6p_bonus : public AuraScript +{ + PrepareAuraScript(spell_pal_t3_6p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PALADIN_HOLY_POWER_ARMOR, + SPELL_PALADIN_HOLY_POWER_ATTACK_POWER, + SPELL_PALADIN_HOLY_POWER_SPELL_POWER, + SPELL_PALADIN_HOLY_POWER_MP5 + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + uint32 spellId; + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + switch (target->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + spellId = SPELL_PALADIN_HOLY_POWER_MP5; + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + spellId = SPELL_PALADIN_HOLY_POWER_SPELL_POWER; + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + spellId = SPELL_PALADIN_HOLY_POWER_ATTACK_POWER; + break; + case CLASS_WARRIOR: + spellId = SPELL_PALADIN_HOLY_POWER_ARMOR; + break; + default: + return; + } + + caster->CastSpell(target, spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pal_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + void AddSC_paladin_spell_scripts() { RegisterSpellAndAuraScriptPair(spell_pal_seal_of_command, spell_pal_seal_of_command_aura); @@ -1091,6 +1754,7 @@ void AddSC_paladin_spell_scripts() RegisterSpellAndAuraScriptPair(spell_pal_hand_of_sacrifice, spell_pal_hand_of_sacrifice_aura); RegisterSpellScript(spell_pal_hand_of_salvation); RegisterSpellScript(spell_pal_holy_shock); + RegisterSpellScript(spell_pal_illumination); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_justice", SPELL_PALADIN_JUDGEMENT_OF_JUSTICE); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_light", SPELL_PALADIN_JUDGEMENT_OF_LIGHT); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_wisdom", SPELL_PALADIN_JUDGEMENT_OF_WISDOM); @@ -1098,4 +1762,21 @@ void AddSC_paladin_spell_scripts() RegisterSpellScript(spell_pal_lay_on_hands); RegisterSpellScript(spell_pal_righteous_defense); RegisterSpellScript(spell_pal_seal_of_righteousness); + RegisterSpellScript(spell_pal_divine_purpose); + RegisterSpellScript(spell_pal_glyph_of_divinity); + RegisterSpellScript(spell_pal_glyph_of_holy_light_dummy); + RegisterSpellScript(spell_pal_heart_of_the_crusader); + RegisterSpellScript(spell_pal_improved_lay_of_hands); + RegisterSpellScript(spell_pal_infusion_of_light); + RegisterSpellScript(spell_pal_item_t6_trinket); + RegisterSpellScript(spell_pal_judgement_of_light_heal); + RegisterSpellScript(spell_pal_judgement_of_wisdom_mana); + RegisterSpellScript(spell_pal_judgements_of_the_just); + RegisterSpellScript(spell_pal_judgements_of_the_wise); + RegisterSpellScript(spell_pal_sacred_shield_dummy); + new spell_pal_seal_of_vengeance("spell_pal_seal_of_vengeance"); + new spell_pal_seal_of_vengeance("spell_pal_seal_of_corruption"); + RegisterSpellScript(spell_pal_seals); + RegisterSpellScript(spell_pal_spiritual_attunement); + RegisterSpellScript(spell_pal_t3_6p_bonus); } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 89624091b..b53807cac 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -31,6 +31,7 @@ enum PriestSpells { + SPELL_PRIEST_BLESSED_RECOVERY_R1 = 27813, SPELL_PRIEST_DIVINE_AEGIS = 47753, SPELL_PRIEST_EMPOWERED_RENEW = 63544, SPELL_PRIEST_GLYPH_OF_CIRCLE_OF_HEALING = 55675, @@ -53,7 +54,22 @@ enum PriestSpells SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411, SPELL_PRIEST_TWIN_DISCIPLINE_R1 = 47586, SPELL_PRIEST_SPIRITUAL_HEALING_R1 = 14898, - SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562 + SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562, + + SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227, + SPELL_REPLENISHMENT = 57669, + SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER = 64136, + SPELL_PRIEST_ABOLISH_DISEASE = 552, + SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL = 15290, + SPELL_PRIEST_DIVINE_BLESSING = 40440, + SPELL_PRIEST_DIVINE_WRATH = 40441, + SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL = 56131, + SPELL_PRIEST_ORACULAR_HEAL = 26170, + SPELL_PRIEST_ARMOR_OF_FAITH = 28810, + SPELL_PRIEST_BLESSED_HEALING = 70772, + SPELL_PRIEST_MIND_BLAST_R1 = 8092, + SPELL_PRIEST_SHADOW_WORD_DEATH_R1 = 32379, + SPELL_PRIEST_MIND_FLAY_DAMAGE = 58381 }; enum PriestSpellIcons @@ -149,6 +165,41 @@ class spell_pri_shadowfiend_scaling : public AuraScript } }; +// -27811 - Blessed Recovery +class spell_pri_blessed_recovery : public AuraScript +{ + PrepareAuraScript(spell_pri_blessed_recovery); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_BLESSED_RECOVERY_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* dmgInfo = eventInfo.GetDamageInfo(); + if (!dmgInfo || !dmgInfo->GetDamage()) + return; + + Unit* target = eventInfo.GetActionTarget(); + uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_PRIEST_BLESSED_RECOVERY_R1, aurEff->GetSpellInfo()->GetRank()); + SpellInfo const* triggerInfo = sSpellMgr->AssertSpellInfo(triggerSpell); + + int32 bp = CalculatePct(static_cast(dmgInfo->GetDamage()), aurEff->GetAmount()); + + ASSERT(triggerInfo->GetMaxTicks() > 0); + bp /= triggerInfo->GetMaxTicks(); + + target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_blessed_recovery::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // -34861 - Circle of Healing class spell_pri_circle_of_healing : public SpellScript { @@ -349,15 +400,6 @@ class spell_pri_item_greater_heal_refund : public AuraScript return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY }); } - bool CheckProc(ProcEventInfo& eventInfo) - { - if (HealInfo* healInfo = eventInfo.GetHealInfo()) - if (Unit* healTarget = healInfo->GetTarget()) - if (eventInfo.GetHitMask() & PROC_EX_NO_OVERHEAL && healTarget->IsFullHealth()) - return true; - return false; - } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); @@ -366,7 +408,6 @@ class spell_pri_item_greater_heal_refund : public AuraScript void Register() override { - DoCheckProc += AuraCheckProcFn(spell_pri_item_greater_heal_refund::CheckProc); OnEffectProc += AuraEffectProcFn(spell_pri_item_greater_heal_refund::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -522,6 +563,33 @@ class spell_pri_mind_sear : public SpellScript } }; +// -47580 - Pain and Suffering (dummy aura) +class spell_pri_pain_and_suffering_dummy : public SpellScriptLoader +{ +public: + spell_pri_pain_and_suffering_dummy() : SpellScriptLoader("spell_pri_pain_and_suffering_dummy") { } + + class spell_pri_pain_and_suffering_dummy_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_pain_and_suffering_dummy_AuraScript); + + bool CheckDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + return false; + } + + void Register() override + { + DoCheckEffectProc += AuraCheckEffectProcFn(spell_pri_pain_and_suffering_dummy_AuraScript::CheckDummy, EFFECT_1, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_pri_pain_and_suffering_dummy_AuraScript; + } +}; + // 47948 - Pain and Suffering (Proc) class spell_pri_pain_and_suffering_proc : public SpellScript { @@ -926,9 +994,326 @@ class spell_pri_mind_control : public AuraScript } }; +// 26169 - Oracle Healing Bonus +class spell_pri_aq_3p_bonus : public AuraScript +{ + PrepareAuraScript(spell_pri_aq_3p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_ORACULAR_HEAL }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + if (caster == eventInfo.GetProcTarget()) + return; + + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), 10); + caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_aq_3p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -64127 - Body and Soul +class spell_pri_body_and_soul : public AuraScript +{ + PrepareAuraScript(spell_pri_body_and_soul); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, + SPELL_PRIEST_ABOLISH_DISEASE + }); + } + + void HandleProcTriggerSpell(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + // Proc only on Power Word: Shield + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000001)) + { + PreventDefaultAction(); + return; + } + } + + void HandleProcDummy(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + // Proc only on self casted abolish disease + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + Unit* caster = eventInfo.GetActor(); + if (spellInfo->Id != SPELL_PRIEST_ABOLISH_DISEASE || caster != eventInfo.GetProcTarget()) + return; + + if (roll_chance_i(aurEff->GetAmount())) + caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcTriggerSpell, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcDummy, EFFECT_1, SPELL_AURA_DUMMY); + } +}; + +// 55677 - Glyph of Dispel Magic +class spell_pri_glyph_of_dispel_magic : public AuraScript +{ + PrepareAuraScript(spell_pri_glyph_of_dispel_magic); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + // Dispel Magic shares spellfamilyflag with abolish disease + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellIconID != 74) + return; + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + int32 amount = static_cast(target->CountPctFromMaxHealth(aurEff->GetAmount())); + + caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_dispel_magic::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -47569 - Improved Shadowform +class spell_pri_imp_shadowform : public AuraScript +{ + PrepareAuraScript(spell_pri_imp_shadowform); + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (roll_chance_i(aurEff->GetAmount())) + eventInfo.GetActor()->RemoveMovementImpairingAuras(true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_imp_shadowform::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -15337 - Improved Spirit Tap +class spell_pri_improved_spirit_tap : public AuraScript +{ + PrepareAuraScript(spell_pri_improved_spirit_tap); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PRIEST_SHADOW_WORD_DEATH_R1, + SPELL_PRIEST_MIND_BLAST_R1 + }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + { + if (spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_SHADOW_WORD_DEATH_R1)) || + spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_MIND_BLAST_R1))) + return true; + else if (spellInfo->Id == SPELL_PRIEST_MIND_FLAY_DAMAGE) + return roll_chance_i(50); + } + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pri_improved_spirit_tap::CheckProc); + } +}; + +// 40438 - Priest Tier 6 Trinket +class spell_pri_item_t6_trinket : public AuraScript +{ + PrepareAuraScript(spell_pri_item_t6_trinket); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_PRIEST_DIVINE_BLESSING, + SPELL_PRIEST_DIVINE_WRATH + }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL) + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true); + + if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE) + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 57989 - Shadowfiend Death +class spell_pri_shadowfiend_death : public AuraScript +{ + PrepareAuraScript(spell_pri_shadowfiend_death); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return false; + + Unit* shadowfiend = eventInfo.GetActionTarget(); + if (!shadowfiend->GetOwner()) + return false; + + return shadowfiend->HealthBelowPctDamaged(1, damageInfo->GetDamage()); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActionTarget()->GetOwner(); + caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pri_shadowfiend_death::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pri_shadowfiend_death::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 15286 - Vampiric Embrace +class spell_pri_vampiric_embrace : public AuraScript +{ + PrepareAuraScript(spell_pri_vampiric_embrace); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 selfHeal = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + int32 partyHeal = selfHeal / 5; + Unit* caster = eventInfo.GetActor(); + caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_vampiric_embrace::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 28809 - Greater Heal +class spell_pri_t3_4p_bonus : public AuraScript +{ + PrepareAuraScript(spell_pri_t3_4p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_ARMOR_OF_FAITH }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_pri_t3_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 37594 - Greater Heal Refund +class spell_pri_t5_heal_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_pri_t5_heal_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (HealInfo* healInfo = eventInfo.GetHealInfo()) + if (Unit* healTarget = healInfo->GetTarget()) + if (healInfo->GetEffectiveHeal()) + if (healTarget->GetHealth() >= healTarget->GetMaxHealth()) + return true; + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_pri_t5_heal_2p_bonus::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pri_t5_heal_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + void AddSC_priest_spell_scripts() { RegisterSpellScript(spell_pri_shadowfiend_scaling); + RegisterSpellScript(spell_pri_blessed_recovery); RegisterSpellScript(spell_pri_circle_of_healing); RegisterSpellScript(spell_pri_divine_aegis); RegisterSpellScript(spell_pri_divine_hymn); @@ -941,6 +1326,7 @@ void AddSC_priest_spell_scripts() RegisterSpellScript(spell_pri_mana_burn); RegisterSpellScript(spell_pri_mana_leech); RegisterSpellScript(spell_pri_mind_sear); + new spell_pri_pain_and_suffering_dummy(); RegisterSpellScript(spell_pri_pain_and_suffering_proc); RegisterSpellScript(spell_pri_penance); RegisterSpellAndAuraScriptPair(spell_pri_power_word_shield, spell_pri_power_word_shield_aura); @@ -949,4 +1335,14 @@ void AddSC_priest_spell_scripts() RegisterSpellScript(spell_pri_shadow_word_death); RegisterSpellScript(spell_pri_vampiric_touch); RegisterSpellScript(spell_pri_mind_control); + RegisterSpellScript(spell_pri_aq_3p_bonus); + RegisterSpellScript(spell_pri_body_and_soul); + RegisterSpellScript(spell_pri_glyph_of_dispel_magic); + RegisterSpellScript(spell_pri_imp_shadowform); + RegisterSpellScript(spell_pri_improved_spirit_tap); + RegisterSpellScript(spell_pri_item_t6_trinket); + RegisterSpellScript(spell_pri_shadowfiend_death); + RegisterSpellScript(spell_pri_vampiric_embrace); + RegisterSpellScript(spell_pri_t3_4p_bonus); + RegisterSpellScript(spell_pri_t5_heal_2p_bonus); } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index bb6b8b9e2..1b419b899 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -42,6 +42,9 @@ enum RogueSpells SPELL_ROGUE_SHIV_TRIGGERED = 5940, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628, + SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER = 63975, + SPELL_ROGUE_QUICK_RECOVERY_ENERGY = 31663, + SPELL_ROGUE_CRIPPLING_POISON = 3409 }; class spell_rog_savage_combat : public AuraScript @@ -126,7 +129,7 @@ class spell_rog_blade_flurry : public AuraScript CustomSpellValues values; values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); - values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_EX_CRITICAL_HIT)); + values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)); GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, values, procTarget, TRIGGERED_FULL_MASK, nullptr, aurEff); } } @@ -675,6 +678,154 @@ class spell_rog_tricks_of_the_trade_proc : public AuraScript } }; +// -51664 - Cut to the Chase +class spell_rog_cut_to_the_chase : public AuraScript +{ + PrepareAuraScript(spell_rog_cut_to_the_chase); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + // "refresh your Slice and Dice duration to its 5 combo point maximum" + Unit* caster = eventInfo.GetActor(); + // lookup Slice and Dice + if (AuraEffect const* snd = caster->GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x00040000, 0x00000000, 0x00000000, caster->GetGUID())) + { + // Max 5 cp duration + uint32 countMax = snd->GetSpellInfo()->GetMaxDuration(); + + snd->GetBase()->SetDuration(countMax, true); + snd->GetBase()->SetMaxDuration(snd->GetBase()->GetDuration()); + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_rog_cut_to_the_chase::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -51625 - Deadly Brew +class spell_rog_deadly_brew : public AuraScript +{ + PrepareAuraScript(spell_rog_deadly_brew); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ROGUE_CRIPPLING_POISON }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_rog_deadly_brew::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -31244 - Quick Recovery +class spell_rog_quick_recovery : public AuraScript +{ + PrepareAuraScript(spell_rog_quick_recovery); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ROGUE_QUICK_RECOVERY_ENERGY }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + Unit* caster = eventInfo.GetActor(); + int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_rog_quick_recovery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 56800 - Glyph of Backstab (dummy) +class spell_rog_glyph_of_backstab : public AuraScript +{ + PrepareAuraScript(spell_rog_glyph_of_backstab); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_rog_glyph_of_backstab::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -13983 - Setup +class spell_rog_setup : public AuraScript +{ + PrepareAuraScript(spell_rog_setup); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (Player* target = GetTarget()->ToPlayer()) + if (eventInfo.GetActor() == target->GetSelectedUnit()) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_rog_setup::CheckProc); + } +}; + +// -51627 - Turn the Tables +class spell_rog_turn_the_tables : public AuraScript +{ + PrepareAuraScript(spell_rog_turn_the_tables); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + Unit* caster = GetCaster(); + if (!caster) + return; + + Unit* target = GetTarget(); + target->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, caster->GetGUID()); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_rog_turn_the_tables::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + void AddSC_rogue_spell_scripts() { RegisterSpellScript(spell_rog_savage_combat); @@ -690,4 +841,10 @@ void AddSC_rogue_spell_scripts() RegisterSpellScript(spell_rog_shiv); RegisterSpellScript(spell_rog_tricks_of_the_trade); RegisterSpellScript(spell_rog_tricks_of_the_trade_proc); + RegisterSpellScript(spell_rog_cut_to_the_chase); + RegisterSpellScript(spell_rog_deadly_brew); + RegisterSpellScript(spell_rog_quick_recovery); + RegisterSpellScript(spell_rog_glyph_of_backstab); + RegisterSpellScript(spell_rog_setup); + RegisterSpellScript(spell_rog_turn_the_tables); } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 6977a0824..098dac0c4 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -31,6 +31,7 @@ enum ShamanSpells { + SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY = 52759, SPELL_SHAMAN_GLYPH_OF_FERAL_SPIRIT = 63271, SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC = 52752, SPELL_SHAMAN_BIND_SIGHT = 6277, @@ -49,8 +50,10 @@ enum ShamanSpells SPELL_SHAMAN_ITEM_MANA_SURGE = 23571, SPELL_SHAMAN_LAVA_FLOWS_R1 = 51480, SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 64694, + SPELL_SHAMAN_LIGHTNING_SHIELD_R1 = 26364, SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE = 52032, SPELL_SHAMAN_MANA_TIDE_TOTEM = 39609, + SPELL_SHAMAN_NATURE_GUARDIAN = 31616, SPELL_SHAMAN_SATED = 57724, SPELL_SHAMAN_STORM_EARTH_AND_FIRE = 51483, SPELL_SHAMAN_TOTEM_EARTHBIND_EARTHGRAB = 64695, @@ -59,13 +62,66 @@ enum ShamanSpells SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042, SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554, SPELL_SHAMAN_STORMSTRIKE = 17364, - SPELL_SHAMAN_LAVA_LASH = 60103 + SPELL_SHAMAN_LAVA_LASH = 60103, + SPELL_SHAMAN_TOTEMIC_MASTERY = 38437, + SPELL_SHAMAN_TIDAL_FORCE_CRIT = 55166, + SPELL_SHAMAN_TOTEMIC_POWER_MP5 = 28824, + SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER = 28825, + SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER = 28826, + SPELL_SHAMAN_TOTEMIC_POWER_ARMOR = 28827, + SPELL_SHAMAN_WINDFURY_WEAPON_R1 = 8232, + SPELL_SHAMAN_WINDFURY_ATTACK_MH = 25504, + SPELL_SHAMAN_WINDFURY_ATTACK_OH = 33750, + SPELL_SHAMAN_ENERGY_SURGE = 40465, + SPELL_SHAMAN_POWER_SURGE = 40466, + SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL = 55533, + SPELL_SHAMAN_SPIRIT_HUNT_HEAL = 58879, + SPELL_SHAMAN_ELECTRIFIED = 64930, + SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE = 71824, + SPELL_SHAMAN_CHAINED_HEAL = 70809, + SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER = 63283, + SPELL_SHAMAN_FREEZE = 63685, + SPELL_SHAMAN_FLAMETONGUE_ATTACK = 10444, + SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1 = 45284, + SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1 = 45297, + SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 = 26364, + SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC = 30824, + SPELL_SHAMAN_MAELSTROM_POWER = 70831, + SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS = 70832 }; enum ShamanSpellIcons { SHAMAN_ICON_ID_RESTORATIVE_TOTEMS = 338, - SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087 + SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087, + SHAMAN_ICON_ID_TOTEM_OF_WRATH = 2019 +}; + +// -51556 - Ancestral Awakening +class spell_sha_ancestral_awakening : public AuraScript +{ + PrepareAuraScript(spell_sha_ancestral_awakening); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); + eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_ancestral_awakening::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } }; class spell_sha_totem_of_wrath : public SpellScript @@ -143,24 +199,30 @@ class spell_sha_t10_restoration_4p_bonus : public AuraScript } }; +// 38443 - Totemic Mastery (Tier 6 - 2P) class spell_sha_totemic_mastery : public AuraScript { PrepareAuraScript(spell_sha_totemic_mastery); - void HandlePeriodic(AuraEffect const* /*aurEff*/) + bool Validate(SpellInfo const* /*spellInfo*/) override { - PreventDefaultAction(); + return ValidateSpellInfo({ SPELL_SHAMAN_TOTEMIC_MASTERY }); + } - for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) - if (!GetTarget()->m_SummonSlot[i]) + void HandleDummy(AuraEffect const* aurEff) + { + Unit* target = GetTarget(); + for (uint8 i = SUMMON_TYPE_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i) + if (!target->m_SummonSlot[i]) return; - GetTarget()->CastSpell(GetTarget(), 38437, true); + target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, aurEff); + PreventDefaultAction(); } void Register() override { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_totemic_mastery::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_totemic_mastery::HandleDummy, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; @@ -772,6 +834,218 @@ class spell_sha_flame_shock : public AuraScript } }; +// -10400 - Flametongue Weapon (Passive) +class spell_sha_flametongue_weapon : public AuraScript +{ + PrepareAuraScript(spell_sha_flametongue_weapon); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_FLAMETONGUE_ATTACK }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Player* player = eventInfo.GetActor()->ToPlayer(); + if (!player) + return false; + + Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID()); + if (!item || !item->IsEquipped()) + return false; + + WeaponAttackType attType = static_cast(player->GetAttackBySlot(item->GetSlot())); + if (attType != BASE_ATTACK && attType != OFF_ATTACK) + return false; + + if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) || + ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK))) + return false; + + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Player* player = eventInfo.GetActor()->ToPlayer(); + Unit* target = eventInfo.GetProcTarget(); + WeaponAttackType attType = BASE_ATTACK; + if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK) + attType = OFF_ATTACK; + + Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); + + float basePoints(GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue()); + + // Flametongue max damage is normalized based on a 4.0 speed weapon + // Tooltip says max damage = BasePoints / 25, so BasePoints / 25 / 4 to get base damage per 1.0s AS + float fireDamage = basePoints / 100.0f; + float attackSpeed = player->GetAttackTime(attType) / 1000.f; + fireDamage *= attackSpeed; + + // clip value between (BasePoints / 77) and (BasePoints / 25) as the tooltip indicates + RoundToInterval(fireDamage, basePoints / 77.0f, basePoints / 25.0f); + + // Calculate Spell Power scaling + float spellPowerBonus(player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); + float const spCoeff = 0.03811f; + spellPowerBonus *= spCoeff * attackSpeed; + + // All done, now proc damage + int32 amount = static_cast(fireDamage + spellPowerBonus); + player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_flametongue_weapon::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_flametongue_weapon::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -63373 - Frozen Power +class spell_sha_frozen_power : public AuraScript +{ + PrepareAuraScript(spell_sha_frozen_power); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_FREEZE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + if (!roll_chance_i(aurEff->GetAmount())) + return; + + Unit* caster = eventInfo.GetActor(); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_FREEZE); + float minDistance(spellInfo->GetEffect(EFFECT_0).CalcValue(caster)); + + Unit* target = eventInfo.GetProcTarget(); + if (caster->GetDistance(target) < minDistance) + return; + + caster->CastSpell(target, SPELL_SHAMAN_FREEZE, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_frozen_power::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); + } +}; + +// 63279 - Glyph of Earth Shield +class spell_sha_glyph_of_earth_shield : public AuraScript +{ + PrepareAuraScript(spell_sha_glyph_of_earth_shield); + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + SpellInfo const* earthShield = eventInfo.GetSpellInfo(); + if (!earthShield) + return; + + AuraEffect* earthShieldEffect = eventInfo.GetProcTarget()->GetAuraEffect(earthShield->Id, EFFECT_0, eventInfo.GetActor()->GetGUID()); + if (!earthShieldEffect) + return; + + int32 amount = earthShieldEffect->GetAmount(); + AddPct(amount, aurEff->GetAmount()); + earthShieldEffect->SetAmount(amount); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_earth_shield::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 55440 - Glyph of Healing Wave +class spell_sha_glyph_of_healing_wave : public AuraScript +{ + PrepareAuraScript(spell_sha_glyph_of_healing_wave); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + if (caster == eventInfo.GetProcTarget()) + return; + + HealInfo* healInfo = eventInfo.GetHealInfo(); + if (!healInfo || !healInfo->GetHeal()) + return; + + int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_healing_wave::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 63280 - Glyph of Totem of Wrath +class spell_sha_glyph_of_totem_of_wrath : public AuraScript +{ + PrepareAuraScript(spell_sha_glyph_of_totem_of_wrath); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + // Totem of Wrath shares family flags with other totems + // filter by spellIcon instead + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellIconID != SHAMAN_ICON_ID_TOTEM_OF_WRATH) + return false; + + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + + // Fire totem summon slot + Creature* totem = ObjectAccessor::GetCreature(*caster, caster->m_SummonSlot[1]); + if (!totem) + return; + + SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(totem->m_spells[0]); + if (!totemSpell) + return; + + int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); + int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(caster), aurEff->GetAmount()); + caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_glyph_of_totem_of_wrath::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_totem_of_wrath::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 52041, 52046, 52047, 52048, 52049, 52050, 58759, 58760, 58761 - Healing Stream Totem class spell_sha_healing_stream_totem : public SpellScript { @@ -787,6 +1061,7 @@ class spell_sha_healing_stream_totem : public SpellScript int32 damage = GetEffectValue(); SpellInfo const* triggeringSpell = GetTriggeringSpell(); if (Unit* target = GetHitUnit()) + { if (Unit* caster = GetCaster()) { if (Unit* owner = caster->GetOwner()) @@ -806,6 +1081,7 @@ class spell_sha_healing_stream_totem : public SpellScript } caster->CastCustomSpell(target, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); } + } } void Register() override @@ -821,13 +1097,12 @@ class spell_sha_heroism : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo({ SPELL_SHAMAN_EXHAUSTION, SPELL_SHAMAN_SATED }); + return ValidateSpellInfo({ SPELL_SHAMAN_EXHAUSTION }); } void RemoveInvalidTargets(std::list& targets) { targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SHAMAN_EXHAUSTION)); - targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SHAMAN_SATED)); } void ApplyDebuff() @@ -838,140 +1113,43 @@ class spell_sha_heroism : public SpellScript void Register() override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_RAID); + AfterHit += SpellHitFn(spell_sha_heroism::ApplyDebuff); } }; -// 23551 - Lightning Shield -class spell_sha_item_lightning_shield : public AuraScript +// -324 - Lightning Shield +class spell_sha_lightning_shield : public AuraScript { - PrepareAuraScript(spell_sha_item_lightning_shield); + PrepareAuraScript(spell_sha_lightning_shield); bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 23552 - Lightning Shield -class spell_sha_item_lightning_shield_trigger : public AuraScript -{ - PrepareAuraScript(spell_sha_item_lightning_shield_trigger); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_MANA_SURGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield_trigger::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 23572 - Mana Surge -class spell_sha_item_mana_surge : public AuraScript -{ - PrepareAuraScript(spell_sha_item_mana_surge); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE }); + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LIGHTNING_SHIELD_R1)) + return false; + return true; } bool CheckProc(ProcEventInfo& eventInfo) { - return eventInfo.GetSpellInfo() != nullptr; + if (eventInfo.GetActionTarget()) + return true; + return false; } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - int32 mana = eventInfo.GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); - int32 damage = CalculatePct(mana, 35); + uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_R1, aurEff->GetSpellInfo()->GetRank()); - GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, nullptr, aurEff); + eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), triggerSpell, true, nullptr, aurEff); } void Register() override { - DoCheckProc += AuraCheckProcFn(spell_sha_item_mana_surge::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 70811 - Item - Shaman T10 Elemental 2P Bonus -class spell_sha_item_t10_elemental_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_sha_item_t10_elemental_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ELEMENTAL_MASTERY }); - } - - void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - if (Player* target = GetTarget()->ToPlayer()) - target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_t10_elemental_2p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 60103 - Lava Lash -class spell_sha_lava_lash : public SpellScript -{ - PrepareSpellScript(spell_sha_lava_lash) - - bool Load() override - { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - - void HandleDummy(SpellEffIndex /*effIndex*/) - { - if (Player* caster = GetCaster()->ToPlayer()) - { - int32 damage = GetEffectValue(); - int32 hitDamage = GetHitDamage(); - if (caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) - { - // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. - if (caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) - AddPct(hitDamage, damage); - SetHitDamage(hitDamage); - } - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_sha_lava_lash::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + DoCheckProc += AuraCheckProcFn(spell_sha_lightning_shield::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -1035,6 +1213,46 @@ class spell_sha_mana_tide_totem : public SpellScript } }; +// -30881 - Nature's Guardian +class spell_sha_nature_guardian : public AuraScript +{ + PrepareAuraScript(spell_sha_nature_guardian); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_NATURE_GUARDIAN)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 healthpct = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); // %s2 - the 30% threshold for health + + if (Unit* target = eventInfo.GetActionTarget()) + { + if (target->HealthBelowPctDamaged(healthpct, eventInfo.GetDamageInfo()->GetDamage())) + { + + uint32 bp = CalculatePct(target->GetMaxHealth(), aurEff->GetAmount()); + target->CastCustomSpell(SPELL_SHAMAN_NATURE_GUARDIAN, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); + + // @TODO: FIX ME PLEASE + // Threat reduction is around 10% confirmed in retail and from wiki +// Unit* attacker = eventInfo.GetActor(); +// if (attacker->IsAlive()) +// attacker->getThreatMgr().modifyThreatPercent(target, -10); + } + } + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_nature_guardian::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 6495 - Sentry Totem class spell_sha_sentry_totem : public AuraScript { @@ -1104,8 +1322,632 @@ class spell_sha_flurry_proc : public AuraScript } }; +class spell_sha_astral_shift_aura : public AuraScript +{ + PrepareAuraScript(spell_sha_astral_shift_aura); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR))) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_astral_shift_aura::CheckProc); + } +}; + +// -16180 - Improved Water Shield +class spell_sha_imp_water_shield : public AuraScript +{ + PrepareAuraScript(spell_sha_imp_water_shield); + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + // If we're here, we've already passed initial aura roll + // So just chance based on 100% + + // Default chance for Healing Wave and Riptide + int32 chance = 100; + // Lesser Healing Wave - 0.6 of default + if (spellInfo->SpellFamilyFlags[0] & 0x00000080) + chance = 60; + // Chain heal - 0.3 of default + else if (spellInfo->SpellFamilyFlags[0] & 0x00000100) + chance = 30; + + if (!roll_chance_i(chance)) + return false; + + return true; + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + // Get Water Shield + AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); + if (!aurEff) + return; + + uint32 spellId = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + caster->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_imp_water_shield::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_imp_water_shield::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -30675 - Lightning Overload +class spell_sha_lightning_overload : public AuraScript +{ + PrepareAuraScript(spell_sha_lightning_overload); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1, + SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1 + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + uint32 spellId; + + // Lightning Bolt + if (spellInfo->SpellFamilyFlags[0] & 0x00000001) + spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1, spellInfo->GetRank()); + // Chain Lightning + else + { + // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit. + // A maxed LO would have a 33% / 3 = 11% chance to proc of each target. + // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets] + float chance = 100.0f / spellInfo->GetEffect(EFFECT_0).ChainTarget; + if (!roll_chance_f(chance)) + return; + + spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1, spellInfo->GetRank()); + } + + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_lightning_overload::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 23551 - Lightning Shield T2 Bonus +class spell_sha_item_lightning_shield : public AuraScript +{ + PrepareAuraScript(spell_sha_item_lightning_shield); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 23552 - Lightning Shield T2 Bonus +class spell_sha_item_lightning_shield_trigger : public AuraScript +{ + PrepareAuraScript(spell_sha_item_lightning_shield_trigger); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield_trigger::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 23572 - Mana Surge +class spell_sha_item_mana_surge : public AuraScript +{ + PrepareAuraScript(spell_sha_item_mana_surge); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_MANA_SURGE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); + int32 damage = CalculatePct(mana, 35); + + GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, NULL, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 40463 - Shaman Tier 6 Trinket +class spell_sha_item_t6_trinket : public AuraScript +{ + PrepareAuraScript(spell_sha_item_t6_trinket); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SHAMAN_ENERGY_SURGE, + SPELL_SHAMAN_POWER_SURGE + }); + } + + void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return; + + uint32 spellId; + int32 chance; + + // Lesser Healing Wave + if (spellInfo->SpellFamilyFlags[0] & 0x00000080) + { + spellId = SPELL_SHAMAN_ENERGY_SURGE; + chance = 10; + } + // Lightning Bolt + else if (spellInfo->SpellFamilyFlags[0] & 0x00000001) + { + spellId = SPELL_SHAMAN_ENERGY_SURGE; + chance = 15; + } + // Stormstrike + else if (spellInfo->SpellFamilyFlags[1] & 0x00000010) + { + spellId = SPELL_SHAMAN_POWER_SURGE; + chance = 50; + } + else + return; + + if (roll_chance_i(chance)) + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 70811 - Item - Shaman T10 Elemental 2P Bonus +class spell_sha_item_t10_elemental_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_sha_item_t10_elemental_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ELEMENTAL_MASTERY }); + } + + void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + if (Player* target = GetTarget()->ToPlayer()) + target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_t10_elemental_2p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 60103 - Lava Lash +class spell_sha_lava_lash : public SpellScript +{ + PrepareSpellScript(spell_sha_lava_lash); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Player* caster = GetCaster()->ToPlayer()) + { + int32 damage = GetEffectValue(); + int32 hitDamage = GetHitDamage(); + if (Item* offhand = caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) + { + // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) + if (aurEff->GetBase()->GetCastItemGUID() == offhand->GetGUID()) + AddPct(hitDamage, damage); + SetHitDamage(hitDamage); + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_sha_lava_lash::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + } + +}; + +// 53817 - Maelstrom Weapon +class spell_sha_maelstrom_weapon : public AuraScript +{ + PrepareAuraScript(spell_sha_maelstrom_weapon); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SHAMAN_MAELSTROM_POWER, + SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS + }); + } + + void HandleBonus(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetStackAmount() < GetSpellInfo()->StackAmount) + return; + + Unit* caster = GetUnitOwner(); + AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS, EFFECT_0); + if (!aurEff || !roll_chance_i(aurEff->GetAmount())) + return; + + caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_sha_maelstrom_weapon::HandleBonus, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER, AURA_EFFECT_HANDLE_CHANGE_AMOUNT); + } +}; + +// 30823 - Shamanistic Rage +class spell_sha_shamanistic_rage : public AuraScript +{ + PrepareAuraScript(spell_sha_shamanistic_rage); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + Unit* target = GetTarget(); + int32 amount = CalculatePct(static_cast(target->GetTotalAttackPowerValue(BASE_ATTACK)), aurEff->GetAmount()); + target->CastCustomSpell(SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_shamanistic_rage::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 58877 - Spirit Hunt +class spell_sha_spirit_hunt : public AuraScript +{ + PrepareAuraScript(spell_sha_spirit_hunt); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_SPIRIT_HUNT_HEAL }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + Unit* caster = eventInfo.GetActor(); + Unit* target = caster->GetOwner(); + if (!target) + return; + + int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_spirit_hunt::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// -51525 - Static Shock +class spell_sha_static_shock : public AuraScript +{ + PrepareAuraScript(spell_sha_static_shock); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + + // Get Lightning Shield + AuraEffect const* lightningShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000400, 0x00000000, 0x00000000, caster->GetGUID()); + if (!lightningShield) + return; + + uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, lightningShield->GetSpellInfo()->GetRank()); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + lightningShield->GetBase()->DropCharge(); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_static_shock::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 55198 - Tidal Force +class spell_sha_tidal_force_dummy : public AuraScript +{ + PrepareAuraScript(spell_sha_tidal_force_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_TIDAL_FORCE_CRIT }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetActor()->RemoveAuraFromStack(SPELL_SHAMAN_TIDAL_FORCE_CRIT); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_tidal_force_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 28823 - Totemic Power +class spell_sha_t3_6p_bonus : public AuraScript +{ + PrepareAuraScript(spell_sha_t3_6p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SHAMAN_TOTEMIC_POWER_ARMOR, + SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER, + SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER, + SPELL_SHAMAN_TOTEMIC_POWER_MP5 + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + uint32 spellId; + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + switch (target->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + spellId = SPELL_SHAMAN_TOTEMIC_POWER_MP5; + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + spellId = SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER; + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + spellId = SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER; + break; + case CLASS_WARRIOR: + spellId = SPELL_SHAMAN_TOTEMIC_POWER_ARMOR; + break; + default: + return; + } + + caster->CastSpell(target, spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 70817 - Item - Shaman T10 Elemental 4P Bonus +class spell_sha_t10_elemental_4p_bonus : public AuraScript +{ + PrepareAuraScript(spell_sha_t10_elemental_4p_bonus); + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* caster = eventInfo.GetActor(); + Unit* target = eventInfo.GetProcTarget(); + + // try to find spell Flame Shock on the target + AuraEffect* flameShock = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x00000000, 0x00000000, caster->GetGUID()); + if (!flameShock) + return; + + Aura* flameShockAura = flameShock->GetBase(); + + int32 maxDuration = flameShockAura->GetMaxDuration(); + int32 newDuration = flameShockAura->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS; + + flameShockAura->SetDuration(newDuration); + // is it blizzlike to change max duration for FS? + if (newDuration > maxDuration) + flameShockAura->SetMaxDuration(newDuration); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_t10_elemental_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 33757 - Windfury Weapon (Passive) +class spell_sha_windfury_weapon : public AuraScript +{ + PrepareAuraScript(spell_sha_windfury_weapon); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_SHAMAN_WINDFURY_WEAPON_R1, + SPELL_SHAMAN_WINDFURY_ATTACK_MH, + SPELL_SHAMAN_WINDFURY_ATTACK_OH + }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + Player* player = eventInfo.GetActor()->ToPlayer(); + if (!player) + return false; + + Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID()); + if (!item || !item->IsEquipped()) + return false; + + WeaponAttackType attType = static_cast(player->GetAttackBySlot(item->GetSlot())); + if (attType != BASE_ATTACK && attType != OFF_ATTACK) + return false; + + if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) || + ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK))) + return false; + + return true; + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Player* player = eventInfo.GetActor()->ToPlayer(); + + uint32 spellId = 0; + WeaponAttackType attType = BASE_ATTACK; + if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK) + spellId = SPELL_SHAMAN_WINDFURY_ATTACK_MH; + + if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK) + { + spellId = SPELL_SHAMAN_WINDFURY_ATTACK_OH; + attType = OFF_ATTACK; + } + + Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); + + int32 enchantId = static_cast(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); + int32 extraAttackPower = 0; + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_WINDFURY_WEAPON_R1); + while (spellInfo) + { + if (spellInfo->Effects[EFFECT_0].MiscValue == enchantId) + { + extraAttackPower = spellInfo->Effects[EFFECT_1].CalcValue(player); + break; + } + spellInfo = spellInfo->GetNextRankSpell(); + } + + if (!extraAttackPower) + return; + + // Value gained from additional AP + int32 amount = static_cast(extraAttackPower / 14.f * player->GetAttackTime(attType) / 1000.f); + + // Attack twice + for (uint8 i = 0; i < 2; ++i) + player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_windfury_weapon::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_windfury_weapon::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + void AddSC_shaman_spell_scripts() { + RegisterSpellScript(spell_sha_ancestral_awakening); RegisterSpellScript(spell_sha_totem_of_wrath); RegisterSpellScript(spell_sha_spirit_walk); RegisterSpellScript(spell_sha_t10_restoration_4p_bonus); @@ -1130,9 +1972,29 @@ void AddSC_shaman_spell_scripts() RegisterSpellScript(spell_sha_item_mana_surge); RegisterSpellScript(spell_sha_item_t10_elemental_2p_bonus); RegisterSpellScript(spell_sha_lava_lash); + RegisterSpellScript(spell_sha_lightning_shield); RegisterSpellScript(spell_sha_mana_spring_totem); RegisterSpellScript(spell_sha_mana_tide_totem); + RegisterSpellScript(spell_sha_nature_guardian); RegisterSpellScript(spell_sha_sentry_totem); RegisterSpellScript(spell_sha_thunderstorm); RegisterSpellScript(spell_sha_flurry_proc); + RegisterSpellScript(spell_sha_flametongue_weapon); + RegisterSpellScript(spell_sha_frozen_power); + RegisterSpellScript(spell_sha_glyph_of_earth_shield); + RegisterSpellScript(spell_sha_glyph_of_healing_wave); + RegisterSpellScript(spell_sha_glyph_of_totem_of_wrath); + RegisterSpellScript(spell_sha_healing_stream_totem); + RegisterSpellScript(spell_sha_astral_shift_aura); + RegisterSpellScript(spell_sha_imp_water_shield); + RegisterSpellScript(spell_sha_lightning_overload); + RegisterSpellScript(spell_sha_item_t6_trinket); + RegisterSpellScript(spell_sha_maelstrom_weapon); + RegisterSpellScript(spell_sha_shamanistic_rage); + RegisterSpellScript(spell_sha_spirit_hunt); + RegisterSpellScript(spell_sha_static_shock); + RegisterSpellScript(spell_sha_tidal_force_dummy); + RegisterSpellScript(spell_sha_t3_6p_bonus); + RegisterSpellScript(spell_sha_t10_elemental_4p_bonus); + RegisterSpellScript(spell_sha_windfury_weapon); } diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index f23d3a247..f17cf7f8b 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -43,6 +43,7 @@ enum WarlockSpells SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444, + SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090, SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181, SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_AURA = 58070, SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_PROC = 58068, @@ -58,17 +59,38 @@ enum WarlockSpells SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956, SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818, SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553, + SPELL_WARLOCK_NETHER_PROTECTION_HOLY = 54370, + SPELL_WARLOCK_NETHER_PROTECTION_FIRE = 54371, + SPELL_WARLOCK_NETHER_PROTECTION_FROST = 54372, + SPELL_WARLOCK_NETHER_PROTECTION_ARCANE = 54373, + SPELL_WARLOCK_NETHER_PROTECTION_SHADOW = 54374, + SPELL_WARLOCK_NETHER_PROTECTION_NATURE = 54375, SPELL_WARLOCK_SOULSHATTER = 32835, SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106, SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117, SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213, - SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371 + SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371, + SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED = 63321, + SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 = 27285, + SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC = 32865, + SPELL_WARLOCK_SHADOW_TRANCE = 17941, + SPELL_WARLOCK_SOUL_LEECH_HEAL = 30294, + SPELL_WARLOCK_IMP_SOUL_LEECH_R1 = 54117, + SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1 = 54607, + SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 = 59118, + SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1 = 54300, + SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 = 59117, + SPELL_REPLENISHMENT = 57669, + SPELL_WARLOCK_SHADOWFLAME = 37378, + SPELL_WARLOCK_FLAMESHADOW = 37379, + SPELL_WARLOCK_GLYPH_OF_SUCCUBUS = 56250 }; enum WarlockSpellIcons { WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208, - WARLOCK_ICON_ID_MANA_FEED = 1982 + WARLOCK_ICON_ID_MANA_FEED = 1982, + WARLOCK_ICON_ID_DEMONIC_PACT = 3220 }; class spell_warl_eye_of_kilrogg : public AuraScript @@ -637,6 +659,42 @@ class spell_warl_everlasting_affliction : public SpellScript } }; +// 54909, 53646 - Demonic Pact +class spell_warl_demonic_pact : public AuraScript +{ + PrepareAuraScript(spell_warl_demonic_pact); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_DEMONIC_PACT_PROC }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetActor() && eventInfo.GetActor()->IsPet(); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + if (Unit* owner = eventInfo.GetActor()->GetOwner()) + { + if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_DEMONIC_PACT, EFFECT_0)) + { + int32 bp0 = static_cast((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC) + 100.0f) / 100.0f); + owner->CastCustomSpell(SPELL_WARLOCK_DEMONIC_PACT_PROC, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true, nullptr, aurEff); + } + } + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warl_demonic_pact::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warl_demonic_pact::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 18541 - Ritual of Doom Effect class spell_warl_ritual_of_doom_effect : public SpellScript { @@ -654,6 +712,92 @@ class spell_warl_ritual_of_doom_effect : public SpellScript } }; +// -27243 - Seed of Corruption +class spell_warl_seed_of_corruption_dummy : public AuraScript +{ + PrepareAuraScript(spell_warl_seed_of_corruption_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 amount = aurEff->GetAmount() - damageInfo->GetDamage(); + if (amount > 0) + { + const_cast(aurEff)->SetAmount(amount); + if (!GetTarget()->HealthBelowPctDamaged(1, damageInfo->GetDamage())) + return; + } + + Remove(); + + Unit* caster = GetCaster(); + if (!caster) + return; + + uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank()); + caster->CastSpell(eventInfo.GetActionTarget(), spellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_dummy::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); + } +}; + +// 32863 - Seed of Corruption +// 36123 - Seed of Corruption +// 38252 - Seed of Corruption +// 39367 - Seed of Corruption +// 44141 - Seed of Corruption +// 70388 - Seed of Corruption +// Monster spells, triggered only on amount drop (not on death) +class spell_warl_seed_of_corruption_generic : public AuraScript +{ + PrepareAuraScript(spell_warl_seed_of_corruption_generic); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + int32 amount = aurEff->GetAmount() - damageInfo->GetDamage(); + if (amount > 0) + { + const_cast(aurEff)->SetAmount(amount); + return; + } + + Remove(); + + Unit* caster = GetCaster(); + if (!caster) + return; + + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_generic::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); + } +}; + // -27285 - Seed of Corruption class spell_warl_seed_of_corruption : public SpellScript { @@ -684,6 +828,61 @@ class spell_warl_seed_of_corruption : public SpellScript } }; +// -30293 - Soul Leech +class spell_warl_soul_leech : public AuraScript +{ + PrepareAuraScript(spell_warl_soul_leech); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_WARLOCK_SOUL_LEECH_HEAL, + SPELL_WARLOCK_IMP_SOUL_LEECH_R1, + SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, + SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2, + SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, + SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2, + SPELL_REPLENISHMENT + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + static uint32 const casterMana[2] = { SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 }; + static uint32 const petMana[2] = { SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 }; + + PreventDefaultAction(); + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo || !damageInfo->GetDamage()) + return; + + Unit* caster = eventInfo.GetActor(); + int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); + caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true); + + // Improved Soul Leech code below + AuraEffect const* impSoulLeech = GetTarget()->GetAuraEffectOfRankedSpell(SPELL_WARLOCK_IMP_SOUL_LEECH_R1, EFFECT_1, aurEff->GetCasterGUID()); + if (!impSoulLeech) + return; + + uint8 impSoulLeechRank = impSoulLeech->GetSpellInfo()->GetRank(); + uint32 selfSpellId = casterMana[impSoulLeechRank - 1]; + uint32 petSpellId = petMana[impSoulLeechRank - 1]; + + caster->CastSpell((Unit*)nullptr, selfSpellId, true); + caster->CastSpell((Unit*)nullptr, petSpellId, true); + + if (roll_chance_i(impSoulLeech->GetAmount())) + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_soul_leech::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 29858 - Soulshatter class spell_warl_soulshatter : public SpellScript { @@ -813,6 +1012,97 @@ class spell_warl_life_tap : public SpellScript } }; +// -30299 - Nether Protection +class spell_warl_nether_protection : public AuraScript +{ + PrepareAuraScript(spell_warl_nether_protection); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_NETHER_PROTECTION_HOLY, SPELL_WARLOCK_NETHER_PROTECTION_FIRE, SPELL_WARLOCK_NETHER_PROTECTION_FROST, SPELL_WARLOCK_NETHER_PROTECTION_ARCANE, SPELL_WARLOCK_NETHER_PROTECTION_SHADOW, SPELL_WARLOCK_NETHER_PROTECTION_NATURE }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetDamageInfo()) + { + switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) + { + case SPELL_SCHOOL_HOLY: + case SPELL_SCHOOL_FIRE: + case SPELL_SCHOOL_NATURE: + case SPELL_SCHOOL_FROST: + case SPELL_SCHOOL_SHADOW: + case SPELL_SCHOOL_ARCANE: + return true; + default: + break; + } + } + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + uint32 triggerspell = 0; + + switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) + { + case SPELL_SCHOOL_HOLY: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_HOLY; + break; + case SPELL_SCHOOL_FIRE: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FIRE; + break; + case SPELL_SCHOOL_NATURE: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_NATURE; + break; + case SPELL_SCHOOL_FROST: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FROST; + break; + case SPELL_SCHOOL_SHADOW: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_SHADOW; + break; + case SPELL_SCHOOL_ARCANE: + triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_ARCANE; + break; + default: + return; + } + + if (Unit* target = eventInfo.GetActionTarget()) + target->CastSpell(target, triggerspell, true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warl_nether_protection::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warl_nether_protection::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// -63156 - Decimation +class spell_warl_decimation : public AuraScript +{ + PrepareAuraScript(spell_warl_decimation); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) + if (eventInfo.GetActionTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, eventInfo.GetActor())) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warl_decimation::CheckProc); + } +}; + // 48018 - Demonic Circle: Summon class spell_warl_demonic_circle_summon : public AuraScript { @@ -968,6 +1258,31 @@ class spell_warl_haunt_aura : public AuraScript } }; +// 37377 - Shadowflame +// 39437 - Shadowflame Hellfire and RoF +template +class spell_warl_t4_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_warl_t4_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ TriggerSpellId }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, TriggerSpellId, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // -30108 - Unstable Affliction class spell_warl_unstable_affliction : public AuraScript { @@ -1098,6 +1413,53 @@ class spell_warl_shadow_ward : public AuraScript } }; +// -18094 - Nightfall +// 56218 - Glyph of Corruption +class spell_warl_glyph_of_corruption_nightfall : public AuraScript +{ + PrepareAuraScript(spell_warl_glyph_of_corruption_nightfall); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_SHADOW_TRANCE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_corruption_nightfall::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 63320 - Glyph of Life Tap +class spell_warl_glyph_of_life_tap : public AuraScript +{ + PrepareAuraScript(spell_warl_glyph_of_life_tap); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_life_tap::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 63310 - Glyph of Shadowflame class spell_warl_glyph_of_shadowflame : public AuraScript { @@ -1292,6 +1654,7 @@ void AddSC_warlock_spell_scripts() RegisterSpellAndAuraScriptPair(spell_warl_haunt, spell_warl_haunt_aura); RegisterSpellScript(spell_warl_health_funnel); RegisterSpellScript(spell_warl_life_tap); + RegisterSpellScript(spell_warl_nether_protection); RegisterSpellScript(spell_warl_ritual_of_doom_effect); RegisterSpellScript(spell_warl_seed_of_corruption); RegisterSpellScript(spell_warl_shadow_ward); @@ -1299,6 +1662,15 @@ void AddSC_warlock_spell_scripts() RegisterSpellScript(spell_warl_soulshatter); RegisterSpellScript(spell_warl_unstable_affliction); RegisterSpellScript(spell_warl_drain_soul); + RegisterSpellScript(spell_warl_demonic_pact); + RegisterSpellScript(spell_warl_decimation); + RegisterSpellScript(spell_warl_seed_of_corruption_dummy); + RegisterSpellScript(spell_warl_seed_of_corruption_generic); + RegisterSpellScript(spell_warl_soul_leech); + RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus, "spell_warl_t4_2p_bonus_shadow"); + RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus, "spell_warl_t4_2p_bonus_fire"); + RegisterSpellScript(spell_warl_glyph_of_corruption_nightfall); + RegisterSpellScript(spell_warl_glyph_of_life_tap); RegisterSpellScript(spell_warl_shadowburn); RegisterSpellScript(spell_warl_glyph_of_felguard); } diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 77108ca9a..723d987e4 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -35,6 +35,7 @@ enum WarriorSpells SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER = 59725, SPELL_WARRIOR_BLOODTHIRST = 23885, SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881, + SPELL_WARRIOR_BLOODSURGE_R1 = 29723, SPELL_WARRIOR_CHARGE = 34846, SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653, SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162, @@ -42,6 +43,8 @@ enum WarriorSpells SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721, SPELL_WARRIOR_EXECUTE = 20647, + SPELL_WARRIOR_EXECUTE_GCD_REDUCED = 71069, + SPELL_WARRIOR_EXTRA_CHARGE = 70849, SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367, SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326, SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, @@ -49,6 +52,8 @@ enum WarriorSpells SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976, SPELL_WARRIOR_RETALIATION_DAMAGE = 22858, SPELL_WARRIOR_SLAM = 50783, + SPELL_WARRIOR_SLAM_GCD_REDUCED = 71072, + SPELL_WARRIOR_SUDDEN_DEATH_R1 = 46913, SPELL_WARRIOR_SUNDER_ARMOR = 58567, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1 = 12723, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2 = 26654, @@ -59,6 +64,11 @@ enum WarriorSpells SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, SPELL_WARRIOR_VIGILANCE_PROC = 50725, SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665, + SPELL_WARRIOR_SECOND_WIND_TRIGGER_1 = 29841, + SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 = 29842, + SPELL_WARRIOR_GLYPH_OF_BLOCKING = 58374, + SPELL_WARRIOR_STOICISM = 70845, + SPELL_WARRIOR_T10_MELEE_4P_BONUS = 70847, SPELL_WARRIOR_WHIRLWIND_OFF = 44949 }; @@ -73,6 +83,7 @@ enum MiscSpells SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899, SPELL_PRIEST_RENEWED_HOPE = 63944, SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066, + SPELL_CATEGORY_SHIELD_SLAM = 1209 }; class spell_warr_mocking_blow : public SpellScript @@ -224,6 +235,31 @@ class spell_warr_improved_spell_reflection_trigger_aura : public AuraScript } }; +// 70844 - Item - Warrior T10 Protection 4P Bonus +class spell_warr_item_t10_prot_4p_bonus : public AuraScript +{ + PrepareAuraScript(spell_warr_item_t10_prot_4p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARRIOR_STOICISM }); + } + + void HandleProc(ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* target = eventInfo.GetActionTarget(); + int32 bp0 = CalculatePct(target->GetMaxHealth(), GetSpellInfo()->Effects[EFFECT_1].CalcValue()); + target->CastCustomSpell(SPELL_WARRIOR_STOICISM, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true); + } + + void Register() override + { + OnProc += AuraProcFn(spell_warr_item_t10_prot_4p_bonus::HandleProc); + } +}; + // 12975 - Last Stand class spell_warr_last_stand : public SpellScript { @@ -254,7 +290,13 @@ class spell_warr_deep_wounds : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo({ SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC }); + return ValidateSpellInfo( + { + SPELL_WARRIOR_DEEP_WOUNDS_RANK_1, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_2, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_3, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -269,7 +311,7 @@ class spell_warr_deep_wounds : public SpellScript ApplyPct(damage, 16.0f * GetSpellInfo()->GetRank() / 6.0f); target->CastDelayedSpellWithPeriodicAmount(caster, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, SPELL_AURA_PERIODIC_DAMAGE, damage, EFFECT_0); - //caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true); + caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true); } } @@ -373,6 +415,47 @@ class spell_warr_damage_shield : public AuraScript } }; +// -12834 - Deep Wounds Aura +class spell_warr_deep_wounds_aura : public AuraScript +{ + PrepareAuraScript(spell_warr_deep_wounds_aura); + + bool Validate(SpellInfo const* spellInfo) override + { + return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (!damageInfo) + return false; + + return eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER; + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + Unit* actor = eventInfo.GetActor(); + float damage = 0.f; + + if (eventInfo.GetDamageInfo()->GetAttackType() == OFF_ATTACK) + damage = (actor->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2.f; + else + damage = (actor->GetFloatValue(UNIT_FIELD_MINDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2.f; + + actor->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, SPELLVALUE_BASE_POINT0, int32(damage), eventInfo.GetProcTarget(), true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warr_deep_wounds_aura::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warr_deep_wounds_aura::OnProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // -5308 - Execute class spell_warr_execute : public SpellScript { @@ -430,6 +513,71 @@ class spell_warr_execute : public SpellScript } }; +// -29723 - Sudden Death +// -46913 - Bloodsurge +class spell_warr_extra_proc : public AuraScript +{ + PrepareAuraScript(spell_warr_extra_proc); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_WARRIOR_T10_MELEE_4P_BONUS, + SPELL_WARRIOR_EXTRA_CHARGE, + SPELL_WARRIOR_SLAM_GCD_REDUCED, + SPELL_WARRIOR_EXECUTE_GCD_REDUCED + }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + Unit* target = GetTarget(); + AuraEffect const* bonusAurEff = target->GetAuraEffect(SPELL_WARRIOR_T10_MELEE_4P_BONUS, EFFECT_0); + if (!bonusAurEff) + return; + + if (!roll_chance_i(bonusAurEff->GetAmount())) + return; + + target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXTRA_CHARGE, true, nullptr, aurEff); + + SpellInfo const* auraInfo = aurEff->GetSpellInfo(); + if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_BLOODSURGE_R1))) + target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_SLAM_GCD_REDUCED, true, nullptr, aurEff); + else if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_SUDDEN_DEATH_R1))) + target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXECUTE_GCD_REDUCED, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warr_extra_proc::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 58375 - Glyph of Blocking +class spell_warr_glyph_of_blocking : public AuraScript +{ + PrepareAuraScript(spell_warr_glyph_of_blocking); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_WARRIOR_GLYPH_OF_BLOCKING }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* caster = eventInfo.GetActor(); + caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_warr_glyph_of_blocking::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 12809 - Concussion Blow class spell_warr_concussion_blow : public SpellScript { @@ -588,6 +736,46 @@ class spell_warr_rend : public AuraScript } }; +// -29834 - Second Wind +class spell_warr_second_wind : public AuraScript +{ + PrepareAuraScript(spell_warr_second_wind); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, + SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 + }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo) + return false; + + return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + static uint32 const triggeredSpells[2] = { SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 }; + + PreventDefaultAction(); + Unit* caster = eventInfo.GetActionTarget(); + uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1]; + caster->CastSpell(caster, spellId, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warr_second_wind::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warr_second_wind::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + // 64380, 65941 - Shattering Throw class spell_warr_shattering_throw : public SpellScript { @@ -678,6 +866,30 @@ private: Unit* _procTarget = nullptr; }; +// 28845 - Cheat Death +class spell_warr_t3_prot_8p_bonus : public AuraScript +{ + PrepareAuraScript(spell_warr_t3_prot_8p_bonus); + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetActionTarget()->HealthBelowPct(20)) + return true; + + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + if (damageInfo && damageInfo->GetDamage()) + if (GetTarget()->HealthBelowPctDamaged(20, damageInfo->GetDamage())) + return true; + + return false; + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc); + } +}; + // 50720 - Vigilance class spell_warr_vigilance : public AuraScript { @@ -812,38 +1024,6 @@ class spell_warr_glyph_of_sunder_armor : public AuraScript } }; -// Spell 28845 - Cheat Death - -enum CheatDeath -{ - SPELL_CHEAT_DEATH_TRIGGER = 28846 -}; - -class spell_warr_t3_prot_8p_bonus : public AuraScript -{ - PrepareAuraScript(spell_warr_t3_prot_8p_bonus); - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetActionTarget() && eventInfo.GetActionTarget()->GetHealthPct() <= 20.0f; - } - - void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (Unit* target = eventInfo.GetActionTarget()) - { - target->CastSpell(target, SPELL_CHEAT_DEATH_TRIGGER, true); - } - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_warr_t3_prot_8p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 20230 - Retaliation class spell_warr_retaliation : public AuraScript { @@ -904,4 +1084,10 @@ void AddSC_warrior_spell_scripts() RegisterSpellScript(spell_warr_vigilance); RegisterSpellScript(spell_warr_vigilance_trigger); RegisterSpellScript(spell_warr_t3_prot_8p_bonus); + RegisterSpellScript(spell_warr_item_t10_prot_4p_bonus); + RegisterSpellScript(spell_warr_deep_wounds_aura); + RegisterSpellScript(spell_warr_extra_proc); + RegisterSpellScript(spell_warr_glyph_of_blocking); + RegisterSpellScript(spell_warr_second_wind); + RegisterSpellScript(spell_warr_t3_prot_8p_bonus); } diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index 38f0d6405..fd173dd18 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -1676,7 +1676,7 @@ struct SpellEntry std::array SpellVisual; // 131-132 m_spellVisualID uint32 SpellIconID; // 133 m_spellIconID uint32 ActiveIconID; // 134 m_activeIconID - uint32 SpellPriority; // 135 not used + uint32 SpellPriority; // 135 std::array SpellName; // 136-151 m_name_lang //uint32 SpellNameFlag; // 152 not used std::array Rank; // 153-168 m_nameSubtext_lang diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 584e0c3f8..737338ae4 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -455,7 +455,7 @@ enum SpellAttr2 : uint32 SPELL_ATTR2_IGNORE_WEAPONSKILL = 0x08000000, // TITLE Unknown attribute 27@Attr2 SPELL_ATTR2_NOT_AN_ACTION = 0x10000000, // TITLE Unknown attribute 28@Attr2 SPELL_ATTR2_CANT_CRIT = 0x20000000, // TITLE Cannot critically strike - SPELL_ATTR2_ACTIVE_THREAT = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs + SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs SPELL_ATTR2_RETAIN_ITEM_CAST = 0x80000000 // TITLE Food buff (client only) }; @@ -471,7 +471,7 @@ enum SpellAttr3 : uint32 SPELL_ATTR3_NO_AVOIDANCE = 0x00000040, // TITLE Unknown attribute 6@Attr3 SPELL_ATTR3_DOT_STACKING_RULE = 0x00000080, // TITLE Stack separately for each caster SPELL_ATTR3_ONLY_ON_PLAYER = 0x00000100, // TITLE Can only target players - SPELL_ATTR3_NOT_A_PROC = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs + SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON = 0x00000400, // TITLE Require main hand weapon SPELL_ATTR3_ONLY_BATTLEGROUNDS = 0x00000800, // TITLE Can only be cast in battleground SPELL_ATTR3_ONLY_ON_GHOSTS = 0x00001000, // TITLE Can only target ghost players @@ -481,14 +481,14 @@ enum SpellAttr3 : uint32 SPELL_ATTR3_SUPRESS_CASTER_PROCS = 0x00010000, // TITLE Cannot trigger procs SPELL_ATTR3_SUPRESS_TARGET_PROCS = 0x00020000, // TITLE No initial aggro SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked - SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc + SPELL_ATTR3_DISABLE_PROC = 0x00080000, // TITLE Cannot trigger spells during aura proc SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unknown attribute 21@Attr3 SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Requires equipped Wand (Mainline: Do Not Trigger Target Stand) SPELL_ATTR3_NO_DAMAGE_HISTORY = 0x00800000, // TITLE Unknown attribute 23@Attr3 SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON = 0x01000000, // TITLE Requires offhand weapon SPELL_ATTR3_TREAT_AS_PERIODIC = 0x02000000, // TITLE Treat as periodic effect - SPELL_ATTR3_CAN_PROC_FROM_PROCS = 0x04000000, // TITLE Can trigger from triggered spells + SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED = 0x04000000, // TITLE Can trigger from triggered spells SPELL_ATTR3_ONLY_PROC_ON_CASTER = 0x08000000, // TITLE Drain Soul SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS = 0x10000000, // TITLE Unknown attribute 28@Attr3 SPELL_ATTR3_IGNORE_CASTER_MODIFIERS = 0x20000000, // TITLE Damage dealt is unaffected by modifiers @@ -3225,7 +3225,7 @@ enum DiminishingReturnsType }; // Diminishing Return Groups -enum DiminishingGroup +enum DiminishingGroup : uint16 { DIMINISHING_NONE = 0, DIMINISHING_BANISH = 1, diff --git a/src/server/shared/enuminfo_SharedDefines.cpp b/src/server/shared/enuminfo_SharedDefines.cpp index 751437861..23c16f9b8 100644 --- a/src/server/shared/enuminfo_SharedDefines.cpp +++ b/src/server/shared/enuminfo_SharedDefines.cpp @@ -445,7 +445,7 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr2 value) case SPELL_ATTR2_IGNORE_WEAPONSKILL: return { "SPELL_ATTR2_IGNORE_WEAPONSKILL", "Unknown attribute 27@Attr2", "" }; case SPELL_ATTR2_NOT_AN_ACTION: return { "SPELL_ATTR2_NOT_AN_ACTION", "Unknown attribute 28@Attr2", "" }; case SPELL_ATTR2_CANT_CRIT: return { "SPELL_ATTR2_CANT_CRIT", "Cannot critically strike", "" }; - case SPELL_ATTR2_ACTIVE_THREAT: return { "SPELL_ATTR2_ACTIVE_THREAT", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; + case SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC: return { "SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; case SPELL_ATTR2_RETAIN_ITEM_CAST: return { "SPELL_ATTR2_RETAIN_ITEM_CAST", "Food buff (client only)", "" }; default: throw std::out_of_range("value"); } @@ -489,7 +489,7 @@ AC_API_EXPORT SpellAttr2 EnumUtils::FromIndex(size_t index) case 27: return SPELL_ATTR2_IGNORE_WEAPONSKILL; case 28: return SPELL_ATTR2_NOT_AN_ACTION; case 29: return SPELL_ATTR2_CANT_CRIT; - case 30: return SPELL_ATTR2_ACTIVE_THREAT; + case 30: return SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC; case 31: return SPELL_ATTR2_RETAIN_ITEM_CAST; default: throw std::out_of_range("index"); } @@ -530,7 +530,7 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr2 value) case SPELL_ATTR2_IGNORE_WEAPONSKILL: return 27; case SPELL_ATTR2_NOT_AN_ACTION: return 28; case SPELL_ATTR2_CANT_CRIT: return 29; - case SPELL_ATTR2_ACTIVE_THREAT: return 30; + case SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC: return 30; case SPELL_ATTR2_RETAIN_ITEM_CAST: return 31; default: throw std::out_of_range("value"); } @@ -553,7 +553,7 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr3 value) case SPELL_ATTR3_NO_AVOIDANCE: return { "SPELL_ATTR3_NO_AVOIDANCE", "Unknown attribute 6@Attr3", "" }; case SPELL_ATTR3_DOT_STACKING_RULE: return { "SPELL_ATTR3_DOT_STACKING_RULE", "Stack separately for each caster", "" }; case SPELL_ATTR3_ONLY_ON_PLAYER: return { "SPELL_ATTR3_ONLY_ON_PLAYER", "Can only target players", "" }; - case SPELL_ATTR3_NOT_A_PROC: return { "SPELL_ATTR3_NOT_A_PROC", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; + case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return { "SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON", "Require main hand weapon", "" }; case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return { "SPELL_ATTR3_ONLY_BATTLEGROUNDS", "Can only be cast in battleground", "" }; case SPELL_ATTR3_ONLY_ON_GHOSTS: return { "SPELL_ATTR3_ONLY_ON_GHOSTS", "Can only target ghost players", "" }; @@ -563,14 +563,14 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr3 value) case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return { "SPELL_ATTR3_SUPRESS_CASTER_PROCS", "Cannot trigger procs", "" }; case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return { "SPELL_ATTR3_SUPRESS_TARGET_PROCS", "No initial aggro", "" }; case SPELL_ATTR3_ALWAYS_HIT: return { "SPELL_ATTR3_ALWAYS_HIT", "Ignore hit result", "Spell cannot miss, or be dodged/parried/blocked" }; - case SPELL_ATTR3_INSTANT_TARGET_PROCS: return { "SPELL_ATTR3_INSTANT_TARGET_PROCS", "Cannot trigger spells during aura proc", "" }; + case SPELL_ATTR3_DISABLE_PROC: return { "SPELL_ATTR3_DISABLE_PROC", "Cannot trigger spells during aura proc", "" }; case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return { "SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD", "Persists through death", "" }; case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return { "SPELL_ATTR3_ONLY_PROC_OUTDOORS", "Unknown attribute 21@Attr3", "" }; case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return { "SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT", "Requires equipped Wand (Mainline: Do Not Trigger Target Stand)", "" }; case SPELL_ATTR3_NO_DAMAGE_HISTORY: return { "SPELL_ATTR3_NO_DAMAGE_HISTORY", "Unknown attribute 23@Attr3", "" }; case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON", "Requires offhand weapon", "" }; case SPELL_ATTR3_TREAT_AS_PERIODIC: return { "SPELL_ATTR3_TREAT_AS_PERIODIC", "Treat as periodic effect", "" }; - case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return { "SPELL_ATTR3_CAN_PROC_FROM_PROCS", "Can trigger from triggered spells", "" }; + case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return { "SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED", "Can trigger from triggered spells", "" }; case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return { "SPELL_ATTR3_ONLY_PROC_ON_CASTER", "Drain Soul", "" }; case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return { "SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS", "Unknown attribute 28@Attr3", "" }; case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return { "SPELL_ATTR3_IGNORE_CASTER_MODIFIERS", "Damage dealt is unaffected by modifiers", "" }; @@ -597,7 +597,7 @@ AC_API_EXPORT SpellAttr3 EnumUtils::FromIndex(size_t index) case 6: return SPELL_ATTR3_NO_AVOIDANCE; case 7: return SPELL_ATTR3_DOT_STACKING_RULE; case 8: return SPELL_ATTR3_ONLY_ON_PLAYER; - case 9: return SPELL_ATTR3_NOT_A_PROC; + case 9: return SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2; case 10: return SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON; case 11: return SPELL_ATTR3_ONLY_BATTLEGROUNDS; case 12: return SPELL_ATTR3_ONLY_ON_GHOSTS; @@ -607,14 +607,14 @@ AC_API_EXPORT SpellAttr3 EnumUtils::FromIndex(size_t index) case 16: return SPELL_ATTR3_SUPRESS_CASTER_PROCS; case 17: return SPELL_ATTR3_SUPRESS_TARGET_PROCS; case 18: return SPELL_ATTR3_ALWAYS_HIT; - case 19: return SPELL_ATTR3_INSTANT_TARGET_PROCS; + case 19: return SPELL_ATTR3_DISABLE_PROC; case 20: return SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD; case 21: return SPELL_ATTR3_ONLY_PROC_OUTDOORS; case 22: return SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT; case 23: return SPELL_ATTR3_NO_DAMAGE_HISTORY; case 24: return SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON; case 25: return SPELL_ATTR3_TREAT_AS_PERIODIC; - case 26: return SPELL_ATTR3_CAN_PROC_FROM_PROCS; + case 26: return SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; case 27: return SPELL_ATTR3_ONLY_PROC_ON_CASTER; case 28: return SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS; case 29: return SPELL_ATTR3_IGNORE_CASTER_MODIFIERS; @@ -638,7 +638,7 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr3 value) case SPELL_ATTR3_NO_AVOIDANCE: return 6; case SPELL_ATTR3_DOT_STACKING_RULE: return 7; case SPELL_ATTR3_ONLY_ON_PLAYER: return 8; - case SPELL_ATTR3_NOT_A_PROC: return 9; + case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return 9; case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return 10; case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return 11; case SPELL_ATTR3_ONLY_ON_GHOSTS: return 12; @@ -648,14 +648,14 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr3 value) case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return 16; case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return 17; case SPELL_ATTR3_ALWAYS_HIT: return 18; - case SPELL_ATTR3_INSTANT_TARGET_PROCS: return 19; + case SPELL_ATTR3_DISABLE_PROC: return 19; case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return 20; case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return 21; case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return 22; case SPELL_ATTR3_NO_DAMAGE_HISTORY: return 23; case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return 24; case SPELL_ATTR3_TREAT_AS_PERIODIC: return 25; - case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return 26; + case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return 26; case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return 27; case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return 28; case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return 29; From 5fc680799ace6a0fc111fc449293a8cf119fe517 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Sun, 2 Oct 2022 17:41:48 +0000 Subject: [PATCH 02/25] chore(DB): import pending files Referenced commit(s): cbd3fd0967fd94a2a9eb96aaf55ebd69f32aa918 --- .../rev_1647677899565690722.sql => db_world/2022_10_02_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1647677899565690722.sql => db_world/2022_10_02_01.sql} (99%) diff --git a/data/sql/updates/pending_db_world/rev_1647677899565690722.sql b/data/sql/updates/db_world/2022_10_02_01.sql similarity index 99% rename from data/sql/updates/pending_db_world/rev_1647677899565690722.sql rename to data/sql/updates/db_world/2022_10_02_01.sql index f12d9986a..4672d680f 100644 --- a/data/sql/updates/pending_db_world/rev_1647677899565690722.sql +++ b/data/sql/updates/db_world/2022_10_02_01.sql @@ -1,3 +1,4 @@ +-- DB update 2022_10_02_00 -> 2022_10_02_01 -- Earth shield heal is DAMAGE_CLASS_NONE, it won't scale -- Entry is unneeded DELETE FROM `spell_bonus_data` WHERE `entry`=379; From 590525b86ce31ec2e8773bb62c95efc00d24b7c7 Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Sun, 2 Oct 2022 22:35:45 -0300 Subject: [PATCH 03/25] fix: Crash (#13230) --- src/server/game/Spells/Spell.cpp | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 937663428..96c900e3a 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3247,33 +3247,23 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) { if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { + m_caster->CastSpell(unit, i->triggeredSpell->Id, true); LOG_DEBUG("spells.aura", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id); // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration // set duration of current aura to the triggered spell if (i->triggeredSpell->GetDuration() == -1) { - // get duration from aura-only once - if (!_duration) - { - Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID()); - _duration = aur ? aur->GetDuration() : -1; - } - if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID())) { - triggeredAur->SetDuration(std::max(triggeredAur->GetDuration(), _duration)); + // get duration from aura-only once + if (!_duration) + { + Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID()); + _duration = aur ? aur->GetDuration() : -1; + } + triggeredAur->SetDuration(_duration); } - else - { - AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx); - m_caster->CastCustomSpell(i->triggeredSpell->Id, SPELLVALUE_AURA_DURATION, _duration, unit, true, nullptr, triggeringAuraEffect); - } - } - else - { - AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx); - m_caster->CastSpell(unit, i->triggeredSpell, true, nullptr, triggeringAuraEffect); } } } From be423a91b53538c92b28f14759f01c474bb8b277 Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Mon, 3 Oct 2022 16:14:43 -0300 Subject: [PATCH 04/25] fix: Crash (#13241) --- src/server/game/Entities/Unit/Unit.cpp | 8 +++ src/server/game/Spells/Spell.cpp | 11 +++- src/server/game/Spells/Spell.h | 1 + src/server/game/Spells/SpellDefines.h | 1 + .../game/Spells/SpellInfoCorrections.cpp | 4 ++ src/server/scripts/Pet/pet_hunter.cpp | 10 +-- src/server/scripts/Spells/spell_dk.cpp | 20 +++--- src/server/scripts/Spells/spell_druid.cpp | 32 ++++----- src/server/scripts/Spells/spell_generic.cpp | 4 +- src/server/scripts/Spells/spell_hunter.cpp | 18 ++--- src/server/scripts/Spells/spell_item.cpp | 66 +++++++++---------- src/server/scripts/Spells/spell_mage.cpp | 14 ++-- src/server/scripts/Spells/spell_paladin.cpp | 48 ++++++++------ src/server/scripts/Spells/spell_priest.cpp | 22 +++---- src/server/scripts/Spells/spell_rogue.cpp | 12 ++-- src/server/scripts/Spells/spell_shaman.cpp | 58 ++++++++-------- src/server/scripts/Spells/spell_warlock.cpp | 18 ++--- src/server/scripts/Spells/spell_warrior.cpp | 8 +-- 18 files changed, 190 insertions(+), 165 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 67669f562..fe8e6c407 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -12398,6 +12398,11 @@ void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uin void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc) { + Spell const* triggeringSpell = eventInfo.GetProcSpell(); + bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled(); + if (disableProcs) + SetCantProc(true); + for (auto const& aurAppProc : aurasTriggeringProc) { AuraApplication* aurApp; @@ -12422,6 +12427,9 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc SetCantProc(false); } } + + if (disableProcs) + SetCantProc(false); } SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 96c900e3a..20d8ad67c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2316,7 +2316,6 @@ void Spell::prepareDataForTriggerSystem() // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget // Because spell positivity is dependant on target } - m_hitMask = PROC_HIT_NONE; // Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && @@ -4074,8 +4073,14 @@ void Spell::handle_immediate() // process immediate effects (items, ground, etc.) also initialize some variables _handle_immediate_phase(); - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - DoAllEffectOnTarget(&(*ihit)); + // consider spell hit for some spells without target, so they may proc on finish phase correctly + if (m_UniqueTargetInfo.empty()) + m_hitMask = PROC_HIT_NORMAL; + else + { + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + DoAllEffectOnTarget(&(*ihit)); + } for (std::list::iterator ihit = m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index a0e0410ac..642ceda36 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -553,6 +553,7 @@ public: bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } bool IsAutoActionResetSpell() const; bool IsIgnoringCooldowns() const; + bool IsProcDisabled() const { return (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) != 0; } bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell.spellInfo); } diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index 2d4c34a24..d3bd7d3db 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -141,6 +141,7 @@ enum TriggerCastFlags TRIGGERED_IGNORE_SET_FACING = 0x00000200, //! Will not adjust facing to target (if any) TRIGGERED_IGNORE_SHAPESHIFT = 0x00000400, //! Will ignore shapeshift checks TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state + TRIGGERED_DISALLOW_PROC_EVENTS = 0x00001000, //! Disallows proc events from triggered spell (default) TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements // reuse 0x00020000 diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index a9e80a5e1..c47169b9d 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4458,6 +4458,10 @@ void SpellMgr::LoadSpellInfoCorrections() } } + // disable proc for magnet auras, they're handled differently + if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET)) + spellInfo->ProcFlags = 0; + if (spellInfo->ActiveIconID == 2158) // flight { spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 6e44ce98a..bd380476e 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -171,8 +171,8 @@ class spell_pet_charge : public AuraScript { return ValidateSpellInfo( { - SPELL_PET_SWOOP, - SPELL_PET_CHARGE + SPELL_PET_SWOOP, + SPELL_PET_CHARGE }); } @@ -224,7 +224,7 @@ class spell_pet_guard_dog : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true); + caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true, nullptr, aurEff); float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); eventInfo.GetProcTarget()->AddThreat(caster, addThreat); @@ -258,14 +258,14 @@ class spell_pet_silverback : public AuraScript return true; } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 }; PreventDefaultAction(); uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 1648ca722..07aee4a41 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -643,7 +643,7 @@ class spell_dk_wandering_plague_aura : public AuraScript PreventDefaultAction(); eventInfo.GetActor()->AddSpellCooldown(SPELL_DK_WANDERING_PLAGUE_TRIGGER, 0, 1000); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_TRIGGER, SPELLVALUE_BASE_POINT0, CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), eventInfo.GetActionTarget(), TRIGGERED_FULL_MASK); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_TRIGGER, SPELLVALUE_BASE_POINT0, CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), eventInfo.GetActionTarget(), TRIGGERED_FULL_MASK, nullptr, aurEff); } void Register() override @@ -2335,7 +2335,7 @@ class spell_dk_butchery : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -2357,7 +2357,7 @@ class spell_dk_glyph_of_scourge_strike : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, true, nullptr, aurEff); } void Register() override @@ -2385,10 +2385,10 @@ class spell_dk_pvp_4p_bonus : public AuraScript return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0; } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true); + eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true, nullptr, aurEff); } void Register() override @@ -2411,7 +2411,7 @@ class spell_dk_mark_of_blood : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, true, nullptr, aurEff); } void Register() override @@ -2439,7 +2439,7 @@ class spell_dk_necrosis : public AuraScript return; int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -2478,7 +2478,7 @@ class spell_dk_sudden_doom : public AuraScript if (!spellId) return; - caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -2545,7 +2545,7 @@ class spell_dk_threat_of_thassarian : public AuraScript return; spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank()); - caster->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -2569,7 +2569,7 @@ class spell_dk_vendetta : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 4e286aa5b..0811fa9e5 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -919,7 +919,7 @@ class spell_dru_savage_defense : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); int32 amount = static_cast(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount())); - caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1059,7 +1059,7 @@ class spell_dru_survival_instincts_aura : public AuraScript { Unit* target = GetTarget(); int32 bp0 = target->CountPctFromMaxHealth(aurEff->GetAmount()); - target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true); + target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true, nullptr, aurEff); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -1328,7 +1328,7 @@ class spell_dru_glyph_of_innervate : public AuraScript int32 amount = CalculatePct(static_cast(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount()); amount /= spellInfo->GetMaxTicks(); - caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1355,7 +1355,7 @@ class spell_dru_glyph_of_rake : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, true, nullptr, aurEff); } void Register() override @@ -1388,7 +1388,7 @@ class spell_dru_glyph_of_rejuvenation : public AuraScript return; int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } void Register() override @@ -1460,7 +1460,7 @@ class spell_dru_glyph_of_starfire_dummy : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, true, nullptr, aurEff); } void Register() override @@ -1512,7 +1512,7 @@ class spell_dru_revitalize : public AuraScript return; } - eventInfo.GetActor()->CastSpell(target, spellId, aurEff); + eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -1564,7 +1564,7 @@ class spell_dru_t3_2p_bonus : public AuraScript return; } - eventInfo.GetActor()->CastSpell(target, spellId, aurEff); + eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -1587,7 +1587,7 @@ class spell_dru_t3_6p_bonus : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, true, nullptr, aurEff); } void Register() override @@ -1615,7 +1615,7 @@ class spell_dru_t3_8p_bonus : public AuraScript Unit* caster = eventInfo.GetActor(); int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1635,10 +1635,10 @@ class spell_dru_t4_2p_bonus : public AuraScript return ValidateSpellInfo({ SPELL_DRUID_INFUSION }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true, nullptr, aurEff); } void Register() override @@ -1662,7 +1662,7 @@ class spell_dru_item_t6_trinket : public AuraScript }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -1693,7 +1693,7 @@ class spell_dru_item_t6_trinket : public AuraScript return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1729,12 +1729,12 @@ class spell_dru_t10_restoration_4p_bonus_dummy : public AuraScript return caster->GetGroup() || caster != eventInfo.GetProcTarget(); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); int32 amount = static_cast(eventInfo.GetHealInfo()->GetHeal()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index b01f9ad21..019ecf37b 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4540,7 +4540,7 @@ public: return ValidateSpellInfo({ _spellId1, _spellId2 }); } - void HandleProc(AuraEffect* /*aurEff*/) + void HandleProc(AuraEffect* aurEff) { if (Unit* caster = GetCaster()) { @@ -4550,7 +4550,7 @@ public: return; } - caster->CastSpell(GetUnitOwner(), _spellId1, true); + caster->CastSpell(GetUnitOwner(), _spellId1, true, nullptr, aurEff); } } diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index df6c63631..ec0279f8c 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -1165,7 +1165,7 @@ class spell_hun_glyph_of_arcane_shot : public AuraScript int32 mana = procSpell->CalcPowerCost(GetTarget(), procSpell->GetSchoolMask()); ApplyPct(mana, aurEff->GetAmount()); - GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget()); + GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), TRIGGERED_NONE, nullptr, aurEff); } void Register() override @@ -1314,7 +1314,7 @@ class spell_hun_lock_and_load : public AuraScript } Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true); + caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true, nullptr, aurEff); } void ApplyMarker(ProcEventInfo& eventInfo) @@ -1402,10 +1402,10 @@ class spell_hun_glyph_of_mend_pet : public AuraScript return ValidateSpellInfo({ SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true, nullptr, aurEff); } void Register() override @@ -1424,10 +1424,10 @@ class spell_hun_hunting_party : public AuraScript return ValidateSpellInfo({ SPELL_REPLENISHMENT }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1488,7 +1488,7 @@ class spell_hun_rapid_recuperation_trigger : public AuraScript } } - void HandleRapidKillingProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleRapidKillingProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 }; @@ -1501,7 +1501,7 @@ class spell_hun_rapid_recuperation_trigger : public AuraScript uint8 rank = GetSpellInfo()->GetRank(); uint32 spellId = triggerSpells[rank - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1549,7 +1549,7 @@ class spell_hun_thrill_of_the_hunt : public AuraScript if (!amount) return; - caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 68ca1f4e2..769d96e77 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -403,12 +403,12 @@ class spell_item_lil_phylactery : public AuraScript return eventInfo.GetActionTarget() && (eventInfo.GetActionTarget()->GetTypeId() != TYPEID_UNIT || eventInfo.GetActionTarget()->ToCreature()->isWorldBoss()); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); if (Unit* critter = ObjectAccessor::GetUnit(*GetUnitOwner(), GetUnitOwner()->GetCritterGUID())) - GetUnitOwner()->CastSpell(critter, 69731 /*SPELL_LICH_PET_AURA_ON_KILL*/, true); + GetUnitOwner()->CastSpell(critter, 69731 /*SPELL_LICH_PET_AURA_ON_KILL*/, true, nullptr, aurEff); } void Register() override @@ -954,10 +954,10 @@ class spell_item_trauma : public AuraScript return eventInfo.GetActionTarget(); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - GetUnitOwner()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); + GetUnitOwner()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff); } void Register() override @@ -971,7 +971,7 @@ class spell_item_blade_ward_enchant : public AuraScript { PrepareAuraScript(spell_item_blade_ward_enchant); - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); if (!eventInfo.GetActionTarget()) @@ -982,7 +982,7 @@ class spell_item_blade_ward_enchant : public AuraScript if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64442 /*SPELL_BLADE_WARDING*/)) { int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActor(), true); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActor(), true, nullptr, aurEff); } } @@ -1628,9 +1628,9 @@ class spell_item_fate_rune_of_unsurpassed_vigor : public AuraScript return ValidateSpellInfo({ SPELL_UNSURPASSED_VIGOR }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { - GetTarget()->CastSpell(GetTarget(), SPELL_UNSURPASSED_VIGOR, true); + GetTarget()->CastSpell(GetTarget(), SPELL_UNSURPASSED_VIGOR, true, nullptr, aurEff); } void Register() override @@ -2247,7 +2247,7 @@ class spell_item_unsated_craving : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, TRIGGERED_FULL_MASK); + eventInfo.GetActor()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, TRIGGERED_FULL_MASK, nullptr, aurEff); } void Register() override @@ -2261,7 +2261,7 @@ class spell_item_shadows_fate : public AuraScript { PrepareAuraScript(spell_item_shadows_fate); - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2270,7 +2270,7 @@ class spell_item_shadows_fate : public AuraScript if (!caster || !target) return; - caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK); + caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK, nullptr, aurEff); } void Register() override @@ -4029,7 +4029,7 @@ class spell_item_alchemists_stone : public AuraScript }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -4053,7 +4053,7 @@ class spell_item_alchemists_stone : public AuraScript } int32 amount = CalculatePct(spellInfo->Effects[i].CalcValue(caster), 40); - caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } } @@ -4096,7 +4096,7 @@ public: }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -4113,7 +4113,7 @@ public: if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) spellId = SPELL_MANIFEST_ANGER_OFF_HAND; - caster->CastSpell(target, spellId, true); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -4207,7 +4207,7 @@ class spell_item_aura_of_madness : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); uint32 spellId = Acore::Containers::SelectRandomContainerElement(triggeredSpells[caster->getClass()]); - caster->CastSpell(caster, spellId, aurEff); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); if (roll_chance_i(10)) caster->Unit::Say(SAY_MADNESS); @@ -4369,7 +4369,7 @@ public: return; uint32 spellId = Acore::Containers::SelectRandomContainerElement(randomSpells); - caster->CastSpell(caster, spellId, aurEff); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override @@ -4436,7 +4436,7 @@ class spell_item_frozen_shadoweave : public AuraScript int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -4461,10 +4461,10 @@ class spell_item_healing_touch_refund : public AuraScript return ValidateSpellInfo({ SPELL_HEALING_TOUCH_MANA }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true, nullptr, aurEff); } void Register() override @@ -4513,7 +4513,7 @@ public: }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -4530,7 +4530,7 @@ public: case POWER_RAGE: spellId = Rage; break; - // Death Knights can't use daggers, but oh well + // Death Knights can't use daggers, but oh well case POWER_RUNIC_POWER: spellId = RunicPower; break; @@ -4538,7 +4538,7 @@ public: return; } - caster->CastSpell((Unit*)nullptr, spellId, true); + caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -4592,14 +4592,14 @@ class spell_item_mark_of_conquest : public AuraScript return ValidateSpellInfo({ SPELL_MARK_OF_CONQUEST_ENERGIZE }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { if (eventInfo.GetTypeMask() & (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)) { // in that case, do not cast heal spell PreventDefaultAction(); // but mana instead - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true, nullptr, aurEff); } } @@ -4676,7 +4676,7 @@ class spell_item_pet_healing : public AuraScript int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -4706,7 +4706,7 @@ class spell_item_swift_hand_justice_dummy : public AuraScript Unit* caster = eventInfo.GetActor(); int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -4731,10 +4731,10 @@ class spell_item_totem_of_flowing_water : public AuraScript return ValidateSpellInfo({ SPELL_LESSER_HEALING_WAVE_MANA }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true, nullptr, aurEff); } void Register() override @@ -4784,10 +4784,10 @@ public: Unit* target = eventInfo.GetProcTarget(); if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) - caster->CastSpell(target, HealProc, aurEff); + caster->CastSpell(target, HealProc, true, nullptr, aurEff); if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG) - caster->CastSpell(target, DamageProc, aurEff); + caster->CastSpell(target, DamageProc, true, nullptr, aurEff); } void Register() override @@ -4864,10 +4864,10 @@ public: // Aggression checks are in the spell system... just cast and forget if (player->GetReputationRank(FACTION_ALDOR) == REP_EXALTED) - player->CastSpell(target, Aldors, aurEff); + player->CastSpell(target, Aldors, true, nullptr, aurEff); if (player->GetReputationRank(FACTION_SCRYERS) == REP_EXALTED) - player->CastSpell(target, Scryers, aurEff); + player->CastSpell(target, Scryers, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index e54941ec2..f2e32797a 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -154,10 +154,10 @@ class spell_mage_burning_determination : public AuraScript return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); - GetUnitOwner()->CastSpell(GetUnitOwner(), 54748, true); + GetUnitOwner()->CastSpell(GetUnitOwner(), 54748, true, nullptr, aurEff); } void Register() override @@ -993,7 +993,7 @@ class spell_mage_arcane_potency : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, aurEff); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override @@ -1064,10 +1064,10 @@ class spell_mage_imp_mana_gems : public AuraScript return ValidateSpellInfo({ SPELL_MAGE_MANA_SURGE }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true, nullptr, aurEff); } void Register() override @@ -1253,7 +1253,7 @@ class spell_mage_hot_streak : public AuraScript return; Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, aurEff); + caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, true, nullptr, aurEff); } // reset counter @@ -1281,7 +1281,7 @@ class spell_mage_magic_absorption : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget(); int32 bp = CalculatePct(static_cast(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true); + caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 032ed12d2..c77f49d8e 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -125,7 +125,8 @@ enum PaladinSpells enum PaladinSpellIcons { - PALADIN_ICON_ID_RETRIBUTION_AURA = 555 + PALADIN_ICON_ID_RETRIBUTION_AURA = 555, + PALADIN_ICON_ID_HAMMER_OF_THE_RIGHTEOUS = 3023 }; class spell_pal_seal_of_command_aura : public AuraScript @@ -1219,7 +1220,7 @@ class spell_pal_glyph_of_holy_light_dummy : public AuraScript Unit* target = eventInfo.GetProcTarget(); int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1243,7 +1244,7 @@ class spell_pal_heart_of_the_crusader : public AuraScript PreventDefaultAction(); uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1369,7 +1370,7 @@ class spell_pal_item_t6_trinket : public AuraScript return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1395,7 +1396,7 @@ class spell_pal_judgement_of_light_heal : public AuraScript Unit* caster = eventInfo.GetProcTarget(); int32 amount = static_cast(caster->CountPctFromMaxHealth(aurEff->GetAmount())); - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1426,7 +1427,7 @@ class spell_pal_judgement_of_wisdom_mana : public AuraScript Unit* caster = eventInfo.GetProcTarget(); int32 amount = CalculatePct(static_cast(caster->GetCreateMana()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1472,13 +1473,13 @@ class spell_pal_judgements_of_the_wise : public AuraScript }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true); - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true, nullptr, aurEff); + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1518,7 +1519,7 @@ class spell_pal_sacred_shield_dummy : public AuraScript cooldown = Seconds(bonus->GetAmount()); _cooldownEnd = now + cooldown; - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, aurEff); + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, true, nullptr, aurEff); } void Register() override @@ -1569,30 +1570,35 @@ public: 5 33% 38% */ - void HandleApplyDoT(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleApplyDoT(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MELEE_AUTO_ATTACK)) - return; + { + // Patch 3.2.0 Notes: Only auto-attacks and Hammer of the Righteous can place the debuff on the paladin's current target(s). + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellIconID != PALADIN_ICON_ID_HAMMER_OF_THE_RIGHTEOUS) + return; + } // don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, false); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, TRIGGERED_NO_PERIODIC_RESET, nullptr, aurEff); } - void HandleSeal(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleSeal(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); - AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); - if (!aurEff) + AuraEffect const* sealDot = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); + if (!sealDot) return; - uint8 stacks = aurEff->GetBase()->GetStackAmount(); - uint8 maxStacks = aurEff->GetSpellInfo()->StackAmount; + uint8 const stacks = sealDot->GetBase()->GetStackAmount(); + uint8 const maxStacks = sealDot->GetSpellInfo()->StackAmount; if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS)) return; @@ -1602,7 +1608,7 @@ public: amount *= stacks; amount /= maxStacks; - caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1668,7 +1674,7 @@ class spell_pal_spiritual_attunement : public AuraScript HealInfo* healInfo = eventInfo.GetHealInfo(); int32 amount = CalculatePct(static_cast(healInfo->GetEffectiveHeal()), aurEff->GetAmount()); - eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1725,7 +1731,7 @@ class spell_pal_t3_6p_bonus : public AuraScript return; } - caster->CastSpell(target, spellId, aurEff); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index b53807cac..e1d9295b9 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -1004,7 +1004,7 @@ class spell_pri_aq_3p_bonus : public AuraScript return ValidateSpellInfo({ SPELL_PRIEST_ORACULAR_HEAL }); } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); @@ -1016,7 +1016,7 @@ class spell_pri_aq_3p_bonus : public AuraScript return; int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), 10); - caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); + caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); } void Register() override @@ -1064,7 +1064,7 @@ class spell_pri_body_and_soul : public AuraScript return; if (roll_chance_i(aurEff->GetAmount())) - caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, aurEff); + caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, true, nullptr, aurEff); } void Register() override @@ -1096,7 +1096,7 @@ class spell_pri_glyph_of_dispel_magic : public AuraScript Unit* target = eventInfo.GetProcTarget(); int32 amount = static_cast(target->CountPctFromMaxHealth(aurEff->GetAmount())); - caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1171,15 +1171,15 @@ class spell_pri_item_t6_trinket : public AuraScript }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true); + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true, nullptr, aurEff); if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true); + caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true, nullptr, aurEff); } void Register() override @@ -1215,7 +1215,7 @@ class spell_pri_shadowfiend_death : public AuraScript { PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget()->GetOwner(); - caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, aurEff); + caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, aurEff, nullptr, aurEff); } void Register() override @@ -1245,7 +1245,7 @@ class spell_pri_vampiric_embrace : public AuraScript int32 selfHeal = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); int32 partyHeal = selfHeal / 5; Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true); + caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true, nullptr, aurEff); } void Register() override @@ -1267,7 +1267,7 @@ class spell_pri_t3_4p_bonus : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, true, nullptr, aurEff); } void Register() override @@ -1300,7 +1300,7 @@ class spell_pri_t5_heal_2p_bonus : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, aurEff); + GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 1b419b899..deee9a2a6 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -641,13 +641,13 @@ class spell_rog_tricks_of_the_trade : public AuraScript return _redirectTarget; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); Unit* target = GetTarget(); - target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true); - target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true); + target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true, nullptr, aurEff); + target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true, nullptr, aurEff); Remove(AURA_REMOVE_BY_DEFAULT); // maybe handle by proc charges } @@ -719,7 +719,7 @@ class spell_rog_deadly_brew : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, true, nullptr, aurEff); } void Register() override @@ -747,7 +747,7 @@ class spell_rog_quick_recovery : public AuraScript Unit* caster = eventInfo.GetActor(); int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -769,7 +769,7 @@ class spell_rog_glyph_of_backstab : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 098dac0c4..0c4500695 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -115,7 +115,7 @@ class spell_sha_ancestral_awakening : public AuraScript return; int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -877,25 +877,25 @@ class spell_sha_flametongue_weapon : public AuraScript Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); - float basePoints(GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue()); + float const basePoints = GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue(); // Flametongue max damage is normalized based on a 4.0 speed weapon // Tooltip says max damage = BasePoints / 25, so BasePoints / 25 / 4 to get base damage per 1.0s AS float fireDamage = basePoints / 100.0f; - float attackSpeed = player->GetAttackTime(attType) / 1000.f; + float const attackSpeed = player->GetAttackTime(attType) / 1000.f; fireDamage *= attackSpeed; // clip value between (BasePoints / 77) and (BasePoints / 25) as the tooltip indicates RoundToInterval(fireDamage, basePoints / 77.0f, basePoints / 25.0f); // Calculate Spell Power scaling - float spellPowerBonus(player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); + float spellPowerBonus = player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE); float const spCoeff = 0.03811f; spellPowerBonus *= spCoeff * attackSpeed; // All done, now proc damage int32 amount = static_cast(fireDamage + spellPowerBonus); - player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item); + player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item, aurEff); } void Register() override @@ -930,7 +930,7 @@ class spell_sha_frozen_power : public AuraScript if (caster->GetDistance(target) < minDistance) return; - caster->CastSpell(target, SPELL_SHAMAN_FREEZE, aurEff); + caster->CastSpell(target, SPELL_SHAMAN_FREEZE, true, nullptr, aurEff); } void Register() override @@ -989,7 +989,7 @@ class spell_sha_glyph_of_healing_wave : public AuraScript return; int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true); + caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); } void Register() override @@ -1036,7 +1036,7 @@ class spell_sha_glyph_of_totem_of_wrath : public AuraScript int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(caster), aurEff->GetAmount()); - caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true); + caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true, nullptr, aurEff); } void Register() override @@ -1370,17 +1370,17 @@ class spell_sha_imp_water_shield : public AuraScript return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); // Get Water Shield - AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); - if (!aurEff) + AuraEffect const* waterShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); + if (!waterShield) return; - uint32 spellId = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - caster->CastSpell((Unit*)nullptr, spellId, true); + uint32 spellId = waterShield->GetSpellInfo()->Effects[waterShield->GetEffIndex()].TriggerSpell; + caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1430,7 +1430,7 @@ class spell_sha_lightning_overload : public AuraScript spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1, spellInfo->GetRank()); } - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -1452,7 +1452,7 @@ class spell_sha_item_lightning_shield : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, aurEff); + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff); } void Register() override @@ -1474,7 +1474,7 @@ class spell_sha_item_lightning_shield_trigger : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, aurEff); + GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff); } void Register() override @@ -1503,7 +1503,7 @@ class spell_sha_item_mana_surge : public AuraScript int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); int32 damage = CalculatePct(mana, 35); - GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, nullptr, aurEff); } void Register() override @@ -1526,7 +1526,7 @@ class spell_sha_item_t6_trinket : public AuraScript }); } - void HandleProc(AuraEffect const* /* aurEff */, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); @@ -1558,7 +1558,7 @@ class spell_sha_item_t6_trinket : public AuraScript return; if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true); + eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); } void Register() override @@ -1638,17 +1638,17 @@ class spell_sha_maelstrom_weapon : public AuraScript }); } - void HandleBonus(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + void HandleBonus(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { if (GetStackAmount() < GetSpellInfo()->StackAmount) return; Unit* caster = GetUnitOwner(); - AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS, EFFECT_0); - if (!aurEff || !roll_chance_i(aurEff->GetAmount())) + AuraEffect const* maelstrom = caster->GetAuraEffect(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS, EFFECT_0); + if (!maelstrom || !roll_chance_i(maelstrom->GetAmount())) return; - caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true); + caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true, nullptr, aurEff); } void Register() override @@ -1705,8 +1705,8 @@ class spell_sha_spirit_hunt : public AuraScript return; int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); + caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); } void Register() override @@ -1737,7 +1737,7 @@ class spell_sha_static_shock : public AuraScript return; uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, lightningShield->GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); lightningShield->GetBase()->DropCharge(); } @@ -1816,7 +1816,7 @@ class spell_sha_t3_6p_bonus : public AuraScript return; } - caster->CastSpell(target, spellId, aurEff); + caster->CastSpell(target, spellId, true, nullptr, aurEff); } void Register() override @@ -1895,7 +1895,7 @@ class spell_sha_windfury_weapon : public AuraScript return true; } - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -1935,7 +1935,7 @@ class spell_sha_windfury_weapon : public AuraScript // Attack twice for (uint8 i = 0; i < 2; ++i) - player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item); + player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index f17cf7f8b..a2b222b44 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -744,7 +744,7 @@ class spell_warl_seed_of_corruption_dummy : public AuraScript return; uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank()); - caster->CastSpell(eventInfo.GetActionTarget(), spellId, aurEff); + caster->CastSpell(eventInfo.GetActionTarget(), spellId, true, nullptr, aurEff); } void Register() override @@ -789,7 +789,7 @@ class spell_warl_seed_of_corruption_generic : public AuraScript if (!caster) return; - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, aurEff); + caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, true, nullptr, aurEff); } void Register() override @@ -859,7 +859,7 @@ class spell_warl_soul_leech : public AuraScript Unit* caster = eventInfo.GetActor(); int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true); + caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); // Improved Soul Leech code below AuraEffect const* impSoulLeech = GetTarget()->GetAuraEffectOfRankedSpell(SPELL_WARLOCK_IMP_SOUL_LEECH_R1, EFFECT_1, aurEff->GetCasterGUID()); @@ -870,11 +870,11 @@ class spell_warl_soul_leech : public AuraScript uint32 selfSpellId = casterMana[impSoulLeechRank - 1]; uint32 petSpellId = petMana[impSoulLeechRank - 1]; - caster->CastSpell((Unit*)nullptr, selfSpellId, true); - caster->CastSpell((Unit*)nullptr, petSpellId, true); + caster->CastSpell((Unit*)nullptr, selfSpellId, true, nullptr, aurEff); + caster->CastSpell((Unit*)nullptr, petSpellId, true, nullptr, aurEff); if (roll_chance_i(impSoulLeech->GetAmount())) - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true); + caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); } void Register() override @@ -1274,7 +1274,7 @@ class spell_warl_t4_2p_bonus : public AuraScript { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, TriggerSpellId, aurEff); + caster->CastSpell(caster, TriggerSpellId, true, nullptr, aurEff); } void Register() override @@ -1428,7 +1428,7 @@ class spell_warl_glyph_of_corruption_nightfall : public AuraScript { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, aurEff); + caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, true, nullptr, aurEff); } void Register() override @@ -1451,7 +1451,7 @@ class spell_warl_glyph_of_life_tap : public AuraScript { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, aurEff); + caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, true, nullptr, aurEff); } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 723d987e4..d91904236 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -173,7 +173,7 @@ class spell_warr_improved_spell_reflection : public AuraScript CustomSpellValues values; values.AddSpellMod(SPELLVALUE_MAX_TARGETS, aurEff->GetAmount()); values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 2000); // Base range = 100, final range = 20 value / 10000.0f = 0.2f - eventInfo.GetActor()->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, values, eventInfo.GetActor(), TRIGGERED_FULL_MASK, nullptr); + eventInfo.GetActor()->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, values, eventInfo.GetActor(), TRIGGERED_FULL_MASK, nullptr, aurEff); } void Register() override @@ -569,7 +569,7 @@ class spell_warr_glyph_of_blocking : public AuraScript { PreventDefaultAction(); Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, aurEff); + caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, true, nullptr, aurEff); } void Register() override @@ -766,7 +766,7 @@ class spell_warr_second_wind : public AuraScript PreventDefaultAction(); Unit* caster = eventInfo.GetActionTarget(); uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, aurEff); + caster->CastSpell(caster, spellId, true, nullptr, aurEff); } void Register() override @@ -846,7 +846,7 @@ class spell_warr_sweeping_strikes : public AuraScript if (spellInfo && spellInfo->Id == SPELL_WARRIOR_EXECUTE && !_procTarget->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) { // If triggered by Execute (while target is not under 20% hp) deals normalized weapon damage - GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, aurEff); + GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, true, nullptr, aurEff); } else { From a818bcf3e20653a52670b7905f004187f883afff Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Tue, 4 Oct 2022 07:38:12 -0300 Subject: [PATCH 05/25] fix(Core): Crash (#13292) --- src/server/game/Entities/Unit/Unit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index fe8e6c407..46d6a5628 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -165,10 +165,10 @@ DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo) } } -DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType /*attackType*/, uint32 /* hitMask */) +DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 /* hitMask */) : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_spellInfo(spellNonMeleeDamage.spellInfo), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType), - m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), + m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(0), m_cleanDamage(spellNonMeleeDamage.cleanDamage) { if (spellNonMeleeDamage.blocked) From e05f61d1b3873a217798078169455591422a1766 Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Tue, 4 Oct 2022 14:37:48 -0300 Subject: [PATCH 06/25] fix(Core/QAston): fixed shields oneshotting (#13271) * fix(Core/QAston): fixed shields oneshotting * fix build --- src/server/game/Entities/Unit/Unit.cpp | 91 +++++++++++-------- src/server/game/Entities/Unit/Unit.h | 3 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 1 + 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 46d6a5628..2ab51a89e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -192,7 +192,7 @@ void DamageInfo::AbsorbDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_absorb += amount; m_damage -= amount; - m_hitMask |= PROC_HIT_ABSORB;m_damage -= amount; + m_hitMask |= PROC_HIT_ABSORB; } void DamageInfo::ResistDamage(uint32 amount) @@ -1413,8 +1413,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // double blocked amount if block is critical if (victim->isBlockCritical()) damageInfo->blocked *= 2; - if (damage < int32(damageInfo->blocked)) + if (damage <= int32(damageInfo->blocked)) + { damageInfo->blocked = uint32(damage); + damageInfo->fullBlock = true; + } damage -= damageInfo->blocked; cleanDamage += damageInfo->blocked; @@ -1468,14 +1471,18 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->damage = std::max(0, damage); // Calculate absorb resist - if (damageInfo->damage > 0) - { - DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, 0); - Unit::CalcAbsorbResist(dmgInfo); - damageInfo->absorb = dmgInfo.GetAbsorb(); - damageInfo->resist = dmgInfo.GetResist(); - damageInfo->damage = dmgInfo.GetDamage(); - } + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); + + if (damageInfo->absorb) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); + + if (damageInfo->resist) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); + + damageInfo->damage = dmgInfo.GetDamage(); } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell /*= nullptr*/) @@ -2070,31 +2077,25 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) } // Ignore Absorption Auras - float auraAbsorbMod = 0; - if (attacker) + float auraAbsorbMod = victim->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, dmgInfo.GetSchoolMask());; + AuraEffectList const& abilityAbsorbAuras = victim->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); + for (AuraEffect const* aurEff : abilityAbsorbAuras) { - AuraEffectList const& AbsIgnoreAurasA = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL); - for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr) - { - if (!((*itr)->GetMiscValue() & schoolMask)) - continue; + if (!(aurEff->GetMiscValue() & schoolMask)) + continue; - if ((*itr)->GetAmount() > auraAbsorbMod) - auraAbsorbMod = float((*itr)->GetAmount()); - } + if (!aurEff->IsAffectedOnSpell(spellInfo)) + continue; - AuraEffectList const& AbsIgnoreAurasB = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); - for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr) - { - if (!((*itr)->GetMiscValue() & schoolMask)) - continue; - - if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo)) - auraAbsorbMod = float((*itr)->GetAmount()); - } - RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); + if (aurEff->GetAmount() > auraAbsorbMod) + auraAbsorbMod = float(aurEff->GetAmount()); } + RoundToInterval(auraAbsorbMod, 0.f, 100.f); + + int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod); + dmgInfo.ModifyDamage(-absorbIgnoringDamage); + // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB)); @@ -12190,14 +12191,13 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond hitMask |= PROC_HIT_PARRY; break; case SPELL_MISS_BLOCK: - hitMask |= PROC_HIT_BLOCK; + // spells can't be partially blocked (it's damage can though) + hitMask |= PROC_HIT_BLOCK | PROC_HIT_FULL_BLOCK; break; case SPELL_MISS_EVADE: hitMask |= PROC_HIT_EVADE; break; case SPELL_MISS_IMMUNE: - hitMask |= PROC_HIT_IMMUNE; - break; case SPELL_MISS_IMMUNE2: hitMask |= PROC_HIT_IMMUNE; break; @@ -12210,6 +12210,9 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond case SPELL_MISS_REFLECT: hitMask |= PROC_HIT_REFLECT; break; + case SPELL_MISS_RESIST: + hitMask |= PROC_HIT_FULL_RESIST; + break; default: break; } @@ -12218,15 +12221,27 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond { // On block if (damageInfo->blocked) + { hitMask |= PROC_HIT_BLOCK; + if (damageInfo->fullBlock) + hitMask |= PROC_HIT_FULL_BLOCK; + } // On absorb if (damageInfo->absorb) hitMask |= PROC_HIT_ABSORB; - // On crit - if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - hitMask |= PROC_HIT_CRITICAL; - else - hitMask |= PROC_HIT_NORMAL; + + // Don't set hit/crit hitMask if damage is nullified + bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0; + if (!damageNullified) + { + // On crit + if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) + hitMask |= PROC_HIT_CRITICAL; + else + hitMask |= PROC_HIT_NORMAL; + } + else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0) + hitMask |= PROC_HIT_FULL_RESIST; } return hitMask; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index d15b141bf..8e66a0a48 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -891,7 +891,7 @@ struct SpellNonMeleeDamage { SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, uint32 _schoolMask) : target(_target), attacker(_attacker), spellInfo(_spellInfo), damage(0), overkill(0), schoolMask(_schoolMask), - absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false) {} Unit* target; @@ -908,6 +908,7 @@ struct SpellNonMeleeDamage uint32 HitInfo; // Used for help uint32 cleanDamage; + bool fullBlock; }; struct SpellPeriodicAuraLogInfo diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 46a5ef1e9..6b195ff72 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6468,7 +6468,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (damage) { procVictim |= PROC_FLAG_TAKEN_DAMAGE; - hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; + hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; } int32 overkill = damage - target->GetHealth(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 0d544bf1f..b847c8f13 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -311,6 +311,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) else { DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); + m_caster->CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); uint32 resist = dmgInfo.GetResist(); From 00eea376f193aa425c5d5a6174f51848305f6903 Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Tue, 4 Oct 2022 20:42:25 -0300 Subject: [PATCH 07/25] fix(Core/TempleOfAhnQiraj): Huhuran timers + EventMap::Repeat (#13182) fix(Core/TempleOfAhnQiraj): Huhuran timers + EventMap::Repeat using std::chrono --- src/common/Utilities/EventMap.cpp | 5 +++ src/common/Utilities/EventMap.h | 8 ++++ .../TempleOfAhnQiraj/boss_huhuran.cpp | 40 ++++++++++--------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/common/Utilities/EventMap.cpp b/src/common/Utilities/EventMap.cpp index 15a95829e..00dac4a6d 100644 --- a/src/common/Utilities/EventMap.cpp +++ b/src/common/Utilities/EventMap.cpp @@ -106,6 +106,11 @@ void EventMap::Repeat(Milliseconds time) RepeatEvent(time.count()); } +void EventMap::Repeat(Milliseconds minTime, Milliseconds maxTime) +{ + RepeatEvent(randtime(minTime, maxTime).count()); +} + uint32 EventMap::ExecuteEvent() { while (!Empty()) diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h index 45f97b15a..1ed115e42 100644 --- a/src/common/Utilities/EventMap.h +++ b/src/common/Utilities/EventMap.h @@ -198,6 +198,14 @@ public: */ void Repeat(Milliseconds time); + /** + * @name RepeatEvent + * @brief Repeats the most recently executed event. + * @param minTime The minimum time until the event occurs as std::chrono type. + * @param maxTime The maximum time until the event occurs as std::chrono type. + */ + void Repeat(Milliseconds minTime, Milliseconds maxTime); + /** * @name ExecuteEvent * @brief Returns the next event to execute and removes it from map. diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp index 2f3dffc3e..c8e5c69e8 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp @@ -35,8 +35,7 @@ enum Spells SPELL_WYVERN_STING = 26180, SPELL_ACID_SPIT = 26050, SPELL_WYVERN_STING_DAMAGE = 26233, - SPELL_POISON_BOLT = 26052, - SPELL_HARD_ENRAGE = 26662 + SPELL_POISON_BOLT = 26052 }; enum Events @@ -54,18 +53,18 @@ struct boss_huhuran : public BossAI void Reset() override { - _Reset(); + BossAI::Reset(); _berserk = false; _hardEnrage = false; } void EnterCombat(Unit* /*who*/) override { - events.ScheduleEvent(EVENT_FRENZY, urand(25000, 35000)); - events.ScheduleEvent(EVENT_WYVERN_STING, urand(18000, 28000)); - events.ScheduleEvent(EVENT_ACID_SPIT, 8000); - events.ScheduleEvent(EVENT_NOXIOUS_POISON, urand(10000, 20000)); - events.ScheduleEvent(EVENT_HARD_ENRAGE, 300000); + events.ScheduleEvent(EVENT_FRENZY, 12s, 21s); + events.ScheduleEvent(EVENT_WYVERN_STING, 25s, 43s); + events.ScheduleEvent(EVENT_ACID_SPIT, 1s, 20s); + events.ScheduleEvent(EVENT_NOXIOUS_POISON, 10s, 22s); + events.ScheduleEvent(EVENT_HARD_ENRAGE, 5min); } void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override @@ -74,6 +73,7 @@ struct boss_huhuran : public BossAI { DoCastSelf(SPELL_BERSERK, true); me->TextEmote(EMOTE_BERSERK); + events.CancelEvent(EVENT_FRENZY); _berserk = true; } } @@ -91,39 +91,43 @@ struct boss_huhuran : public BossAI case EVENT_FRENZY: DoCastSelf(SPELL_FRENZY, true); Talk(EMOTE_FRENZY_KILL); - events.RepeatEvent(urand(25000, 35000)); + events.Repeat(12s, 21s); break; case EVENT_WYVERN_STING: me->CastCustomSpell(SPELL_WYVERN_STING, SPELLVALUE_MAX_TARGETS, 10, me, true); - events.RepeatEvent(urand(15000, 32000)); + events.Repeat(25s, 43s); break; case EVENT_ACID_SPIT: DoCastVictim(SPELL_ACID_SPIT); - events.RepeatEvent(urand(5000, 10000)); + events.Repeat(1s, 20s); break; case EVENT_NOXIOUS_POISON: - DoCastRandomTarget(SPELL_NOXIOUS_POISON, 0, 100, true); - events.RepeatEvent(urand(12000, 24000)); + DoCastRandomTarget(SPELL_NOXIOUS_POISON, 0, 100.f, true); + events.Repeat(10s, 22s); break; case EVENT_HARD_ENRAGE: if (!_hardEnrage) { - DoCastSelf(SPELL_HARD_ENRAGE, true); + DoCastSelf(SPELL_BERSERK, true); + events.CancelEvent(EVENT_FRENZY); _hardEnrage = true; } else { DoCastAOE(SPELL_POISON_BOLT); } - events.RepeatEvent(3000); + events.Repeat(2s); + break; + default: break; } } DoMeleeAttackIfReady(); } - private: - bool _berserk; - bool _hardEnrage; + +private: + bool _berserk; + bool _hardEnrage; }; // 26180 - Wyvern Sting From e189caeb76347b573727262739d7fbc919366aa6 Mon Sep 17 00:00:00 2001 From: Yehonal Date: Wed, 5 Oct 2022 13:15:42 +0200 Subject: [PATCH 08/25] feat(docker): implemented dbimport (#13308) ## Changes Proposed: - Implemented dbimport with docker - deprecated db_assembler - Fixed deno scripts and integrated them with the CI --- .dockerignore | 3 + .github/workflows/docker_build.yml | 4 +- .gitignore | 3 + apps/bash_shared/deno.sh | 2 +- apps/ci/ci-import-db.sh | 14 --- apps/compiler/includes/functions.sh | 1 + apps/db_assembler/README.md | 4 +- apps/db_assembler/conf.dist.sh | 121 ++++++++++++++++++++++++ apps/docker/Dockerfile | 6 +- apps/docker/docker-cmd.ts | 2 +- apps/installer/includes/includes.sh | 1 - apps/installer/main.sh | 40 ++++---- conf/dist/config.sh | 121 ------------------------ docker-compose.yml | 6 ++ env/docker/etc/dbimport.conf.dockerdist | 18 ++++ 15 files changed, 181 insertions(+), 165 deletions(-) delete mode 100755 apps/ci/ci-import-db.sh create mode 100644 apps/db_assembler/conf.dist.sh create mode 100644 env/docker/etc/dbimport.conf.dockerdist diff --git a/.dockerignore b/.dockerignore index ea6c901b7..e0f14b384 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,8 +9,11 @@ /env/docker/* !/env/docker/bin/.gitkeep !/env/docker/data/.gitkeep +!/env/docker/etc/ +/env/docker/etc/* !/env/docker/etc/authserver.conf.dockerdist !/env/docker/etc/worldserver.conf.dockerdist +!/env/docker/etc/dbimport.conf.dockerdist !/env/docker/logs/.gitkeep /.env* .idea diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 7ccbf23f9..0914d5021 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -68,7 +68,7 @@ jobs: run: | export DOCKER_USER_ID=$(id -u) export DOCKER_GROUP_ID=$(id -u) - docker-compose --profile dev --profile local build --parallel + ./acore.sh docker build - name: Deploy Dev #env: @@ -97,7 +97,7 @@ jobs: run: | export DOCKER_USER_ID=$(id -u) export DOCKER_GROUP_ID=$(id -u) - docker-compose --profile build --profile prod build --parallel + ./acore.sh docker prod:build docker-compose run --no-deps --name build ac-build echo "image created" docker cp build:/azerothcore/var/ccache var/docker/ echo "ccache exported" diff --git a/.gitignore b/.gitignore index 23193e9c8..d1b444f30 100644 --- a/.gitignore +++ b/.gitignore @@ -20,8 +20,11 @@ /env/docker/* !/env/docker/bin/.gitkeep !/env/docker/data/.gitkeep +!/env/docker/etc/ +/env/docker/etc/* !/env/docker/etc/authserver.conf.dockerdist !/env/docker/etc/worldserver.conf.dockerdist +!/env/docker/etc/dbimport.conf.dockerdist !/env/docker/logs/.gitkeep /.env* /apps/joiner diff --git a/apps/bash_shared/deno.sh b/apps/bash_shared/deno.sh index 68086acf5..1caaf6f80 100644 --- a/apps/bash_shared/deno.sh +++ b/apps/bash_shared/deno.sh @@ -1,4 +1,4 @@ -DENO_MIN_VERSION="1.9.1" +DENO_MIN_VERSION="1.26.0" function denoInstall() { diff --git a/apps/ci/ci-import-db.sh b/apps/ci/ci-import-db.sh deleted file mode 100755 index a7ee847d8..000000000 --- a/apps/ci/ci-import-db.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -e - -sudo systemctl start mysql -./acore.sh "db-assembler" "import-all" - -if [ -s modules/mod-premium/sql/example_item_9017.sql ] -then - echo "Import custom module item..." - # if the premium module is available insert the example item or else the worldserver dry run will fail - mysql -uroot -proot acore_world < modules/mod-premium/sql/example_item_9017.sql - echo "Done!" -fi diff --git a/apps/compiler/includes/functions.sh b/apps/compiler/includes/functions.sh index ced1f488d..04467cbf0 100644 --- a/apps/compiler/includes/functions.sh +++ b/apps/compiler/includes/functions.sh @@ -111,6 +111,7 @@ function comp_compile() { echo "Generating confs..." cp -n "env/dist/etc/worldserver.conf.dockerdist" "env/dist/etc/worldserver.conf" cp -n "env/dist/etc/authserver.conf.dockerdist" "env/dist/etc/authserver.conf" + cp -n "env/dist/etc/dbimport.conf.dockerdist" "env/dist/etc/dbimport.conf" fi runHooks "ON_AFTER_BUILD" diff --git a/apps/db_assembler/README.md b/apps/db_assembler/README.md index 865efc454..46ee0075e 100644 --- a/apps/db_assembler/README.md +++ b/apps/db_assembler/README.md @@ -1,5 +1,7 @@ ## Description +**ATTENTION:** this tool is not supported anymore. It has been replaced by the **dbimport** tools integrated in AC server sources + This script allows you to assemble all sql files into one so you can easily import it to your databases (or use the main script to import directly). By default, it creates the merged files in `/env/dist`. ## How to use: @@ -15,7 +17,7 @@ Just run it to display the options. Note: You can even use actions directly by command lines specifying the option. Ex: - ./db_assembler.sh 1 + ./db_assembler.sh 1 It will merge all sql files without an interactive menu. diff --git a/apps/db_assembler/conf.dist.sh b/apps/db_assembler/conf.dist.sh new file mode 100644 index 000000000..c16710b7d --- /dev/null +++ b/apps/db_assembler/conf.dist.sh @@ -0,0 +1,121 @@ +############################################## +# +# DB ASSEMBLER / EXPORTER CONFIGURATIONS +# +############################################## + +# +# Comma separated list of databases +# +# You can add another element here if you need +# to support multiple databases +# + +DBLIST=${DBLIST:-"AUTH,CHARACTERS,WORLD"} +# convert from comma separated list to an array. +# This is needed to support environment variables +readarray -td, DATABASES <<<"$DBLIST"; + +OUTPUT_FOLDER=${OUTPUT_FOLDER:-"$AC_PATH_ROOT/env/dist/sql/"} + +DBASM_WAIT_TIMEOUT=${DBASM_WAIT_TIMEOUT:-5} +DBASM_WAIT_RETRIES=${DBASM_WAIT_RETRIES:-3} + +####### BACKUP +# Set to true if you want to backup your azerothcore databases before importing the SQL with the db_assembler +# Do not forget to stop your database software (mysql) before doing so + +BACKUP_ENABLE=false + +BACKUP_FOLDER="$AC_PATH_ROOT/env/dist/sql/backup/" + +####### + +# FULL DB +DB_AUTH_PATHS=( + "$SRCPATH/data/sql/base/db_auth/" +) + +DB_CHARACTERS_PATHS=( + "$SRCPATH/data/sql/base/db_characters" +) + +DB_WORLD_PATHS=( + "$SRCPATH/data/sql/base/db_world/" +) + +# UPDATES +DB_AUTH_UPDATES_PATHS=( + "$SRCPATH/data/sql/updates/db_auth/" + "$SRCPATH/data/sql/updates/pending_db_auth/" +) + +DB_CHARACTERS_UPDATES_PATHS=( + "$SRCPATH/data/sql/updates/db_characters/" + "$SRCPATH/data/sql/updates/pending_db_characters/" +) + +DB_WORLD_UPDATES_PATHS=( + "$SRCPATH/data/sql/updates/db_world/" + "$SRCPATH/data/sql/updates/pending_db_world/" +) + +# CUSTOM +DB_AUTH_CUSTOM_PATHS=( + "$SRCPATH/data/sql/custom/db_auth/" +) + +DB_CHARACTERS_CUSTOM_PATHS=( + "$SRCPATH/data/sql/custom/db_characters/" +) + +DB_WORLD_CUSTOM_PATHS=( + "$SRCPATH/data/sql/custom/db_world/" +) + +############################################## +# +# DB EXPORTER/IMPORTER CONFIGURATIONS +# +############################################## + +# +# Skip import of base sql files to avoid +# table dropping +# +DB_SKIP_BASE_IMPORT_IF_EXISTS=true + +# +# Example: +# "C:/Program Files/MySQL/MySQL Server 8.0/bin/mysql.exe" +# "/usr/bin/mysql" +# "mysql" +# + +DB_MYSQL_EXEC="mysql" +DB_MYSQL_DUMP_EXEC="mysqldump" + + +DB_AUTH_CONF=${DB_AUTH_CONF:-"MYSQL_USER='acore'; \ + MYSQL_PASS='acore'; \ + MYSQL_HOST='localhost';\ + MYSQL_PORT='3306';\ + "} + +DB_CHARACTERS_CONF=${DB_CHARACTERS_CONF:-"MYSQL_USER='acore'; \ + MYSQL_PASS='acore'; \ + MYSQL_HOST='localhost';\ + MYSQL_PORT='3306';\ + "} + +DB_WORLD_CONF=${DB_WORLD_CONF:-"MYSQL_USER='acore'; \ + MYSQL_PASS='acore'; \ + MYSQL_HOST='localhost';\ + MYSQL_PORT='3306';\ + "} + +DB_AUTH_NAME="acore_auth" + +DB_CHARACTERS_NAME="acore_characters" + +DB_WORLD_NAME="acore_world" diff --git a/apps/docker/Dockerfile b/apps/docker/Dockerfile index 1a53b7a80..c89e01fb2 100644 --- a/apps/docker/Dockerfile +++ b/apps/docker/Dockerfile @@ -179,6 +179,7 @@ RUN mkdir -p /azerothcore/env/etc/ COPY --chown=$DOCKER_USER:$DOCKER_USER var/docker/ccache /azerothcore/var/ccache COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/authserver.conf.dockerdist /azerothcore/env/dist/etc/authserver.conf.dockerdist COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/worldserver.conf.dockerdist /azerothcore/env/dist/etc/worldserver.conf.dockerdist +COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/dbimport.conf.dockerdist /azerothcore/env/dist/etc/dbimport.conf.dockerdist # install eluna RUN git clone --depth=1 --branch=master https://github.com/azerothcore/mod-eluna.git /azerothcore/modules/mod-eluna @@ -189,8 +190,8 @@ ENV AC_CCACHE=true ENV CCACHE_CPP2=true ENV CSCRIPTPCH=OFF ENV CCOREPCH=OFF -# ENV CTOOLS_BUILD=all -ENV CTOOLS_BUILD=maps-only +ENV CTOOLS_BUILD=all +# ENV CTOOLS_BUILD=maps-only ENV CSCRIPTS=static RUN bash apps/docker/docker-build-prod.sh @@ -225,6 +226,7 @@ RUN mkdir -p /azerothcore/env/dist/bin/lua_scripts COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build /azerothcore/env/dist/etc /azerothcore/env/dist/etc COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build /azerothcore/env/dist/bin/worldserver /azerothcore/env/dist/bin/worldserver COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build /azerothcore/env/dist/bin/lua_scripts /azerothcore/env/dist/bin/lua_scripts +COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build /azerothcore/env/dist/bin/dbimport /azerothcore/env/dist/bin/dbimport #================================================================ # diff --git a/apps/docker/docker-cmd.ts b/apps/docker/docker-cmd.ts index 20e22f0f5..c140cb165 100644 --- a/apps/docker/docker-cmd.ts +++ b/apps/docker/docker-cmd.ts @@ -3,7 +3,7 @@ import * as ink from "https://deno.land/x/ink/mod.ts"; import { Input, Select, -} from "https://deno.land/x/cliffy@v0.18.2/prompt/mod.ts"; +} from "https://deno.land/x/cliffy@v0.25.2/prompt/mod.ts"; const program = new Command(); diff --git a/apps/installer/includes/includes.sh b/apps/installer/includes/includes.sh index 5b99c45cc..c0d6bb8bd 100644 --- a/apps/installer/includes/includes.sh +++ b/apps/installer/includes/includes.sh @@ -16,7 +16,6 @@ if [ -f "$AC_PATH_INSTALLER/config.sh" ]; then fi source "$AC_PATH_APPS/compiler/includes/includes.sh" -source "$AC_PATH_APPS/db_assembler/includes/includes.sh" source "$AC_PATH_DEPS/semver_bash/semver.sh" diff --git a/apps/installer/main.sh b/apps/installer/main.sh index b985b225b..7475c8f2f 100644 --- a/apps/installer/main.sh +++ b/apps/installer/main.sh @@ -11,16 +11,15 @@ options=( "pull (u): Update Repository" # 3 "reset (r): Reset & Clean Repository" # 4 "compiler (c): Run compiler tool" # 5 - "db-assembler (a): Run db assembler tool" # 6 - "module-search (ms): Module Search by keyword" # 7 - "module-install (mi): Module Install by name" # 8 - "module-update (mu): Module Update by name" # 9 - "module-remove: (mr): Module Remove by name" # 10 - "client-data: (gd): download client data from github repository (beta)" # 11 - "run-worldserver (rw): execute a simple restarter for worldserver" # 12 - "run-authserver (ra): execute a simple restarter for authserver" # 13 - "docker (dr): Run docker tools" # 14 - "quit: Exit from this menu" # 15 + "module-search (ms): Module Search by keyword" # 6 + "module-install (mi): Module Install by name" # 7 + "module-update (mu): Module Update by name" # 8 + "module-remove: (mr): Module Remove by name" # 9 + "client-data: (gd): download client data from github repository (beta)" # 10 + "run-worldserver (rw): execute a simple restarter for worldserver" # 11 + "run-authserver (ra): execute a simple restarter for authserver" # 12 + "docker (dr): Run docker tools" # 13 + "quit: Exit from this menu" # 14 ) function _switch() { @@ -43,35 +42,32 @@ function _switch() { ""|"c"|"compiler"|"5") bash "$AC_PATH_APPS/compiler/compiler.sh" $_opt ;; - ""|"a"|"db-assembler"|"6") - bash "$AC_PATH_APPS/db_assembler/db_assembler.sh" $_opt - ;; - ""|"ms"|"module-search"|"7") + ""|"ms"|"module-search"|"6") inst_module_search "$_opt" ;; - ""|"mi"|"module-install"|"8") + ""|"mi"|"module-install"|"7") inst_module_install "$_opt" ;; - ""|"mu"|"module-update"|"9") + ""|"mu"|"module-update"|"8") inst_module_update "$_opt" ;; - ""|"mr"|"module-remove"|"10") + ""|"mr"|"module-remove"|"9") inst_module_remove "$_opt" ;; - ""|"gd"|"client-data"|"11") + ""|"gd"|"client-data"|"10") inst_download_client_data ;; - ""|"rw"|"run-worldserver"|"12") + ""|"rw"|"run-worldserver"|"11") inst_simple_restarter worldserver ;; - ""|"ra"|"run-authserver"|"13") + ""|"ra"|"run-authserver"|"12") inst_simple_restarter authserver ;; - ""|"dr"|"docker"|"14") + ""|"dr"|"docker"|"13") DOCKER=1 denoRunFile "$AC_PATH_APPS/docker/docker-cmd.ts" "${@:2}" exit ;; - ""|"quit"|"15") + ""|"quit"|"14") echo "Goodbye!" exit ;; diff --git a/conf/dist/config.sh b/conf/dist/config.sh index d04f474c9..3c85c0c18 100644 --- a/conf/dist/config.sh +++ b/conf/dist/config.sh @@ -145,124 +145,3 @@ export CPUPROFILESIGNAL=${CPUPROFILESIGNAL:-12} #export HEAPCHECK=${HEAPCHECK:-normal} -############################################## -# -# DB ASSEMBLER / EXPORTER CONFIGURATIONS -# -############################################## - -# -# Comma separated list of databases -# -# You can add another element here if you need -# to support multiple databases -# - -DBLIST=${DBLIST:-"AUTH,CHARACTERS,WORLD"} -# convert from comma separated list to an array. -# This is needed to support environment variables -readarray -td, DATABASES <<<"$DBLIST"; - -OUTPUT_FOLDER=${OUTPUT_FOLDER:-"$AC_PATH_ROOT/env/dist/sql/"} - -DBASM_WAIT_TIMEOUT=${DBASM_WAIT_TIMEOUT:-5} -DBASM_WAIT_RETRIES=${DBASM_WAIT_RETRIES:-3} - -####### BACKUP -# Set to true if you want to backup your azerothcore databases before importing the SQL with the db_assembler -# Do not forget to stop your database software (mysql) before doing so - -BACKUP_ENABLE=false - -BACKUP_FOLDER="$AC_PATH_ROOT/env/dist/sql/backup/" - -####### - -# FULL DB -DB_AUTH_PATHS=( - "$SRCPATH/data/sql/base/db_auth/" -) - -DB_CHARACTERS_PATHS=( - "$SRCPATH/data/sql/base/db_characters" -) - -DB_WORLD_PATHS=( - "$SRCPATH/data/sql/base/db_world/" -) - -# UPDATES -DB_AUTH_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_auth/" - "$SRCPATH/data/sql/updates/pending_db_auth/" -) - -DB_CHARACTERS_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_characters/" - "$SRCPATH/data/sql/updates/pending_db_characters/" -) - -DB_WORLD_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_world/" - "$SRCPATH/data/sql/updates/pending_db_world/" -) - -# CUSTOM -DB_AUTH_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_auth/" -) - -DB_CHARACTERS_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_characters/" -) - -DB_WORLD_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_world/" -) - -############################################## -# -# DB EXPORTER/IMPORTER CONFIGURATIONS -# -############################################## - -# -# Skip import of base sql files to avoid -# table dropping -# -DB_SKIP_BASE_IMPORT_IF_EXISTS=true - -# -# Example: -# "C:/Program Files/MySQL/MySQL Server 8.0/bin/mysql.exe" -# "/usr/bin/mysql" -# "mysql" -# - -DB_MYSQL_EXEC="mysql" -DB_MYSQL_DUMP_EXEC="mysqldump" - - -DB_AUTH_CONF=${DB_AUTH_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_CHARACTERS_CONF=${DB_CHARACTERS_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_WORLD_CONF=${DB_WORLD_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_AUTH_NAME="acore_auth" - -DB_CHARACTERS_NAME="acore_characters" - -DB_WORLD_NAME="acore_world" diff --git a/docker-compose.yml b/docker-compose.yml index 006d64481..72d0bf172 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -291,6 +291,12 @@ services: - ${DOCKER_VOL_TOOLS_MMAPS:-./var/extractors/mmaps}:/azerothcore/env/client/mmaps profiles: [prod, tools] + ac-db-import: + <<: *ac-shared-conf + image: acore/ac-wotlk-worldserver:${DOCKER_IMAGE_TAG:-master} # name of the generated image after built locally + command: ./env/dist/bin/dbimport + profiles: [db-import] + volumes: ac-database: ac-bin: diff --git a/env/docker/etc/dbimport.conf.dockerdist b/env/docker/etc/dbimport.conf.dockerdist new file mode 100644 index 000000000..9f60b9772 --- /dev/null +++ b/env/docker/etc/dbimport.conf.dockerdist @@ -0,0 +1,18 @@ +# Do NOT change those Dir configs +# Files in LogsDir will reflect on your host directory: docker/worldserver/logs +LogsDir = "/azerothcore/env/dist/logs" +DataDir = "/azerothcore/env/dist/data" + +# Change this configuration accordingly with your docker setup +# The format is "hostname;port;username;password;database": +# - docker containers must be on the same docker network to be able to communicate +# - the DB hostname will be the name of the database docker container +LoginDatabaseInfo = "ac-database;3306;root;password;acore_auth" +WorldDatabaseInfo = "ac-database;3306;root;password;acore_world" +CharacterDatabaseInfo = "ac-database;3306;root;password;acore_characters" + +# Add more configuration overwrites by copying settings from worldserver.conf.dist +LogLevel = 2 + +# Disable idle connections automatic kick since it doesn't work well on macOS + Docker +CloseIdleConnections = 0 From ad4ce0895f04e633e259941aee470c138700ee8e Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Wed, 5 Oct 2022 16:53:20 -0300 Subject: [PATCH 09/25] fix: Qaston revert (#13320) * Revert "fix(Core/QAston): fixed shields oneshotting (#13271)" This reverts commit e05f61d1b3873a217798078169455591422a1766. * Revert "fix(Core): Crash (#13292)" This reverts commit a818bcf3e20653a52670b7905f004187f883afff. * Revert "fix: Crash (#13241)" This reverts commit be423a91b53538c92b28f14759f01c474bb8b277. * delete sql * Revert "refactor(Core/Spells): Implement QAston Proc System (#11079)" This reverts commit cbd3fd0967fd94a2a9eb96aaf55ebd69f32aa918. * add sql revert * fix sql * remove update from world.updates --- .gitignore | 1 - data/sql/updates/db_world/2022_10_02_01.sql | 1101 ---- .../rev_1664980163888388800.sql | 2950 ++++++++++ src/server/game/Combat/ThreatMgr.cpp | 2 +- .../game/Entities/Creature/Creature.cpp | 4 +- src/server/game/Entities/Player/Player.cpp | 221 +- src/server/game/Entities/Player/Player.h | 236 +- src/server/game/Entities/Unit/Unit.cpp | 4902 +++++++++++++++-- src/server/game/Entities/Unit/Unit.h | 80 +- src/server/game/Handlers/CharacterHandler.cpp | 2 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 203 +- .../game/Spells/Auras/SpellAuraEffects.h | 3 +- src/server/game/Spells/Auras/SpellAuras.cpp | 205 +- src/server/game/Spells/Auras/SpellAuras.h | 18 +- src/server/game/Spells/Spell.cpp | 273 +- src/server/game/Spells/Spell.h | 27 +- src/server/game/Spells/SpellDefines.h | 63 +- src/server/game/Spells/SpellEffects.cpp | 53 +- src/server/game/Spells/SpellInfo.cpp | 42 +- src/server/game/Spells/SpellInfo.h | 4 +- .../game/Spells/SpellInfoCorrections.cpp | 14 +- src/server/game/Spells/SpellMgr.cpp | 590 +- src/server/game/Spells/SpellMgr.h | 109 +- src/server/game/Spells/SpellScript.cpp | 15 - src/server/game/Spells/SpellScript.h | 23 +- src/server/game/World/World.cpp | 5 +- src/server/scripts/Commands/cs_reload.cpp | 10 + .../BattleForMountHyjal/boss_anetheron.cpp | 54 +- .../TrialOfTheCrusader/boss_twin_valkyr.cpp | 2 +- .../boss_blood_prince_council.cpp | 20 - .../boss_deathbringer_saurfang.cpp | 40 +- .../boss_professor_putricide.cpp | 54 - .../IcecrownCitadel/icecrown_citadel.cpp | 2 +- .../Ulduar/Ulduar/boss_yoggsaron.cpp | 2 - .../UtgardeKeep/UtgardeKeep/utgarde_keep.cpp | 52 - .../ShadowLabyrinth/shadow_labyrinth.cpp | 58 - .../scripts/Outland/boss_doomlord_kazzak.cpp | 60 +- .../scripts/Outland/outland_script_loader.cpp | 2 - src/server/scripts/Pet/pet_hunter.cpp | 173 - src/server/scripts/Pet/pet_priest.cpp | 10 +- src/server/scripts/Spells/spell_dk.cpp | 466 +- src/server/scripts/Spells/spell_druid.cpp | 648 +-- src/server/scripts/Spells/spell_generic.cpp | 54 +- src/server/scripts/Spells/spell_hunter.cpp | 319 +- src/server/scripts/Spells/spell_item.cpp | 1597 +----- src/server/scripts/Spells/spell_mage.cpp | 405 +- src/server/scripts/Spells/spell_paladin.cpp | 709 +-- src/server/scripts/Spells/spell_priest.cpp | 418 +- src/server/scripts/Spells/spell_rogue.cpp | 165 +- src/server/scripts/Spells/spell_shaman.cpp | 1116 +--- src/server/scripts/Spells/spell_warlock.cpp | 376 +- src/server/scripts/Spells/spell_warrior.cpp | 258 +- src/server/shared/DataStores/DBCStructure.h | 2 +- src/server/shared/SharedDefines.h | 10 +- src/server/shared/enuminfo_SharedDefines.cpp | 24 +- 55 files changed, 8995 insertions(+), 9257 deletions(-) delete mode 100644 data/sql/updates/db_world/2022_10_02_01.sql create mode 100644 data/sql/updates/pending_db_world/rev_1664980163888388800.sql delete mode 100644 src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp diff --git a/.gitignore b/.gitignore index d1b444f30..8d0d4fcfb 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,6 @@ nbproject/ cmake-build-debug/* cmake-build-debug-coverage/* cmake-build-debug-event-trace/* -cmake-build-debug-visual-studio/* coverage-report/ # diff --git a/data/sql/updates/db_world/2022_10_02_01.sql b/data/sql/updates/db_world/2022_10_02_01.sql deleted file mode 100644 index 4672d680f..000000000 --- a/data/sql/updates/db_world/2022_10_02_01.sql +++ /dev/null @@ -1,1101 +0,0 @@ --- DB update 2022_10_02_00 -> 2022_10_02_01 --- Earth shield heal is DAMAGE_CLASS_NONE, it won't scale --- Entry is unneeded -DELETE FROM `spell_bonus_data` WHERE `entry`=379; - -ALTER TABLE `spell_proc` - CHANGE `spellId` `SpellId` int(11) NOT NULL DEFAULT 0 FIRST, - CHANGE `schoolMask` `SchoolMask` tinyint(3) unsigned NOT NULL DEFAULT 0 AFTER `SpellId`, - CHANGE `spellFamilyName` `SpellFamilyName` smallint(5) unsigned NOT NULL DEFAULT 0 AFTER `SchoolMask`, - CHANGE `spellFamilyMask0` `SpellFamilyMask0` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyName`, - CHANGE `spellFamilyMask1` `SpellFamilyMask1` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask0`, - CHANGE `spellFamilyMask2` `SpellFamilyMask2` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask1`, - CHANGE `typeMask` `ProcFlags` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellFamilyMask2`, - CHANGE `spellTypeMask` `SpellTypeMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `ProcFlags`, - CHANGE `spellPhaseMask` `SpellPhaseMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellTypeMask`, - CHANGE `hitMask` `HitMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `SpellPhaseMask`, - CHANGE `attributesMask` `AttributesMask` int(10) unsigned NOT NULL DEFAULT 0 AFTER `HitMask`, - CHANGE `ratePerMinute` `ProcsPerMinute` float NOT NULL DEFAULT 0 AFTER `AttributesMask`, - CHANGE `chance` `Chance` float NOT NULL DEFAULT 0 AFTER `ProcsPerMinute`, - CHANGE `cooldown` `Cooldown` int(10) unsigned NOT NULL DEFAULT 0 AFTER `Chance`, - CHANGE `charges` `Charges` tinyint(3) unsigned NOT NULL DEFAULT 0 AFTER `Cooldown`; - -DELETE FROM `command` WHERE `name`='reload spell_proc_event'; - -DELETE FROM `spell_proc`; -INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES -(17941, 0, 5, 1, 0, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), -(18820, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 1), -(22008, 0, 3, 1631584309, 0, 0, 69632, 5, 1, 0, 0, 0, 0, 0, 1), -(28200, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 6), -(-7001, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(32216, 0, 4, 0, 256, 0, 16, 1, 4, 0, 0, 0, 0, 0, 1), -(34477, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 1), -(34936, 0, 5, 1, 64, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), -(44401, 0, 3, 2048, 0, 0, 65536, 5, 1, 0, 8, 0, 0, 0, 1), -(48108, 0, 3, 4194304, 0, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), -(51124, 0, 15, 2, 6, 0, 65552, 1, 4, 0, 8, 0, 0, 0, 1), -(54741, 0, 3, 4, 0, 0, 65536, 5, 1, 0, 0, 0, 0, 0, 1), -(57761, 0, 3, 1, 4096, 0, 65536, 1, 1, 0, 8, 0, 0, 0, 1), -(64823, 0, 7, 4, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 0, 1), -(-974, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), -(-10400, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-11119, 4, 3, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-11185, 0, 3, 128, 0, 0, 65536, 1, 2, 0, 2, 0, 0, 0, 0), -(-12834, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-13983, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 1000, 0), -(-14156, 0, 8, 4063232, 9, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0), -(-15337, 0, 6, 8396800, 2, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(-16180, 0, 11, 448, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(-18094, 0, 5, 10, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-47230, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(-20234, 0, 10, 32768, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(-20335, 0, 10, 8388608, 0, 0, 16, 5, 2, 0, 0, 0, 100, 0, 0), -(-27243, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(-29441, 0, 0, 0, 0, 0, 0, 7, 0, 8, 0, 0, 0, 1000, 0), -(-29723, 0, 4, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-29834, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), -(-30293, 0, 5, 385, 8519872, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-30675, 0, 11, 3, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-31244, 0, 8, 3801088, 9, 0, 0, 5, 2, 11196, 0, 0, 0, 0, 0), -(-31571, 0, 3, 0, 34, 0, 16384, 7, 4, 0, 2, 0, 0, 0, 0), -(-31785, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), -(-31871, 0, 10, 16, 0, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(-31876, 0, 10, 8388608, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-34497, 0, 9, 395264, 8388609, 513, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-34914, 0, 6, 8192, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(-44404, 0, 3, 536870945, 36864, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-44445, 0, 3, 19, 69632, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-44546, 0, 3, 736, 4096, 0, 69632, 0, 2, 0, 0, 0, 0, 0, 0), -(-46913, 0, 4, 64, 1028, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-46951, 0, 4, 1024, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-47569, 0, 6, 16384, 0, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(-48979, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), -(-49015, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), -(-49018, 0, 15, 20971520, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-49182, 0, 15, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-49188, 0, 15, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-49208, 0, 15, 4194304, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-49467, 0, 15, 16, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-51459, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), -(-51474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-51525, 0, 11, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-51556, 0, 11, 192, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(-51625, 0, 8, 268476416, 0, 0, 0, 5, 2, 0, 2, 0, 0, 0, 0), -(-51627, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), -(-51664, 0, 8, 131072, 8, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-53178, 0, 9, 0, 268435456, 0, 65536, 4, 2, 0, 0, 0, 100, 0, 0), -(-53228, 0, 9, 32, 16777216, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), -(-53290, 0, 9, 2048, 1, 512, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(-53380, 0, 10, 8388608, 163840, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(-53501, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(-53569, 0, 10, 1075838976, 65536, 0, 0, 3, 2, 0, 2, 0, 0, 0, 0), -(-53695, 0, 10, 8388608, 0, 8, 16, 5, 2, 0, 2, 0, 0, 0, 0), -(-54639, 0, 15, 4194304, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-54747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-59088, 0, 4, 0, 2, 0, 1024, 4, 4, 0, 0, 0, 0, 0, 0), -(-61680, 0, 9, 0, 268435456, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-62764, 0, 9, 0, 268435456, 0, 65536, 4, 2, 0, 0, 0, 100, 0, 0), -(-63156, 0, 5, 1, 192, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-63373, 0, 11, 2147483648, 0, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), -(-64127, 0, 6, 1, 1, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0), -(-65661, 0, 15, 4194321, 537001988, 0, 16, 1, 2, 0, 0, 0, 100, 0, 0), -(1719, 0, 4, 778044484, 4212549, 0, 0, 1, 2, 0, 8, 0, 0, 0, 0), -(11129, 4, 3, 146800663, 200776, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(12536, 0, 3, 549591799, 168000, 0, 0, 0, 1, 0, 12, 0, 0, 0, 0), -(15286, 32, 6, 41984016, 9218, 8, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(16246, 0, 11, 2551185859, 5120, 16, 0, 0, 1, 0, 12, 0, 0, 0, 0), -(16864, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0), -(16870, 0, 7, 14924799, 126879699, 263168, 0, 0, 1, 0, 12, 0, 0, 0, 0), -(17619, 0, 13, 0, 0, 0, 34816, 7, 0, 0, 0, 0, 0, 0, 0), -(20185, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 0), -(20186, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 0), -(22007, 0, 3, 2097185, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(24658, 0, 0, 0, 0, 0, 87376, 7, 2, 0, 0, 0, 0, 0, 0), -(24932, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(26169, 0, 6, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(26467, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(28719, 0, 7, 32, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(28744, 0, 7, 64, 0, 0, 278528, 2, 2, 0, 0, 0, 0, 0, 0), -(28789, 0, 10, 3221225472, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(28809, 0, 6, 4096, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(28823, 0, 11, 192, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(28845, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(28847, 0, 7, 32, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(28849, 0, 11, 128, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(29601, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0), -(32863, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(36123, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(38252, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(39367, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(44141, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(70388, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(30823, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 10, 0, 0, 0), -(31801, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(32409, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(33757, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3000, 0), -(37288, 0, 7, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(37295, 0, 7, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(37381, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(37377, 32, 5, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(39437, 4, 5, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(37168, 0, 8, 4063232, 9, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0), -(37594, 0, 6, 4096, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(38164, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(39372, 48, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(40442, 0, 7, 20, 1088, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0), -(40463, 0, 11, 129, 16, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), -(40470, 0, 10, 3229614080, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), -(40971, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(42770, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), -(45057, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(46916, 0, 4, 2097152, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0), -(47383, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(71162, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(71165, 0, 5, 0, 192, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(49005, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(49028, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0), -(49194, 0, 15, 0, 0, 1, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(49222, 0, 0, 0, 0, 0, 139944, 1, 0, 0, 0, 0, 0, 2000, 0), -(49796, 0, 15, 2, 131078, 0, 0, 0, 4, 0, 8, 0, 0, 0, 0), -(51209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(51528, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 4, 0, 0, 0), -(51529, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 8, 0, 0, 0), -(51530, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), -(51531, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 16, 0, 0, 0), -(51532, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 20, 0, 0, 0), -(51698, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 33, 0, 0), -(51700, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 66, 0, 0), -(51701, 0, 0, 0, 0, 0, 0, 3, 4, 2, 0, 0, 100, 0, 0), -(52420, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(52437, 1, 4, 536870912, 0, 0, 16, 0, 4, 0, 0, 0, 0, 0, 0), -(53601, 0, 0, 0, 0, 0, 1048576, 0, 0, 0, 0, 0, 0, 0, 0), -(53736, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(54274, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(54276, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(54277, 0, 5, 357, 131264, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(54748, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0), -(54815, 0, 7, 32768, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), -(54821, 0, 7, 4096, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), -(54832, 0, 7, 0, 4096, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(54845, 0, 7, 4, 0, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), -(54937, 0, 10, 2147483648, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(54939, 0, 10, 32768, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(55198, 0, 11, 448, 0, 0, 16384, 2, 2, 2, 0, 0, 0, 0, 3), -(55440, 0, 11, 64, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(55677, 0, 6, 0, 1, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), -(56372, 0, 3, 0, 128, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(56374, 0, 3, 0, 16384, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(56375, 0, 3, 16777216, 0, 0, 65536, 4, 2, 2049, 0, 0, 0, 0, 0), -(56800, 0, 8, 4, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), -(58375, 0, 4, 0, 512, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), -(58642, 0, 15, 0, 134217728, 0, 16, 1, 2, 0, 0, 0, 0, 0, 0), -(58677, 0, 15, 8192, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), -(58877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(59906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), -(59915, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(37447, 0, 3, 0, 256, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(61062, 0, 3, 0, 256, 0, 16384, 4, 2, 0, 0, 0, 0, 0, 0), -(61257, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0), -(62259, 0, 15, 33554432, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), -(62600, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(62606, 0, 0, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0, 0), -(63279, 0, 11, 0, 1024, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), -(63280, 0, 11, 536870912, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0), -(63320, 0, 5, 2147745792, 0, 32768, 1024, 7, 2, 0, 0, 0, 0, 0, 0), -(64890, 0, 10, 0, 65536, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0), -(64928, 0, 11, 1, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(65032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(67228, 0, 11, 0, 4096, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(69755, 0, 0, 0, 0, 0, 0, 7, 2, 0, 0, 0, 0, 45000, 0), -(69739, 0, 0, 0, 0, 0, 0, 7, 2, 0, 0, 0, 0, 45000, 0), -(69762, 0, 0, 0, 0, 0, 87040, 0, 1, 0, 256, 0, 0, 0, 0), -(70723, 0, 7, 5, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(70770, 0, 6, 2048, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(70805, 0, 8, 0, 131072, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0), -(70808, 0, 11, 256, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(70817, 0, 11, 0, 4096, 0, 65536, 1, 2, 0, 0, 0, 0, 0, 0), -(70844, 0, 4, 256, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(70672, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), -(72455, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), -(72832, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), -(72833, 0, 0, 0, 0, 0, 0, 0, 0, 12287, 0, 0, 0, 0, 0), -(71756, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(72782, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(72783, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(72784, 4, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(71406, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 50, 0, 0), -(71545, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 50, 0, 0), -(71880, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), -(71892, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), -(71519, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 105000, 0), -(71562, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 105000, 0), -(71564, 126, 0, 0, 0, 0, 0, 3, 2, 2, 0, 0, 0, 0, 5), -(71634, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(71640, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(71761, 0, 3, 0, 1048576, 0, 0, 5, 2, 256, 0, 0, 0, 0, 0), -(71770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(72176, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(75475, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), -(75481, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), -(-66799, 0, 15, 4194304, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-63730, 0, 6, 2048, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-58872, 0, 0, 0, 0, 0, 0, 1, 0, 8259, 0, 0, 0, 0, 0), -(-57878, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 0, 0, 0, 0), -(-57470, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), -(-56342, 0, 9, 24, 134217728, 147456, 0, 0, 4, 0, 2, 0, 0, 0, 0), -(-55666, 0, 15, 1, 134217728, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-53709, 2, 10, 16384, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-53671, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-53551, 0, 10, 4096, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-53527, 1, 10, 0, 0, 4, 1024, 0, 2, 1, 0, 0, 100, 0, 0), -(-53486, 0, 10, 8388608, 163840, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), -(-53256, 0, 9, 2048, 8388609, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-53234, 0, 9, 131072, 1, 1, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-53221, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-53215, 0, 9, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-52795, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-52127, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), -(-51940, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(-51692, 0, 8, 516, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-51672, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 1000, 0), -(-51634, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(-51562, 0, 11, 256, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-51523, 0, 11, 0, 1, 0, 65536, 0, 2, 0, 0, 0, 50, 0, 0), -(-51521, 0, 11, 0, 16777216, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(-50880, 0, 15, 0, 67108864, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(-49223, 0, 15, 17, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-49219, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), -(-49149, 0, 15, 6, 131074, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-49027, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 20000, 0), -(-49004, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0), -(-48988, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-48516, 0, 7, 5, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-48506, 0, 7, 5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-48496, 0, 7, 96, 33554434, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-48483, 0, 7, 34816, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-47580, 0, 6, 0, 0, 64, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-47516, 0, 6, 6144, 65536, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(-47509, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(-47263, 32, 5, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 20000, 0), -(-47258, 0, 5, 0, 8388608, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-47201, 0, 5, 16393, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-46945, 0, 4, 0, 65536, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-46867, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-46854, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-45234, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-44557, 0, 3, 32, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-44449, 0, 3, 551686775, 102472, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-44442, 0, 3, 8388608, 64, 0, 0, 0, 2, 0, 0, 0, 0, 1000, 0), -(-41635, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(-35541, 0, 0, 0, 0, 0, 8388608, 0, 0, 0, 0, 0, 0, 0, 0), -(-35100, 0, 9, 4096, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-34950, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-34935, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 8000, 0), -(-34753, 0, 6, 6144, 4, 4096, 0, 0, 2, 2, 2, 0, 0, 0, 0), -(-34500, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-33881, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-33191, 0, 6, 32768, 1024, 64, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-33150, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 0, 0, 0, 0), -(-33142, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-33076, 0, 0, 0, 0, 0, 664232, 1, 0, 0, 0, 0, 0, 0, 0), -(-32385, 0, 5, 1, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-31833, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-31569, 0, 3, 65536, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-31124, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-30881, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(-30701, 28, 0, 0, 0, 0, 664232, 1, 0, 0, 0, 0, 100, 0, 0), -(-30299, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-30160, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-29593, 0, 0, 0, 0, 0, 0, 1, 0, 112, 0, 0, 0, 0, 0), -(-29074, 20, 3, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-27811, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-20925, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(-20500, 0, 4, 268435456, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-20210, 0, 10, 3221225472, 65536, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-20177, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(-20049, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-19184, 0, 9, 16, 8192, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0), -(-18119, 0, 5, 0, 8388608, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-18096, 0, 5, 256, 8388608, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-17793, 0, 5, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-17106, 0, 7, 524288, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-16958, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-16952, 0, 7, 233472, 1024, 262144, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-16880, 72, 7, 103, 58720258, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(-16487, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-16257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-16256, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-16176, 0, 11, 448, 0, 16, 0, 2, 2, 2, 0, 0, 0, 0, 0), -(-14892, 0, 6, 268443136, 65540, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), -(-14531, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-14186, 0, 8, 1107296782, 2, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0), -(-13754, 0, 8, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-12966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-12319, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(-12311, 0, 4, 2048, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-12298, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), -(-12289, 0, 4, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-12281, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 6000, 0), -(-11255, 0, 3, 16384, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-11213, 0, 3, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(-11180, 16, 3, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0), -(-11095, 0, 3, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-9799, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(-9452, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(-5952, 0, 8, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(-324, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3000, 0), -(6346, 0, 0, 0, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0, 0), -(7383, 1, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), -(7434, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(57351, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(9782, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(9784, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(12169, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(12322, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), -(12999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0), -(13000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0), -(13001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0), -(13002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0), -(15088, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), -(15128, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(15277, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(15346, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(15600, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, 0, 0), -(16164, 28, 0, 0, 0, 0, 65536, 1, 2, 2, 0, 0, 0, 0, 0), -(16550, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), -(16620, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 30000, 0), -(16624, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(17364, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(17495, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(20128, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(20131, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(20132, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(20164, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 5, 0, 0, 0), -(20165, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 20, 0, 0, 0), -(20166, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), -(20375, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1000, 0), -(20705, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), -(20911, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), -(21185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(21882, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), -(21890, 0, 4, 712396527, 876, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(22618, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(22648, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0), -(23547, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(23548, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(23551, 0, 11, 192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(23552, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(23572, 0, 11, 192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(23578, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), -(23581, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), -(23686, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), -(23688, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(23689, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 4, 0, 0, 0), -(23721, 0, 9, 2048, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(23920, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(24353, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(24389, 4, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(24905, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 15, 0, 0, 0), -(25050, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(25669, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), -(25899, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0), -(26107, 0, 7, 8388608, 268435584, 0, 0, 0, 2, 116, 0, 0, 0, 0, 0), -(26119, 0, 0, 2416967683, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(26128, 0, 0, 0, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 0), -(26135, 0, 10, 8388608, 0, 0, 16, 0, 2, 0, 2, 0, 0, 0, 0), -(26480, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(26605, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(27419, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), -(27498, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), -(27521, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), -(27656, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(27774, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), -(27787, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), -(28305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(28752, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(28802, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(28812, 0, 8, 33554438, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(28816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0), -(29150, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), -(29455, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(29501, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29624, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29625, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29626, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29632, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29633, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29634, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29635, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29636, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29637, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(29977, 4, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(30003, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(30937, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(31394, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(31794, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(31904, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(32587, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(32642, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(32734, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(32748, 0, 8, 0, 1, 0, 320, 0, 2, 0, 0, 0, 0, 0, 0), -(32776, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(32777, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(32837, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(32844, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0), -(32885, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(33089, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(33127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), -(33297, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(33299, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(33510, 0, 0, 0, 0, 0, 340, 1, 2, 0, 0, 3, 0, 0, 0), -(33648, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(33719, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(33746, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(33759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(33953, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 45000, 0), -(34074, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(34080, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(34138, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(34139, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(34258, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(34262, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(34320, 0, 0, 0, 0, 0, 0, 3, 2, 2, 0, 0, 0, 45000, 0), -(34355, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(34584, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 30000, 0), -(34586, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.5, 0, 0, 0), -(34598, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(34749, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 0, 0, 0, 0), -(34774, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.5, 0, 20000, 0), -(34783, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(34827, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(35077, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 55000, 0), -(35080, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 55000, 0), -(35083, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 55000, 0), -(35086, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 55000, 0), -(35121, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(36032, 0, 3, 4096, 32768, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(36096, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(36111, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(36541, 4, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(37165, 0, 8, 2098176, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37170, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0), -(37173, 0, 8, 750519704, 262, 0, 0, 0, 2, 0, 0, 0, 0, 25000, 0), -(37189, 0, 10, 3221225472, 0, 0, 0, 0, 2, 2, 0, 0, 0, 60000, 0), -(37193, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(37195, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(37197, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(37213, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(37214, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(37227, 0, 11, 448, 0, 0, 0, 0, 2, 2, 0, 0, 0, 60000, 0), -(37237, 0, 11, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(37247, 8, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(37379, 32, 5, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37384, 0, 5, 1, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37443, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(37514, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(37516, 0, 4, 1024, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37519, 0, 0, 0, 0, 0, 0, 0, 2, 48, 0, 0, 0, 0, 0), -(37523, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(37528, 0, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37536, 0, 4, 65536, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37568, 0, 6, 2048, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(37600, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(37601, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(37655, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), -(37657, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 2500, 0), -(38026, 1, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), -(38031, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(38290, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1.6, 0, 0, 0), -(38299, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 12000, 0), -(38326, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(38327, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(38334, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), -(38347, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), -(38350, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(48504, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(39027, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(39442, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0), -(39443, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(39530, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(39958, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0.7, 0, 40000, 0), -(40407, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(40444, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(40458, 0, 4, 33554432, 1537, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(40475, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0), -(40482, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(40485, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(40899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), -(41034, 126, 0, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0, 0), -(41260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(41262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(41381, 0, 0, 0, 0, 0, 0, 1, 0, 256, 0, 0, 0, 0, 0), -(41393, 0, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0), -(41434, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 45000, 0), -(41469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1000, 0), -(41989, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0.5, 0, 0, 0), -(42083, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(42135, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 90000, 0), -(42136, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 90000, 0), -(42368, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(42370, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43443, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(43726, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43728, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43737, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), -(43739, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43741, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43745, 0, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43748, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43750, 0, 11, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(43819, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(44543, 0, 3, 1049120, 4096, 0, 0, 0, 1, 0, 2, 0, 7, 0, 0), -(44545, 0, 3, 1049120, 4096, 0, 0, 0, 1, 0, 2, 0, 15, 0, 0), -(45354, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(45355, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(45469, 0, 15, 16, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0), -(45481, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(45482, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(45483, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(45484, 0, 0, 0, 0, 0, 16384, 2, 2, 0, 0, 0, 0, 45000, 0), -(46025, 32, 6, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(46092, 0, 10, 1073741824, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(46098, 0, 11, 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(46569, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(46662, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 20000, 0), -(46832, 0, 7, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(46910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5.5, 0, 0, 0), -(46911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7.5, 0, 0, 0), -(47981, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(48833, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(48835, 0, 10, 8388608, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0), -(48837, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(49592, 0, 0, 0, 0, 0, 8528552, 1, 0, 0, 0, 0, 0, 0, 0), -(49622, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 60000, 0), -(50240, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0), -(50421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(50781, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 6000, 0), -(51123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), -(51127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0), -(51128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0), -(51129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0), -(51130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0), -(51346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(51349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(51352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(51359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10000, 0), -(51414, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), -(51915, 0, 0, 0, 0, 0, 16777216, 0, 0, 0, 0, 0, 100, 600000, 0), -(52020, 0, 7, 32768, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(52423, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(52898, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(53386, 0, 15, 2182250279, 447, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(53397, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(54646, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(54695, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(54707, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 60000, 0), -(54738, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), -(54808, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 60000, 0), -(54838, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(54841, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 2500, 0), -(54925, 2, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(55380, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0.7, 0, 40000, 0), -(55381, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), -(55640, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(55680, 0, 6, 512, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(55681, 0, 6, 32768, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(55689, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0), -(55747, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(55768, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(55776, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(56249, 0, 5, 0, 0, 1024, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(56355, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), -(56364, 0, 3, 0, 16777216, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(56451, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3000, 0), -(56816, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0), -(56817, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(56821, 0, 8, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(56841, 0, 9, 2048, 0, 0, 256, 0, 2, 0, 0, 0, 0, 0, 0), -(57345, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), -(57352, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(57907, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(57989, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(58357, 0, 4, 64, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(58364, 0, 4, 1024, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(58372, 0, 4, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(58386, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0), -(58442, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 15000, 0), -(58444, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 5000, 0), -(58616, 0, 15, 16777216, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(58620, 0, 15, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(58626, 0, 15, 33554432, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(58901, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(59176, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0), -(59327, 0, 15, 134217728, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(59345, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(59630, 0, 0, 0, 0, 0, 69648, 5, 1, 0, 2, 0, 0, 35000, 0), -(59725, 0, 0, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0, 0), -(60063, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60066, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(60132, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60172, 0, 5, 262144, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60221, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 45000, 0), -(60301, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60306, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60317, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60436, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60442, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60473, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), -(60482, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(60490, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(60493, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(60503, 1, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60519, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 45000, 0), -(60524, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60529, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), -(60537, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 45000, 0), -(60564, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60571, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60572, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60573, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60574, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60575, 0, 11, 2416967680, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60710, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60717, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60719, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60722, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60724, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60726, 0, 7, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60770, 0, 11, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60818, 0, 10, 0, 512, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(60826, 0, 15, 20971520, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(61324, 0, 10, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(61356, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 90000, 0), -(61618, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(62114, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(62115, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(62147, 0, 15, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(62459, 0, 15, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(63086, 0, 9, 0, 0, 65536, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(63108, 0, 5, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(63251, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(63310, 0, 5, 0, 65536, 0, 65536, 0, 2, 0, 0, 0, 0, 0, 0), -(63335, 0, 15, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(63611, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 0, 0), -(64343, 0, 3, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64411, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 0, 0), -(64415, 0, 0, 0, 0, 0, 279552, 2, 2, 0, 0, 0, 0, 45000, 0), -(64440, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(64571, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 10000, 0), -(64714, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(64738, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(64742, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(64786, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(64792, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(64860, 0, 9, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64867, 0, 3, 536870945, 4096, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64882, 0, 10, 0, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64908, 0, 6, 8192, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64912, 0, 6, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64938, 0, 4, 2097216, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0), -(64952, 0, 7, 0, 1088, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64955, 0, 10, 0, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64964, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64976, 0, 4, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(64999, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0), -(65002, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(65005, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), -(65007, 0, 0, 0, 0, 0, 81920, 3, 1, 0, 0, 0, 0, 0, 0), -(65013, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(65020, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(65025, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(66808, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), -(67115, 0, 15, 20971520, 0, 0, 0, 0, 2, 0, 0, 0, 0, 45000, 0), -(67151, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(67353, 0, 7, 32768, 1049856, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(67363, 0, 10, 2147483648, 0, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), -(67379, 0, 10, 0, 262144, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(67381, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 10000, 0), -(67384, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 80, 10000, 0), -(67386, 0, 11, 1, 0, 0, 65536, 0, 1, 0, 0, 0, 0, 6000, 0), -(67389, 0, 11, 256, 0, 0, 16384, 0, 1, 0, 0, 0, 0, 8000, 0), -(67392, 0, 11, 0, 0, 4, 16, 0, 2, 0, 0, 0, 0, 0, 0), -(67653, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 50000, 0), -(67667, 0, 0, 0, 0, 0, 16384, 2, 1, 0, 0, 0, 0, 45000, 0), -(67670, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), -(67672, 0, 0, 0, 0, 0, 8388948, 1, 2, 0, 0, 0, 0, 45000, 0), -(67698, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(67702, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(67712, 0, 0, 0, 0, 0, 69632, 1, 2, 2, 0, 0, 0, 2000, 0), -(67752, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(67758, 0, 0, 0, 0, 0, 69632, 1, 2, 2, 0, 0, 0, 2000, 0), -(67771, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(68051, 1, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(68160, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0), -(70188, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0), -(70652, 0, 15, 8, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(70727, 0, 9, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(70748, 0, 3, 0, 2097152, 0, 1024, 0, 2, 0, 0, 0, 0, 0, 0), -(70756, 0, 10, 0, 65536, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(70761, 0, 10, 0, 0, 1, 1024, 0, 2, 0, 0, 0, 0, 0, 0), -(70803, 0, 8, 4063232, 8, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(70807, 0, 11, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(70811, 0, 11, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(70830, 0, 11, 0, 131072, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71186, 0, 10, 0, 32768, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71191, 0, 10, 0, 65536, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0), -(71194, 0, 10, 0, 1048576, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71214, 0, 11, 0, 16, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0), -(71217, 0, 11, 0, 0, 16, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71226, 0, 15, 16, 134348800, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71228, 0, 15, 0, 536870912, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0), -(71402, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(71404, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 45000, 0), -(71540, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(71585, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 45000, 0), -(71602, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), -(71611, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), -(71642, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 45000, 0), -(71645, 0, 0, 0, 0, 0, 65536, 1, 1, 0, 0, 0, 0, 45000, 0), -(71903, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 12, 0, 0, 0), -(72413, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 10, 60000, 0), -(72417, 0, 0, 0, 0, 0, 327680, 1, 2, 0, 0, 0, 0, 60000, 0), -(72419, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 60000, 0), -(74396, 84, 3, 685904631, 1151048, 0, 65536, 0, 1, 0, 0, 0, 0, 0, 0), -(75455, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(75457, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 45000, 0), -(75465, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), -(75474, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45000, 0), -(-12317, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(63057, 0, 7, 0, 262144, 0, 16384, 0, 2, 0, 0, 0, 0, 0, 0), -(71571, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(71573, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(71865, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), -(71868, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), -(75490, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), -(75495, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 0), -(53651, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0), -(53257, 0, 9, 0, 268435456, 0, 16, 1, 2, 2, 8, 0, 0, 0, 0), -(-31226, 0, 8, 0, 524288, 0, 0, 5, 2, 0, 2, 0, 0, 0, 0), -(-51682, 0, 8, 0, 524288, 0, 0, 4, 2, 0, 2, 0, 0, 0, 0), -(53817, 0, 11, 451, 32768, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(12328, 0, 4, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(21084, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(5118, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(13159, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(-168, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), -(-7302, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), -(-30482, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), -(17670, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(50908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(58501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(-1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), -(-49200, 126, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0), -(41350, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0), -(18708, 0, 5, 536870912, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0), -(57529, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(57531, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(72059, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), -(-11103, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(13234, 0, 0, 0, 0, 0, 0, 1, 0, 1027, 2, 0, 0, 0, 0), -(12043, 0, 3, 1631584309, 4096, 0, 0, 7, 1, 0, 8, 0, 0, 0, 0), -(16166, 0, 11, 3, 4096, 0, 0, 7, 1, 0, 8, 0, 0, 0, 0), -(17116, 0, 7, 268436065, 33554464, 32768, 0, 7, 1, 0, 8, 0, 0, 0, 0), -(-53583, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0), -(53515, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0), -(71993, 0, 0, 0, 0, 0, 4, 0, 0, 12287, 0, 0, 0, 4000, 0), -(35321, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), -(38363, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), -(39215, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0), -(45092, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(50871, 0, 9, 0, 1073741824, 0, 0, 1, 2, 2, 0, 0, 0, 0, 0), -(32065, 0, 0, 0, 0, 0, 524288, 1, 0, 0, 0, 0, 0, 0, 0), -(36659, 0, 0, 0, 0, 0, 524288, 1, 0, 0, 0, 0, 0, 0, 0), -(4341, 0, 0, 0, 0, 0, 4096, 1, 1, 0, 0, 0, 0, 0, 0), -(70904, 0, 6, 0, 0, 2048, 2048, 4, 0, 0, 0, 0, 0, 0, 0), -(63849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -(23591, 0, 10, 8388608, 0, 0, 16, 0, 2, 0, 2, 0, 0, 0, 0), -(-16689, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(-588, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), -(-59887, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), -(71567, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 400, 0), -(-14143, 0, 8, 1191182854, 2097152, 0, 0, 1, 2, 0, 8, 0, 0, 0, 0), -(60617, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0), -(40816, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7000, 0); - --- Threat of Thassarian triggered spells, for easier script access -DELETE FROM `spell_ranks` WHERE `first_spell_id` IN (59133,66198,66196,66216,66188,66215); -INSERT INTO `spell_ranks` (`first_spell_id`, `spell_id`, `rank`) VALUES -(66198, 66198, 1), -(66198, 66972, 2), -(66198, 66973, 3), -(66198, 66974, 4), - -(66196, 66196, 1), -(66196, 66958, 2), -(66196, 66959, 3), -(66196, 66960, 4), -(66196, 66961, 5), -(66196, 66962, 6), - -(66216, 66216, 1), -(66216, 66988, 2), -(66216, 66989, 3), -(66216, 66990, 4), -(66216, 66991, 5), -(66216, 66992, 6), - -(66188, 66188, 1), -(66188, 66950, 2), -(66188, 66951, 3), -(66188, 66952, 4), -(66188, 66953, 5), - -(66215, 66215, 1), -(66215, 66975, 2), -(66215, 66976, 3), -(66215, 66977, 4), -(66215, 66978, 5), -(66215, 66979, 6); - --- Remove renamed scripts -DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_gen_dummy_trigger','spell_pri_item_greater_heal_refund'); - --- Stop console spam from dummy EFFECT_2 proc -DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_pal_seals'; -INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES -(20375, 'spell_pal_seals'), -- Seal of Command -(21084, 'spell_pal_seals'), -- Seal of Righteousness -(31801, 'spell_pal_seals'), -- Seal of Vengeance -(31892, 'spell_pal_seals'), -- Seal of Blood -(33127, 'spell_pal_seals'), -- Seal of Command -(38008, 'spell_pal_seals'), -- Seal of Blood -(41459, 'spell_pal_seals'), -- Seal of Blood -(53720, 'spell_pal_seals'), -- Seal of the Martyr -(53736, 'spell_pal_seals'); -- Seal of Corruption - --- Grouped several hacks and handled with AuraScript now -DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_mage_fingers_of_frost'; -INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES -(74396, 'spell_mage_fingers_of_frost'); -- Fingers of Frost - --- Add spellscripts to spells previously on giant switches in Unit.cpp -DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_rog_t10_2p_bonus'; -DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_sha_flametongue_weapon','spell_mage_imp_blizzard','spell_warr_deep_wounds_aura','spell_rog_setup','spell_pri_improved_spirit_tap','spell_sha_imp_water_shield','spell_pal_improved_lay_of_hands','spell_pal_heart_of_the_crusader','spell_warl_seed_of_corruption_dummy','spell_mage_magic_absorption','spell_warr_extra_proc','spell_warr_second_wind','spell_warl_soul_leech','spell_sha_lightning_overload','spell_rog_quick_recovery','spell_mage_arcane_potency','spell_mage_empowered_fire','spell_pal_spiritual_attunement','spell_pal_divine_purpose','spell_pal_judgements_of_the_wise','spell_hun_thrill_of_the_hunt','spell_mage_missile_barrage','spell_mage_hot_streak','spell_pri_imp_shadowform','spell_dk_butchery','spell_item_unstable_power','spell_item_restless_strength','spell_pri_aq_3p_bonus','spell_item_persistent_shield','spell_dru_revitalize','spell_dk_scent_of_blood_trigger','spell_dk_vendetta','spell_dk_sudden_doom','spell_dk_blade_barrier','spell_dk_wandering_plague','spell_sha_astral_shift_aura','spell_dk_necrosis','spell_sha_static_shock','spell_sha_maelstrom_weapon','spell_sha_ancestral_awakening','spell_rog_deadly_brew','spell_rog_turn_the_tables','spell_rog_cut_to_the_chase','spell_pet_guard_dog','spell_hun_rapid_recuperation_trigger','spell_hun_hunting_party','spell_pal_infusion_of_light','spell_pal_judgements_of_the_just','spell_mage_burning_determination','spell_warr_improved_spell_reflection','spell_pet_culling_the_herd','spell_pet_silverback','spell_warl_decimation','spell_sha_frozen_power','spell_pri_body_and_soul','spell_dk_threat_of_thassarian','spell_warl_seduction','spell_mage_combustion','spell_pri_vampiric_embrace','spell_dru_omen_of_clarity','spell_item_alchemists_stone','spell_pal_judgement_of_light_heal','spell_pal_judgement_of_wisdom_mana','spell_twisted_reflection','spell_dru_t3_2p_bonus','spell_dru_t3_8p_bonus','spell_dru_t3_6p_bonus','spell_pal_t3_6p_bonus','spell_pri_t3_4p_bonus','spell_sha_t3_6p_bonus','spell_warr_t3_prot_8p_bonus','spell_item_healing_touch_refund','spell_item_totem_of_flowing_water','spell_sha_shamanistic_rage','spell_pal_seal_of_vengeance','spell_warl_seed_of_corruption_generic','spell_mark_of_malice','spell_item_mark_of_conquest','spell_sha_windfury_weapon','spell_dru_t4_2p_bonus','spell_pri_t5_heal_2p_bonus','spell_anetheron_vampiric_aura','spell_item_frozen_shadoweave','spell_item_aura_of_madness','spell_pri_item_t6_trinket','spell_dru_item_t6_trinket','spell_sha_item_t6_trinket','spell_pal_item_t6_trinket','spell_item_crystal_spire_of_karabor','spell_item_dementia','spell_item_pet_healing','spell_warl_t4_2p_bonus_shadow','spell_warl_t4_2p_bonus_fire','spell_mage_gen_extra_effects','spell_uk_second_wind','spell_item_sunwell_exalted_caster_neck','spell_item_sunwell_exalted_melee_neck','spell_item_sunwell_exalted_tank_neck','spell_item_sunwell_exalted_healer_neck','spell_warl_glyph_of_corruption_nightfall','spell_dk_mark_of_blood','spell_dk_dancing_rune_weapon','spell_dk_hungering_cold','spell_pal_sacred_shield_dummy','spell_warl_demonic_pact','spell_pal_seal_of_corruption','spell_dru_glyph_of_rejuvenation','spell_dru_glyph_of_shred','spell_dru_glyph_of_rake','spell_dru_glyph_of_innervate','spell_dru_glyph_of_starfire_dummy','spell_pal_glyph_of_holy_light_dummy','spell_pal_glyph_of_divinity','spell_sha_tidal_force_dummy','spell_sha_glyph_of_healing_wave','spell_pri_glyph_of_dispel_magic','spell_mage_glyph_of_icy_veins','spell_mage_glyph_of_polymorph','spell_rog_glyph_of_backstab','spell_hun_glyph_of_mend_pet','spell_pri_shadowfiend_death','spell_warr_glyph_of_blocking','spell_dk_glyph_of_scourge_strike','spell_sha_spirit_hunt','spell_hun_kill_command_pet','spell_item_swift_hand_justice_dummy','spell_item_discerning_eye_beast_dummy','spell_mage_imp_mana_gems','spell_dk_pvp_4p_bonus','spell_dru_savage_defense','spell_sha_glyph_of_earth_shield','spell_sha_glyph_of_totem_of_wrath','spell_warl_glyph_of_life_tap','spell_item_purified_shard_of_the_scale','spell_item_shiny_shard_of_the_scale','spell_dru_t10_balance_4p_bonus','spell_dru_t10_restoration_4p_bonus_dummy','spell_sha_t10_restoration_4p_bonus','spell_sha_t10_elemental_4p_bonus','spell_warr_item_t10_prot_4p_bonus','spell_item_tiny_abomination_in_a_jar','spell_item_tiny_abomination_in_a_jar_hero','spell_item_deadly_precision_dummy','spell_item_deadly_precision','spell_item_heartpierce','spell_item_heartpierce_hero','spell_item_deathbringers_will_normal','spell_item_deathbringers_will_heroic','spell_putricide_ooze_tank_protection','spell_deathbringer_blood_beast_blood_link'); -INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES -(-10400, 'spell_sha_flametongue_weapon'), -(-11185, 'spell_mage_imp_blizzard'), -(-12834, 'spell_warr_deep_wounds_aura'), -(-13983, 'spell_rog_setup'), -(-15337, 'spell_pri_improved_spirit_tap'), -(-16180, 'spell_sha_imp_water_shield'), -(-20234, 'spell_pal_improved_lay_of_hands'), -(-20335, 'spell_pal_heart_of_the_crusader'), -(-27243, 'spell_warl_seed_of_corruption_dummy'), -(-29441, 'spell_mage_magic_absorption'), - -(-29723, 'spell_warr_extra_proc'), -(-46913, 'spell_warr_extra_proc'), - -(-29834, 'spell_warr_second_wind'), -(-30293, 'spell_warl_soul_leech'), -(-30675, 'spell_sha_lightning_overload'), -(-31244, 'spell_rog_quick_recovery'), -(-31571, 'spell_mage_arcane_potency'), -(-31656, 'spell_mage_empowered_fire'), -(-31785, 'spell_pal_spiritual_attunement'), -(-31871, 'spell_pal_divine_purpose'), -(-31876, 'spell_pal_judgements_of_the_wise'), -(-34497, 'spell_hun_thrill_of_the_hunt'), -(-44404, 'spell_mage_missile_barrage'), -(-44445, 'spell_mage_hot_streak'), -(-47569, 'spell_pri_imp_shadowform'), -(-48979, 'spell_dk_butchery'), -(-48539, 'spell_dru_revitalize'), - -(-49004, 'spell_dk_scent_of_blood_trigger'), -(-49015, 'spell_dk_vendetta'), -(-49018, 'spell_dk_sudden_doom'), -(-49182, 'spell_dk_blade_barrier'), -(-49217, 'spell_dk_wandering_plague'), -(-51474, 'spell_sha_astral_shift_aura'), -(-51459, 'spell_dk_necrosis'), -(-51525, 'spell_sha_static_shock'), -(-51556, 'spell_sha_ancestral_awakening'), -(-51625, 'spell_rog_deadly_brew'), -(-51627, 'spell_rog_turn_the_tables'), -(-51664, 'spell_rog_cut_to_the_chase'), -(-53178, 'spell_pet_guard_dog'), -(-53228, 'spell_hun_rapid_recuperation_trigger'), -(-53290, 'spell_hun_hunting_party'), -(-53569, 'spell_pal_infusion_of_light'), -(-53695, 'spell_pal_judgements_of_the_just'), -(-54747, 'spell_mage_burning_determination'), -(-59088, 'spell_warr_improved_spell_reflection'), -(-61680, 'spell_pet_culling_the_herd'), -(-62764, 'spell_pet_silverback'), -(-63156, 'spell_warl_decimation'), -(-63373, 'spell_sha_frozen_power'), -(-64127, 'spell_pri_body_and_soul'), -(-65661, 'spell_dk_threat_of_thassarian'), -(6358, 'spell_warl_seduction'), -(11129, 'spell_mage_combustion'), -(15286, 'spell_pri_vampiric_embrace'), -(16864, 'spell_dru_omen_of_clarity'), -(17619, 'spell_item_alchemists_stone'), -(20185, 'spell_pal_judgement_of_light_heal'), -(20186, 'spell_pal_judgement_of_wisdom_mana'), -(21063, 'spell_twisted_reflection'), -(24658, 'spell_item_unstable_power'), -(24661, 'spell_item_restless_strength'), -(26169, 'spell_pri_aq_3p_bonus'), -(26467, 'spell_item_persistent_shield'), -(28716, 'spell_dru_t3_2p_bonus'), -(28719, 'spell_dru_t3_8p_bonus'), -(28744, 'spell_dru_t3_6p_bonus'), -(28789, 'spell_pal_t3_6p_bonus'), -(28809, 'spell_pri_t3_4p_bonus'), -(28823, 'spell_sha_t3_6p_bonus'), -(28845, 'spell_warr_t3_prot_8p_bonus'), -(28847, 'spell_item_healing_touch_refund'), -(28849, 'spell_item_totem_of_flowing_water'), -(30823, 'spell_sha_shamanistic_rage'), -(31801, 'spell_pal_seal_of_vengeance'), - -(32863, 'spell_warl_seed_of_corruption_generic'), -(36123, 'spell_warl_seed_of_corruption_generic'), -(38252, 'spell_warl_seed_of_corruption_generic'), -(39367, 'spell_warl_seed_of_corruption_generic'), -(44141, 'spell_warl_seed_of_corruption_generic'), -(70388, 'spell_warl_seed_of_corruption_generic'), - -(33493, 'spell_mark_of_malice'), -(33510, 'spell_item_mark_of_conquest'), -(33757, 'spell_sha_windfury_weapon'), -(37288, 'spell_dru_t4_2p_bonus'), -(37295, 'spell_dru_t4_2p_bonus'), -(37594, 'spell_pri_t5_heal_2p_bonus'), -(38196, 'spell_anetheron_vampiric_aura'), -(39372, 'spell_item_frozen_shadoweave'), -(39446, 'spell_item_aura_of_madness'), -(40438, 'spell_pri_item_t6_trinket'), -(40442, 'spell_dru_item_t6_trinket'), -(40463, 'spell_sha_item_t6_trinket'), -(40470, 'spell_pal_item_t6_trinket'), -(40971, 'spell_item_crystal_spire_of_karabor'), -(41404, 'spell_item_dementia'), - -(37381, 'spell_item_pet_healing'), - -(37377, 'spell_warl_t4_2p_bonus_shadow'), -(39437, 'spell_warl_t4_2p_bonus_fire'), - -(44401, 'spell_mage_gen_extra_effects'), -(48108, 'spell_mage_gen_extra_effects'), -(57761, 'spell_mage_gen_extra_effects'), - -(42770, 'spell_uk_second_wind'), -(45481, 'spell_item_sunwell_exalted_caster_neck'), -(45482, 'spell_item_sunwell_exalted_melee_neck'), -(45483, 'spell_item_sunwell_exalted_tank_neck'), -(45484, 'spell_item_sunwell_exalted_healer_neck'), - -(-18094, 'spell_warl_glyph_of_corruption_nightfall'), -(56218, 'spell_warl_glyph_of_corruption_nightfall'), - -(49005, 'spell_dk_mark_of_blood'), -(49028, 'spell_dk_dancing_rune_weapon'), -(51209, 'spell_dk_hungering_cold'), - -(53601, 'spell_pal_sacred_shield_dummy'), - -(53646, 'spell_warl_demonic_pact'), -(54909, 'spell_warl_demonic_pact'), - -(53736, 'spell_pal_seal_of_corruption'), -(53817, 'spell_sha_maelstrom_weapon'), -(54748, 'spell_mage_burning_determination'), -(54754, 'spell_dru_glyph_of_rejuvenation'), -(54815, 'spell_dru_glyph_of_shred'), -(54821, 'spell_dru_glyph_of_rake'), -(54832, 'spell_dru_glyph_of_innervate'), -(54845, 'spell_dru_glyph_of_starfire_dummy'), -(54937, 'spell_pal_glyph_of_holy_light_dummy'), -(54939, 'spell_pal_glyph_of_divinity'), -(55198, 'spell_sha_tidal_force_dummy'), -(55440, 'spell_sha_glyph_of_healing_wave'), -(55677, 'spell_pri_glyph_of_dispel_magic'), -(56374, 'spell_mage_glyph_of_icy_veins'), -(56375, 'spell_mage_glyph_of_polymorph'), -(56800, 'spell_rog_glyph_of_backstab'), -(57870, 'spell_hun_glyph_of_mend_pet'), -(57989, 'spell_pri_shadowfiend_death'), -(58375, 'spell_warr_glyph_of_blocking'), -(58642, 'spell_dk_glyph_of_scourge_strike'), -(58877, 'spell_sha_spirit_hunt'), -(58914, 'spell_hun_kill_command_pet'), -(59906, 'spell_item_swift_hand_justice_dummy'), -(59915, 'spell_item_discerning_eye_beast_dummy'), - -(37447, 'spell_mage_imp_mana_gems'), -(61062, 'spell_mage_imp_mana_gems'), - -(61257, 'spell_dk_pvp_4p_bonus'), -(62600, 'spell_dru_savage_defense'), -(63279, 'spell_sha_glyph_of_earth_shield'), -(63280, 'spell_sha_glyph_of_totem_of_wrath'), -(63320, 'spell_warl_glyph_of_life_tap'), -(69755, 'spell_item_purified_shard_of_the_scale'), -(69739, 'spell_item_shiny_shard_of_the_scale'), -(70723, 'spell_dru_t10_balance_4p_bonus'), -(70664, 'spell_dru_t10_restoration_4p_bonus_dummy'), -(70808, 'spell_sha_t10_restoration_4p_bonus'), -(70817, 'spell_sha_t10_elemental_4p_bonus'), -(70844, 'spell_warr_item_t10_prot_4p_bonus'), - -(71406, 'spell_item_tiny_abomination_in_a_jar'), -(71545, 'spell_item_tiny_abomination_in_a_jar_hero'), - -(71563, 'spell_item_deadly_precision_dummy'), -(71564, 'spell_item_deadly_precision'), - -(71880, 'spell_item_heartpierce'), -(71892, 'spell_item_heartpierce_hero'), - -(71519, 'spell_item_deathbringers_will_normal'), -(71562, 'spell_item_deathbringers_will_heroic'), - -(61685, 'spell_pet_charge'), -(-49200, 'spell_dk_acclimation'), -(70656, 'spell_dk_advantage_t10_4p'), -(37336, 'spell_dru_forms_trinket'), -(67353, 'spell_dru_t9_feral_relic'), -(13567, 'spell_gen_dummy_trigger'), -(-53234, 'spell_hun_piercing_shots'), -(67151, 'spell_hun_t9_4p_bonus'), -(-31641, 'spell_mage_blazing_speed'), -(-20210, 'spell_pal_illumination'), -(-27811, 'spell_pri_blessed_recovery'), -(37594, 'spell_pri_item_greater_heal_refund'), -(-47580, 'spell_pri_pain_and_suffering_dummy'), -(-324, 'spell_sha_lightning_shield'), -(-30881, 'spell_sha_nature_guardian'), -(-30299, 'spell_warl_nether_protection'), -(60510, 'spell_item_soul_preserver'), -(67702, 'spell_item_death_choice'), -(67771, 'spell_item_death_choice'), -(37657, 'spell_item_lightning_capacitor'), -(54841, 'spell_item_thunder_capacitor'), -(67712, 'spell_item_toc25_normal_caster_trinket'), -(67758, 'spell_item_toc25_heroic_caster_trinket'), -(57345, 'spell_item_darkmoon_card_greatness'), -(43820, 'spell_item_charm_witch_doctor'), -(27522, 'spell_item_mana_drain'), -(40336, 'spell_item_mana_drain'), - -(71770, 'spell_putricide_ooze_tank_protection'), -(72176, 'spell_deathbringer_blood_beast_blood_link'); - --- Kill the damned thing already! -DROP TABLE IF EXISTS `spell_proc_event`; diff --git a/data/sql/updates/pending_db_world/rev_1664980163888388800.sql b/data/sql/updates/pending_db_world/rev_1664980163888388800.sql new file mode 100644 index 000000000..d7baaa402 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664980163888388800.sql @@ -0,0 +1,2950 @@ +-- +-- Restoring spell_proc to how it was before the commit. +DROP TABLE IF EXISTS `spell_proc`; +CREATE TABLE IF NOT EXISTS `spell_proc` ( + `spellId` MEDIUMINT(9) NOT NULL DEFAULT '0', + `schoolMask` TINYINT(4) NOT NULL DEFAULT '0', + `spellFamilyName` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `spellFamilyMask0` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `spellFamilyMask1` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `spellFamilyMask2` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `typeMask` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `spellTypeMask` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `spellPhaseMask` INT(11) NOT NULL DEFAULT '0', + `hitMask` INT(11) NOT NULL DEFAULT '0', + `attributesMask` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `ratePerMinute` FLOAT NOT NULL DEFAULT '0', + `chance` FLOAT NOT NULL DEFAULT '0', + `cooldown` FLOAT NOT NULL DEFAULT '0', + `charges` INT(10) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`spellId`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4; + +-- Restoring spell_script_names to how it was before the commit +DROP TABLE IF EXISTS `spell_script_names`; +CREATE TABLE IF NOT EXISTS `spell_script_names` ( + `spell_id` INT(11) NOT NULL, + `ScriptName` CHAR(64) NOT NULL, + UNIQUE KEY `spell_id` (`spell_id`,`ScriptName`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4; + +DELETE FROM `spell_script_names`; + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(-62900, 'spell_dk_death_coil'), +(-61391, 'spell_dru_typhoon'), +(-58872, 'spell_warr_damage_shield'), +(-56342, 'spell_hun_lock_and_load'), +(-55428, 'spell_gen_lifeblood'), +(-55090, 'spell_dk_scourge_strike'), +(-54347, 'spell_warl_improved_demonic_tactics'), +(-53302, 'spell_hun_sniper_training'), +(-52284, 'spell_dk_will_of_the_necropolis'), +(-51940, 'spell_sha_earthliving_weapon'), +(-51685, 'spell_rog_prey_on_the_weak'), +(-51490, 'spell_sha_thunderstorm'), +(-51474, 'spell_sha_astral_shift'), +(-51123, 'spell_gen_no_offhand_proc'), +(-50391, 'spell_dk_improved_unholy_presence'), +(-50384, 'spell_dk_improved_frost_presence'), +(-50365, 'spell_dk_improved_blood_presence'), +(-50294, 'spell_dru_starfall_aoe'), +(-50286, 'spell_dru_starfall_dummy'), +(-49998, 'spell_dk_death_strike'), +(-49821, 'spell_pri_mind_sear'), +(-49219, 'spell_dk_blood_caked_blade'), +(-49217, 'spell_dk_wandering_plague_aura'), +(-49188, 'spell_gen_no_offhand_proc'), +(-49158, 'spell_dk_corpse_explosion'), +(-49145, 'spell_dk_spell_deflection'), +(-49004, 'spell_dk_scent_of_blood_trigger'), +(-49004, 'spell_gen_proc_from_direct_damage'), +(-48721, 'spell_dk_blood_boil'), +(-48496, 'spell_dru_living_seed'), +(-48438, 'spell_dru_wild_growth'), +(-48181, 'spell_warl_haunt'), +(-47897, 'spell_warl_shadowflame'), +(-47541, 'spell_dk_death_coil'), +(-47540, 'spell_pri_penance'), +(-47509, 'spell_pri_divine_aegis'), +(-47230, 'spell_warl_fel_synergy'), +(-44546, 'spell_mage_brain_freeze'), +(-44543, 'spell_mage_fingers_of_frost_proc_aura'), +(-44457, 'spell_mage_living_bomb'), +(-44450, 'spell_mage_burnout_trigger'), +(-44449, 'spell_mage_burnout'), +(-43265, 'spell_dk_death_and_decay'), +(-42243, 'spell_hun_volley_trigger'), +(-35696, 'spell_warl_demonic_knowledge'), +(-35541, 'spell_rog_combat_potency'), +(-34914, 'spell_pri_vampiric_touch'), +(-34861, 'spell_pri_circle_of_healing'), +(-33872, 'spell_dru_nurturing_instinct'), +(-33851, 'spell_dru_primal_tenacity'), +(-33763, 'spell_dru_lifebloom'), +(-32379, 'spell_pri_shadow_word_death'), +(-31850, 'spell_pal_ardent_defender'), +(-31228, 'spell_rog_cheat_death'), +(-31130, 'spell_rog_nerves_of_steel'), +(-30706, 'spell_sha_totem_of_wrath'), +(-30482, 'spell_mage_molten_armor'), +(-30451, 'spell_mage_arcane_blast'), +(-30143, 'spell_warl_demonic_aegis'), +(-30108, 'spell_warl_unstable_affliction'), +(-29074, 'spell_mage_master_of_elements'), +(-27285, 'spell_warl_seed_of_corruption'), +(-24869, 'spell_gen_holiday_buff_food'), +(-20473, 'spell_pal_holy_shock'), +(-19572, 'spell_hun_improved_mend_pet'), +(-19386, 'spell_hun_wyvern_sting'), +(-17002, 'spell_dru_feral_swiftness'), +(-16972, 'spell_dru_predatory_strikes'), +(-16257, 'spell_sha_flurry_proc'), +(-12317, 'spell_gen_proc_from_direct_damage'), +(-12162, 'spell_warr_deep_wounds'), +(-11426, 'spell_mage_ice_barrier'), +(-11119, 'spell_mage_ignite'), +(-11113, 'spell_mage_blast_wave'), +(-9799, 'spell_pal_eye_for_an_eye'), +(-8050, 'spell_sha_flame_shock'), +(-7001, 'spell_pri_lightwell_renew'), +(-6229, 'spell_warl_shadow_ward'), +(-6201, 'spell_warl_create_healthstone'), +(-6143, 'spell_mage_fire_frost_ward'), +(-5570, 'spell_dru_insect_swarm'), +(-5308, 'spell_warr_execute'), +(-5217, 'spell_dru_tiger_s_fury'), +(-2818, 'spell_rog_deadly_poison'), +(-1943, 'spell_rog_rupture'), +(-1850, 'spell_dru_dash'), +(-1535, 'spell_sha_fire_nova'), +(-1464, 'spell_warr_slam'), +(-1463, 'spell_mage_mana_shield'), +(-1454, 'spell_warl_life_tap'), +(-1120, 'spell_warl_drain_soul'), +(-1079, 'spell_dru_rip'), +(-1064, 'spell_sha_chain_heal'), +(-974, 'spell_sha_earth_shield'), +(-772, 'spell_warr_rend'), +(-755, 'spell_hun_check_pet_los'), +(-755, 'spell_warl_health_funnel'), +(-746, 'spell_gen_bandage'), +(-710, 'spell_warl_banish'), +(-633, 'spell_pal_lay_on_hands'), +(-603, 'spell_warl_curse_of_doom'), +(-543, 'spell_mage_fire_frost_ward'), +(-139, 'spell_pri_renew'), +(-136, 'spell_hun_check_pet_los'), +(-100, 'spell_warr_charge'), +(-17, 'spell_pri_power_word_shield'), +(126, 'spell_warl_eye_of_kilrogg'), +(605, 'spell_pri_mind_control'), +(694, 'spell_warr_mocking_blow'), +(698, 'spell_warl_ritual_of_summoning'), +(781, 'spell_hun_disengage'), +(802, 'spell_mutate_explode_bug'), +(804, 'spell_mutate_explode_bug'), +(818, 'spell_gen_basic_campfire'), +(1038, 'spell_pal_hand_of_salvation'), +(1090, 'spell_item_magic_dust'), +(1178, 'spell_dru_bear_form_passive'), +(1515, 'spell_hun_tame_beast'), +(1742, 'spell_hun_cower'), +(2825, 'spell_sha_bloodlust'), +(3411, 'spell_warr_intervene'), +(4073, 'spell_gen_allow_cast_from_item_only'), +(4338, 'spell_q13280_13283_plant_battle_standard'), +(5024, 'spell_item_skull_of_impeding_doom'), +(5229, 'spell_dru_enrage'), +(5246, 'spell_warr_intimidating_shout'), +(5487, 'spell_dru_feral_swiftness'), +(5938, 'spell_rog_shiv'), +(6358, 'spell_warl_seduction'), +(6474, 'spell_sha_earthbind_totem'), +(6495, 'spell_sha_sentry_totem'), +(6870, 'spell_gen_moss_covered_feet'), +(6940, 'spell_pal_hand_of_sacrifice'), +(6962, 'spell_gen_pet_summoned'), +(7054, 'spell_shadowfang_keep_forsaken_skills'), +(7057, 'spell_shadowfang_keep_haunting_spirits'), +(7102, 'spell_contagion_of_rot'), +(7215, 'spell_item_with_mount_speed'), +(7384, 'spell_warr_overpower'), +(7434, 'spell_item_fate_rune_of_unsurpassed_vigor'), +(7887, 'spell_warr_overpower'), +(7932, 'spell_item_anti_venom'), +(7933, 'spell_item_strong_anti_venom'), +(8063, 'spell_item_deviate_fish'), +(8067, 'spell_item_party_time'), +(8129, 'spell_pri_mana_burn'), +(8171, 'spell_sha_cleansing_totem_pulse'), +(8213, 'spell_item_savory_deviate_delight'), +(8342, 'spell_item_goblin_jumper_cables'), +(8344, 'spell_item_gnomish_universal_remote'), +(8593, 'spell_symbol_of_life_dummy'), +(8856, 'spell_q1846_bending_shinbone'), +(8913, 'spell_q55_sacred_cleansing'), +(9204, 'spell_gen_hate_to_zero'), +(9634, 'spell_dru_feral_swiftness'), +(9635, 'spell_dru_bear_form_passive'), +(9712, 'spell_q2203_thaumaturgy_channel'), +(9771, 'spell_gnomeregan_radiation_bolt'), +(10101, 'spell_gen_knock_away'), +(10247, 'spell_zulfarrak_summon_zulfarrak_zombies'), +(10255, 'spell_uldaman_stoned'), +(10340, 'spell_uldaman_boss_agro_archaedas'), +(10738, 'spell_zulfarrak_unlocking'), +(11568, 'spell_uldaman_sub_boss_agro_keepers'), +(11584, 'spell_warr_overpower'), +(11585, 'spell_warr_overpower'), +(11885, 'spell_item_muisek_vessel'), +(11886, 'spell_item_muisek_vessel'), +(11887, 'spell_item_muisek_vessel'), +(11888, 'spell_item_muisek_vessel'), +(11889, 'spell_item_muisek_vessel'), +(11958, 'spell_mage_cold_snap'), +(12021, 'spell_scholomance_fixate'), +(12328, 'spell_warr_sweeping_strikes'), +(12346, 'spell_temple_of_atal_hakkar_awaken_the_soulflayer'), +(12479, 'spell_temple_of_atal_hakkar_hex_of_jammal_an'), +(12749, 'spell_gen_allow_cast_from_item_only'), +(12809, 'spell_warr_concussion_blow'), +(12975, 'spell_warr_last_stand'), +(13006, 'spell_item_gnomish_shrink_ray'), +(13120, 'spell_item_net_o_matic'), +(13161, 'spell_hun_aspect_of_the_beast'), +(13166, 'spell_gen_allow_cast_from_item_only'), +(13180, 'spell_item_mind_amplify_dish'), +(13258, 'spell_gen_allow_cast_from_item_only'), +(13280, 'spell_item_gnomish_death_ray'), +(13567, 'spell_gen_dummy_trigger'), +(13877, 'spell_rog_blade_flurry'), +(14185, 'spell_rog_preparation'), +(14537, 'spell_item_six_demon_bag'), +(15366, 'spell_gen_disabled_above_63'), +(15600, 'spell_gen_proc_reduced_above_60'), +(15712, 'spell_item_linken_boomerang'), +(15748, 'spell_item_freeze_rookery_egg'), +(15958, 'spell_q4735_collect_rookery_egg'), +(15998, 'spell_gen_despawn_self'), +(16028, 'spell_item_freeze_rookery_egg'), +(16349, 'spell_blackrock_spire_call_of_vaelastrasz'), +(16372, 'spell_gyth_chromatic_protection'), +(16414, 'spell_item_wraith_scythe_drain_life'), +(16589, 'spell_item_noggenfogger_elixir'), +(16796, 'spell_q5056_summon_shy_rotam'), +(16864, 'spell_dru_omen_of_clarity'), +(17009, 'spell_voodoo'), +(17179, 'spell_scholomance_boon_of_life'), +(17251, 'spell_gen_spirit_healer_res'), +(17271, 'spell_q5206_test_fetid_skull'), +(17512, 'spell_item_piccolo_of_the_flaming_fire'), +(18173, 'spell_vael_burning_adrenaline'), +(18277, 'spell_onslaught_or_call_bone_gryphon'), +(18541, 'spell_warl_ritual_of_doom_effect'), +(18670, 'spell_vem_knockback'), +(18765, 'spell_warr_sweeping_strikes'), +(18813, 'spell_gen_knock_away'), +(18945, 'spell_gen_knock_away'), +(19395, 'spell_gordunni_trap'), +(19411, 'spell_magmadar_lava_bomb'), +(19512, 'spell_q6124_6129_apply_salve'), +(19515, 'spell_garr_frenzy'), +(19548, 'spell_hun_tame_beast'), +(19574, 'spell_hun_bestial_wrath'), +(19577, 'spell_hun_intimidation'), +(19593, 'spell_egg_explosion'), +(19597, 'spell_hun_taming_the_beast'), +(19633, 'spell_gen_knock_away'), +(19674, 'spell_hun_tame_beast'), +(19676, 'spell_hun_taming_the_beast'), +(19677, 'spell_hun_taming_the_beast'), +(19678, 'spell_hun_taming_the_beast'), +(19679, 'spell_hun_taming_the_beast'), +(19680, 'spell_hun_taming_the_beast'), +(19681, 'spell_hun_taming_the_beast'), +(19682, 'spell_hun_taming_the_beast'), +(19683, 'spell_hun_taming_the_beast'), +(19684, 'spell_hun_taming_the_beast'), +(19685, 'spell_hun_taming_the_beast'), +(19686, 'spell_hun_taming_the_beast'), +(19687, 'spell_hun_tame_beast'), +(19688, 'spell_hun_tame_beast'), +(19689, 'spell_hun_tame_beast'), +(19692, 'spell_hun_tame_beast'), +(19693, 'spell_hun_tame_beast'), +(19694, 'spell_hun_tame_beast'), +(19695, 'spell_geddon_inferno'), +(19696, 'spell_hun_tame_beast'), +(19697, 'spell_hun_tame_beast'), +(19699, 'spell_hun_tame_beast'), +(19700, 'spell_hun_tame_beast'), +(19753, 'spell_pal_divine_intervention'), +(19774, 'spell_summon_ragnaros'), +(19804, 'spell_gen_allow_cast_from_item_only'), +(19822, 'spell_mc_play_dead'), +(19873, 'spell_egg_event'), +(20004, 'spell_gen_reduced_above_60'), +(20005, 'spell_gen_reduced_above_60'), +(20007, 'spell_gen_reduced_above_60'), +(20154, 'spell_pal_seal_of_righteousness'), +(20165, 'spell_pal_seal_of_light'), +(20166, 'spell_pal_seal_of_light'), +(20230, 'spell_warr_retaliation'), +(20271, 'spell_pal_judgement_of_light'), +(20375, 'spell_pal_seal_of_command'), +(20424, 'spell_pal_seal_of_command'), +(20425, 'spell_pal_judgement_of_command'), +(20474, 'spell_magmadar_lava_bomb'), +(20478, 'spell_geddon_armageddon'), +(20538, 'spell_hate_to_zero'), +(20577, 'spell_gen_cannibalize'), +(20589, 'spell_gen_remove_impairing_auras'), +(20625, 'spell_gen_default_count_pct_from_max_hp'), +(20631, 'spell_gen_use_spell_base_level_check'), +(20686, 'spell_gen_knock_away'), +(20911, 'spell_gen_damage_reduction_aura'), +(20911, 'spell_pal_blessing_of_sanctuary'), +(21084, 'spell_pal_seal_of_righteousness'), +(21094, 'spell_majordomo_separation_nexiety'), +(21108, 'spell_ragnaros_summon_sons_of_flame'), +(21147, 'spell_arcane_vacuum'), +(21149, 'spell_item_eggnog'), +(21708, 'spell_gen_visual_dummy_stun'), +(21737, 'spell_gen_periodic_knock_away'), +(21809, 'spell_gen_random_target32'), +(21848, 'spell_item_snowman'), +(21908, 'spell_ragnaros_lava_burst_randomizer'), +(22247, 'spell_suppression_aura'), +(22276, 'spell_gen_elemental_shield'), +(22282, 'spell_gen_brood_power'), +(22539, 'spell_bwl_shadowflame'), +(22563, 'spell_item_recall'), +(22564, 'spell_item_recall'), +(22659, 'spell_spawn_drakonid'), +(22664, 'spell_shadowblink'), +(22803, 'spell_gen_random_target32'), +(22812, 'spell_dru_barkskin'), +(22821, 'spell_gen_random_target32'), +(22888, 'spell_gen_disabled_above_63'), +(22888, 'spell_gen_rallying_cry_of_the_dragonslayer'), +(22999, 'spell_item_goblin_jumper_cables_xl'), +(23019, 'spell_item_crystal_prison_dummy_dnd'), +(23074, 'spell_item_arcanite_dragonling'), +(23075, 'spell_item_mithril_mechanical_dragonling'), +(23076, 'spell_item_mechanical_dragonling'), +(23133, 'spell_item_gnomish_battle_chicken'), +(23134, 'spell_item_goblin_bomb'), +(23138, 'spell_shazzrah_gate_dummy'), +(23183, 'spell_mark_of_frost_freeze'), +(23397, 'spell_class_call_handler'), +(23398, 'spell_class_call_handler'), +(23401, 'spell_class_call_handler'), +(23410, 'aura_class_call_wild_magic'), +(23410, 'spell_class_call_handler'), +(23414, 'spell_class_call_handler'), +(23418, 'aura_class_call_siphon_blessing'), +(23418, 'spell_class_call_handler'), +(23424, 'spell_corrupted_totems'), +(23425, 'spell_class_call_handler'), +(23427, 'spell_class_call_handler'), +(23436, 'spell_class_call_handler'), +(23448, 'spell_gen_gadgetzan_transporter_backfire'), +(23453, 'spell_gen_gnomish_transporter'), +(23487, 'spell_garr_separation_nexiety'), +(23551, 'spell_sha_item_lightning_shield'), +(23552, 'spell_sha_item_lightning_shield_trigger'), +(23567, 'spell_gen_bandage'), +(23568, 'spell_gen_bandage'), +(23569, 'spell_gen_bandage'), +(23572, 'spell_sha_item_mana_surge'), +(23603, 'spell_class_call_polymorph'), +(23696, 'spell_gen_bandage'), +(23780, 'spell_item_aegis_of_preservation'), +(23786, 'spell_item_powerful_anti_venom'), +(23878, 'spell_random_aggro'), +(23880, 'spell_warr_bloodthirst_heal'), +(23881, 'spell_warr_bloodthirst'), +(23970, 'spell_batrider_bomb'), +(23989, 'spell_hun_readiness'), +(24083, 'spell_hatch_eggs'), +(24084, 'spell_marli_transform'), +(24110, 'spell_enveloping_webs'), +(24306, 'spell_delusions_of_jindo'), +(24314, 'spell_threatening_gaze'), +(24315, 'spell_threatening_gaze_charge'), +(24324, 'spell_blood_siphon'), +(24325, 'spell_pagles_point_cast'), +(24326, 'spell_gahzranka_slam'), +(24401, 'spell_gen_model_visible'), +(24408, 'spell_mandokir_charge'), +(24412, 'spell_gen_bandage'), +(24413, 'spell_gen_bandage'), +(24414, 'spell_gen_bandage'), +(24531, 'spell_item_refocus'), +(24590, 'spell_item_brittle_armor'), +(24684, 'spell_chain_burn'), +(24693, 'spell_hakkar_power_down'), +(24717, 'spell_hallows_end_pirate_costume'), +(24718, 'spell_hallows_end_ninja_costume'), +(24719, 'spell_hallows_end_leper_costume'), +(24720, 'spell_hallows_end_trick'), +(24737, 'spell_hallows_end_ghost_costume'), +(24750, 'spell_hallows_end_trick'), +(24751, 'spell_hallows_end_trick_or_treat'), +(24778, 'spell_dream_fog_sleep'), +(24834, 'spell_shadow_bolt_whirl'), +(24905, 'spell_dru_moonkin_form_passive_proc'), +(24930, 'spell_hallows_end_candy'), +(24983, 'spell_gen_baby_murloc_passive'), +(24984, 'spell_gen_baby_murloc'), +(25042, 'spell_mark_of_nature'), +(25153, 'spell_aggro_drones'), +(25177, 'spell_crystal_weakness'), +(25178, 'spell_crystal_weakness'), +(25180, 'spell_crystal_weakness'), +(25181, 'spell_crystal_weakness'), +(25183, 'spell_crystal_weakness'), +(25185, 'spell_itch_aq20'), +(25281, 'spell_gen_turkey_marker'), +(25371, 'spell_consume_aq20'), +(25373, 'spell_gen_10pct_count_pct_from_max_hp'), +(25599, 'spell_rajaxx_thundercrash'), +(25671, 'spell_drain_mana'), +(25676, 'spell_moam_mana_drain_filter'), +(25684, 'spell_moam_summon_mana_fiends'), +(25711, 'spell_ayamiss_swarmer_start_loop'), +(25755, 'spell_drain_mana'), +(25778, 'spell_gen_knock_away'), +(25790, 'spell_vem_vengeance'), +(25830, 'spell_ayamiss_swarmer_teleport_trigger'), +(25833, 'spell_gen_ayamiss_swarmer_loop_1'), +(25834, 'spell_gen_ayamiss_swarmer_loop_2'), +(25835, 'spell_gen_ayamiss_swarmer_loop_3'), +(25844, 'spell_ayamiss_swarmer_swarm'), +(25860, 'spell_item_reindeer_transformation'), +(25899, 'spell_gen_damage_reduction_aura'), +(25899, 'spell_pal_blessing_of_sanctuary'), +(25938, 'spell_explode_trigger'), +(25952, 'spell_gen_despawn_self'), +(26052, 'spell_huhuran_poison_bolt'), +(26077, 'spell_itch_aq40'), +(26180, 'spell_huhuran_wyvern_sting'), +(26192, 'spell_skeram_arcane_explosion'), +(26218, 'spell_winter_veil_mistletoe'), +(26275, 'spell_winter_wondervolt_trap'), +(26374, 'spell_gen_elune_candle'), +(26400, 'spell_item_arcane_shroud'), +(26465, 'spell_item_mercurial_shield'), +(26546, 'spell_aq_shadow_storm'), +(26552, 'spell_nullify'), +(26555, 'spell_aq_shadow_storm'), +(26584, 'spell_summon_toxin_slime'), +(26678, 'spell_item_create_heart_candy'), +(27539, 'spell_gen_obsidian_armor'), +(27686, 'spell_razelikh_teleport_group'), +(27687, 'spell_kormok_summon_bone_minions'), +(27695, 'spell_kormok_summon_bone_mages'), +(27769, 'spell_gen_whisper_gulch_yogg_saron_whisper'), +(27808, 'spell_kelthuzad_frost_blast'), +(27819, 'spell_kelthuzad_detonate_mana'), +(27831, 'spell_gothik_shadow_bolt_volley'), +(27867, 'spell_gen_disabled_above_70'), +(28062, 'spell_thaddius_pos_neg_charge'), +(28085, 'spell_thaddius_pos_neg_charge'), +(28089, 'spell_thaddius_polarity_shift'), +(28169, 'spell_grobbulus_mutating_injection'), +(28241, 'spell_grobbulus_poison'), +(28305, 'spell_pri_mana_leech'), +(28374, 'spell_gluth_decimate'), +(28441, 'spell_item_ashbringer'), +(28524, 'spell_sapphiron_frost_explosion'), +(28682, 'spell_mage_combustion_proc'), +(28702, 'spell_gen_netherbloom'), +(28720, 'spell_gen_nightmare_vine'), +(28764, 'spell_gen_adaptive_warding'), +(28832, 'spell_four_horsemen_mark'), +(28833, 'spell_four_horsemen_mark'), +(28834, 'spell_four_horsemen_mark'), +(28835, 'spell_four_horsemen_mark'), +(28845, 'spell_warr_t3_prot_8p_bonus'), +(28862, 'spell_item_the_eye_of_diminution'), +(28865, 'spell_four_horsemen_consumption'), +(28880, 'spell_gen_gift_of_naaru'), +(29142, 'spell_gen_default_count_pct_from_max_hp'), +(29166, 'spell_dru_innervate'), +(29200, 'spell_item_purify_helboar_meat'), +(29266, 'spell_gen_creature_permanent_feign_death'), +(29341, 'spell_warl_shadowburn'), +(29431, 'spell_gen_select_target_count_15_1'), +(29431, 'spell_moroes_vanish'), +(29435, 'spell_gen_despawn_self'), +(29519, 'spell_silithyst'), +(29768, 'spell_karazhan_overload'), +(29830, 'spell_item_mirrens_drinking_hat'), +(29858, 'spell_warl_soulshatter'), +(29866, 'spell_q9452_cast_net'), +(29883, 'spell_gen_select_target_count_15_1'), +(29883, 'spell_karazhan_blink'), +(30099, 'spell_hun_tame_beast'), +(30100, 'spell_hun_taming_the_beast'), +(30102, 'spell_hun_tame_beast'), +(30103, 'spell_hun_taming_the_beast'), +(30104, 'spell_hun_taming_the_beast'), +(30105, 'spell_hun_tame_beast'), +(30205, 'spell_gen_visual_dummy_stun'), +(30410, 'spell_magtheridon_shadow_grasp'), +(30458, 'spell_item_nigh_invulnerability'), +(30505, 'spell_tsh_shadow_bolt'), +(30507, 'spell_item_poultryizer'), +(30541, 'spell_magtheridon_blaze'), +(30646, 'spell_hun_tame_beast'), +(30647, 'spell_hun_taming_the_beast'), +(30648, 'spell_hun_taming_the_beast'), +(30652, 'spell_hun_taming_the_beast'), +(30653, 'spell_hun_tame_beast'), +(30654, 'spell_hun_tame_beast'), +(30693, 'spell_vazruden_call_nazan'), +(30735, 'spell_tsh_shadow_sear'), +(30914, 'spell_broggok_poison_cloud'), +(30918, 'spell_gen_remove_impairing_auras'), +(30926, 'spell_vazruden_fireball'), +(30952, 'spell_tsh_shoot_flame_arrow'), +(31225, 'spell_item_shimmering_vessel'), +(31261, 'spell_gen_creature_permanent_feign_death'), +(31326, 'spell_black_morass_corrupt_medivh'), +(31389, 'spell_gen_knock_away'), +(31399, 'spell_gen_moss_covered_feet'), +(31427, 'spell_gen_allergies'), +(31447, 'spell_mark_of_kazrogal'), +(31687, 'spell_mage_summon_water_elemental'), +(31696, 'spell_q12943_shadow_vault_decree'), +(31789, 'spell_pal_righteous_defense'), +(31884, 'spell_pal_avenging_wrath'), +(31984, 'spell_finger_of_death'), +(32111, 'spell_red_sky_effect'), +(32146, 'spell_q9874_liquid_fire'), +(32182, 'spell_sha_heroism'), +(32441, 'spell_karazhan_brittle_bones'), +(32727, 'spell_gen_bg_preparation'), +(32826, 'spell_mage_polymorph_cast_visual'), +(32830, 'spell_auchenai_possess'), +(32959, 'spell_gen_knock_away'), +(32960, 'spell_mark_of_kazzak'), +(33060, 'spell_item_make_a_wish'), +(33110, 'spell_pri_prayer_of_mending_heal'), +(33401, 'spell_auchenai_possess'), +(33525, 'spell_gruul_ground_slam'), +(33654, 'spell_gruul_shatter'), +(33666, 'spell_murmur_sonic_boom_effect'), +(33671, 'spell_gruul_shatter_effect'), +(33695, 'spell_pal_exorcism_and_holy_wrath_damage'), +(33735, 'spell_rog_blade_flurry'), +(33793, 'spell_vazruden_fireball'), +(33794, 'spell_vazruden_fireball'), +(33896, 'spell_item_desperate_defense'), +(33953, 'spell_item_essence_of_life'), +(34074, 'spell_hun_ascpect_of_the_viper'), +(34098, 'spell_gen_clear_debuffs'), +(34133, 'spell_alar_ember_blast'), +(34201, 'spell_botanica_shift_form'), +(34229, 'spell_alar_flame_quills'), +(34246, 'spell_dru_idol_lifebloom'), +(34341, 'spell_alar_ember_blast_death'), +(34428, 'spell_warr_victory_rush'), +(34438, 'spell_warl_unstable_affliction'), +(34439, 'spell_warl_unstable_affliction'), +(34477, 'spell_hun_misdirection'), +(34719, 'spell_midnight_fixate'), +(34803, 'spell_commander_sarannis_summon_reinforcements'), +(34852, 'spell_botanica_call_of_the_falcon'), +(34902, 'spell_hun_generic_scaling'), +(34903, 'spell_hun_generic_scaling'), +(34904, 'spell_hun_generic_scaling'), +(34947, 'spell_warl_generic_scaling'), +(34956, 'spell_warl_generic_scaling'), +(34957, 'spell_warl_generic_scaling'), +(34958, 'spell_warl_generic_scaling'), +(35035, 'spell_the_eye_countercharge'), +(35079, 'spell_hun_misdirection_proc'), +(35139, 'spell_gen_default_count_pct_from_max_hp'), +(35183, 'spell_warl_unstable_affliction'), +(35201, 'spell_gen_paralytic_poison'), +(35268, 'spell_ragin_flames_inferno'), +(35354, 'spell_hand_of_death'), +(35356, 'spell_gen_creature_permanent_feign_death'), +(35357, 'spell_gen_creature_permanent_feign_death'), +(35367, 'spell_alar_dive_bomb'), +(35429, 'spell_warr_sweeping_strikes'), +(35657, 'spell_mage_pet_scaling'), +(35658, 'spell_mage_pet_scaling'), +(35659, 'spell_mage_pet_scaling'), +(35660, 'spell_mage_pet_scaling'), +(35661, 'spell_pri_shadowfiend_scaling'), +(35662, 'spell_pri_shadowfiend_scaling'), +(35663, 'spell_pri_shadowfiend_scaling'), +(35664, 'spell_pri_shadowfiend_scaling'), +(35665, 'spell_sha_fire_elemental_scaling'), +(35666, 'spell_sha_fire_elemental_scaling'), +(35667, 'spell_sha_fire_elemental_scaling'), +(35668, 'spell_sha_fire_elemental_scaling'), +(35669, 'spell_dru_treant_scaling'), +(35670, 'spell_dru_treant_scaling'), +(35671, 'spell_dru_treant_scaling'), +(35672, 'spell_dru_treant_scaling'), +(35674, 'spell_sha_feral_spirit_scaling'), +(35675, 'spell_sha_feral_spirit_scaling'), +(35676, 'spell_sha_feral_spirit_scaling'), +(35745, 'spell_item_socrethars_stone'), +(35865, 'spell_kaelthas_summon_nether_vapor'), +(35869, 'spell_kaelthas_nether_beam'), +(35941, 'spell_kaelthas_gravity_lapse'), +(36186, 'spell_warl_infernal_scaling'), +(36188, 'spell_warl_infernal_scaling'), +(36189, 'spell_warl_infernal_scaling'), +(36190, 'spell_warl_infernal_scaling'), +(36444, 'spell_wintergrasp_water'), +(36448, 'spell_gen_focused_bursts'), +(36450, 'spell_kaelthas_resurrection'), +(36475, 'spell_gen_focused_bursts'), +(36500, 'spell_gen_throw_back'), +(36573, 'spell_q10525_vision_guide'), +(36709, 'spell_kaelthas_kael_phase_two'), +(36720, 'spell_kaelthas_burn'), +(36730, 'spell_kaelthas_flame_strike'), +(36778, 'spell_arcatraz_soul_steal'), +(36785, 'spell_quest_test_flight_charging'), +(36797, 'spell_kaelthas_mind_control'), +(36860, 'spell_quest_test_flight_charging'), +(36890, 'spell_item_dimensional_ripper_area52'), +(36921, 'spell_vazruden_fireball'), +(36976, 'spell_kaelthas_summon_weapons'), +(37025, 'spell_serpentshrine_cavern_coilfang_water'), +(37027, 'spell_kaelthas_remote_toy'), +(37065, 'spell_q10036_torgos'), +(37097, 'spell_q10563_q10596_to_legion_hold'), +(37408, 'spell_oscillating_field'), +(37430, 'spell_lurker_below_spout'), +(37433, 'spell_lurker_below_spout_cone'), +(37506, 'spell_hun_scatter_shot'), +(37594, 'spell_pri_item_greater_heal_refund'), +(37641, 'spell_leotheras_whirlwind'), +(37674, 'spell_leotheras_chaos_blast'), +(37676, 'spell_leotheras_insidious_whisper'), +(37705, 'spell_item_eye_of_gruul_healing_discount'), +(37716, 'spell_leotheras_demon_link'), +(37727, 'spell_gen_charmed_unit_spell_cooldown'), +(37750, 'spell_leotheras_clear_consuming_madness'), +(37851, 'spell_gen_charmed_unit_spell_cooldown'), +(37853, 'spell_black_morass_corrupt_medivh'), +(37877, 'spell_pal_blessing_of_faith'), +(37917, 'spell_gen_charmed_unit_spell_cooldown'), +(37918, 'spell_gen_charmed_unit_spell_cooldown'), +(37919, 'spell_gen_charmed_unit_spell_cooldown'), +(37934, 'spell_hydross_cleansing_field_command'), +(37935, 'spell_hydross_cleansing_field_aura'), +(38017, 'spell_gen_select_target_count_7_1'), +(38028, 'spell_morogrim_tidewalker_watery_grave'), +(38055, 'spell_q10612_10613_the_fel_and_the_furious'), +(38112, 'spell_lady_vashj_magic_barrier'), +(38140, 'spell_gen_select_target_count_7_1'), +(38173, 'spell_q10714_on_spirits_wings'), +(38215, 'spell_hydross_mark_of_hydross'), +(38219, 'spell_hydross_mark_of_hydross'), +(38223, 'spell_q10769_dissension_amongst_the_ranks'), +(38224, 'spell_q10769_dissension_amongst_the_ranks'), +(38241, 'spell_gen_select_target_count_7_1'), +(38248, 'spell_gen_select_target_count_7_1'), +(38441, 'spell_gen_50pct_count_pct_from_max_hp'), +(38443, 'spell_sha_totemic_mastery'), +(38451, 'spell_karathress_power_of_caribdis'), +(38462, 'spell_broggok_poison_cloud'), +(38494, 'spell_lady_vashj_summon_sporebat'), +(38573, 'spell_gen_select_target_count_15_1'), +(38573, 'spell_lady_vashj_spore_drop_effect'), +(38629, 'spell_q10720_the_smallest_creature'), +(38633, 'spell_gen_select_target_count_15_1'), +(38650, 'spell_gen_select_target_count_15_1'), +(38724, 'spell_q10838_demoniac_scryer_visual'), +(38776, 'spell_q9718_crow_transform'), +(38795, 'spell_murmur_sonic_boom_effect'), +(39032, 'spell_serpentshrine_cavern_infection'), +(39042, 'spell_serpentshrine_cavern_infection'), +(39044, 'spell_serpentshrine_cavern_serpentshrine_parasite'), +(39053, 'spell_serpentshrine_cavern_serpentshrine_parasite_trigger'), +(39090, 'spell_capacitus_polarity_charge'), +(39093, 'spell_capacitus_polarity_charge'), +(39096, 'spell_capacitus_polarity_shift'), +(39117, 'spell_astromancer_solarian_transform'), +(39166, 'spell_q10898_skywing'), +(39187, 'spell_gruul_ground_slam_trigger'), +(39228, 'spell_gen_absorb0_hitlimit1'), +(39238, 'spell_q10929_fumping'), +(39239, 'spell_q10923_evil_draws_near_summon'), +(39246, 'spell_q10930_big_bone_worm'), +(39256, 'spell_q10923_evil_draws_near_visual'), +(39257, 'spell_q10923_evil_draws_near_visual'), +(39259, 'spell_q10923_evil_draws_near_periodic'), +(39346, 'spell_ragin_flames_inferno'), +(39365, 'spell_murmur_thundering_storm'), +(39371, 'spell_q10935_the_exorcism_of_colonel_jules'), +(39495, 'spell_lady_vashj_remove_tainted_cores'), +(39575, 'spell_black_temple_charge_rage'), +(39610, 'spell_sha_mana_tide_totem'), +(39635, 'spell_illidan_glaive_throw'), +(39645, 'spell_black_temple_shadow_inferno'), +(39672, 'spell_gen_select_target_count_15_1'), +(39832, 'spell_q10985_light_of_the_naaru'), +(39844, 'spell_q11010_q11102_q11023_q11008_check_fly_mount'), +(39848, 'spell_morogrim_tidewalker_water_globule_new_target'), +(39849, 'spell_illidan_glaive_throw'), +(39857, 'spell_illidan_tear_of_azzinoth_summon_channel'), +(39948, 'spell_najentus_hurl_spine'), +(39953, 'spell_gen_adals_song_of_battle'), +(39992, 'spell_najentus_needle_spine'), +(40056, 'spell_q11010_q11102_q11023_choose_loc'), +(40081, 'spell_black_template_free_friend'), +(40084, 'spell_black_template_harpooners_mark'), +(40112, 'spell_q11010_q11102_q11023_aggro_check'), +(40113, 'spell_q11010_q11102_q11023_aggro_check_aura'), +(40119, 'spell_q11010_q11102_q11023_aggro_burst'), +(40121, 'spell_dru_swift_flight_passive'), +(40132, 'spell_gen_summon_earth_elemental'), +(40133, 'spell_gen_summon_fire_elemental'), +(40157, 'spell_teron_gorefiend_spirit_lance'), +(40160, 'spell_q11010_q11102_q11023_q11008_check_fly_mount'), +(40251, 'spell_teron_gorefiend_shadow_of_death'), +(40268, 'spell_teron_gorefiend_spiritual_vengeance'), +(40326, 'spell_teron_gorefiend_shadowy_construct'), +(40398, 'spell_illidan_demon_transform2'), +(40401, 'spell_shade_of_akama_shade_soul_channel'), +(40414, 'spell_gen_fixate'), +(40486, 'spell_gurtogg_eject'), +(40511, 'spell_illidan_demon_transform1'), +(40638, 'spell_item_sleepy_willy'), +(40647, 'spell_illidan_shadow_prison'), +(40760, 'spell_illidan_cage_trap_stun'), +(40761, 'spell_illidan_cage_trap'), +(40802, 'spell_item_mingos_fortune_generator'), +(40816, 'spell_mother_shahraz_saber_lash'), +(40825, 'spell_q11026_a11051_banish_the_demons'), +(40828, 'spell_q11026_a11051_banish_the_demons'), +(40846, 'spell_npc22275_crystal_prison'), +(40851, 'spell_gen_select_target_count_7_1'), +(40854, 'spell_shade_of_akama_akama_soul_expel'), +(40855, 'spell_shade_of_akama_akama_soul_expel'), +(40856, 'spell_q11065_wrangle_some_aether_rays'), +(40862, 'spell_mother_shahraz_beam_periodic'), +(40863, 'spell_mother_shahraz_beam_periodic'), +(40865, 'spell_mother_shahraz_beam_periodic'), +(40866, 'spell_mother_shahraz_beam_periodic'), +(40867, 'spell_mother_shahraz_random_periodic'), +(40869, 'spell_mother_shahraz_fatal_attraction'), +(40870, 'spell_mother_shahraz_fatal_attraction_dummy'), +(40890, 'spell_quest_dragonmaw_race_generic'), +(40892, 'spell_gen_fixate'), +(40894, 'spell_quest_dragonmaw_race_generic'), +(40904, 'spell_illidan_draw_soul'), +(40909, 'spell_quest_dragonmaw_race_generic'), +(40928, 'spell_quest_dragonmaw_race_generic'), +(40930, 'spell_quest_dragonmaw_race_generic'), +(40945, 'spell_quest_dragonmaw_race_generic'), +(41001, 'spell_mother_shahraz_fatal_attraction_aura'), +(41034, 'spell_black_temple_spell_absorption'), +(41054, 'spell_gen_clone_weapon_aura'), +(41055, 'spell_gen_clone_weapon'), +(41072, 'spell_black_temple_bloodbolt'), +(41081, 'spell_gen_select_target_count_15_1'), +(41082, 'spell_illidan_found_target'), +(41126, 'spell_illidan_flame_burst'), +(41170, 'spell_black_temple_curse_of_the_bleakheart'), +(41171, 'spell_black_temple_skeleton_shot'), +(41172, 'spell_gen_select_target_count_24_1'), +(41186, 'spell_black_temple_wyvern_sting'), +(41213, 'spell_gen_throw_shield'), +(41248, 'spell_black_temple_consuming_strikes'), +(41292, 'spell_reliquary_of_souls_aura_of_suffering'), +(41294, 'spell_reliquary_of_souls_fixate'), +(41337, 'spell_reliquary_of_souls_aura_of_anger'), +(41341, 'spell_illidari_council_balance_of_power'), +(41350, 'spell_reliquary_of_souls_aura_of_desire'), +(41351, 'spell_black_temple_curse_of_vitality'), +(41357, 'spell_gen_select_target_count_15_1'), +(41360, 'spell_gen_100pct_count_pct_from_max_hp'), +(41376, 'spell_reliquary_of_souls_spite'), +(41404, 'spell_black_temple_dementia'), +(41467, 'spell_illidari_council_judgement'), +(41475, 'spell_illidari_council_reflective_shield'), +(41480, 'spell_illidari_council_deadly_strike'), +(41499, 'spell_illidari_council_empyreal_balance'), +(41621, 'spell_q11117_catch_the_wild_wolpertinger'), +(41914, 'spell_illidan_parasitic_shadowfiend_trigger'), +(41917, 'spell_illidan_parasitic_shadowfiend'), +(41920, 'spell_brewfest_fill_keg'), +(41921, 'spell_brewfest_unfill_keg'), +(41943, 'spell_brewfest_unfill_keg'), +(41944, 'spell_brewfest_unfill_keg'), +(41945, 'spell_brewfest_unfill_keg'), +(41946, 'spell_brewfest_unfill_keg'), +(42005, 'spell_gurtogg_bloodboil'), +(42074, 'spell_hallows_end_base_fire'), +(42268, 'spell_gen_despawn_self'), +(42300, 'spell_brewfest_add_mug'), +(42339, 'spell_hallows_end_bucket_lands'), +(42393, 'spell_gen_default_count_pct_from_max_hp'), +(42436, 'spell_brewfest_toss_mug'), +(42485, 'spell_ooze_zap_channel_end'), +(42489, 'spell_ooze_zap'), +(42492, 'spell_energize_aoe'), +(42578, 'spell_q11198_take_down_tethyr'), +(42672, 'spell_frost_tomb'), +(42760, 'spell_item_goblin_gumbo_kettle'), +(42783, 'spell_astromancer_wrath_of_the_astromancer'), +(42992, 'spell_brewfest_ram_fatigue'), +(42993, 'spell_brewfest_ram_fatigue'), +(42994, 'spell_brewfest_ram_fatigue'), +(43042, 'spell_item_summon_or_dismiss'), +(43102, 'spell_item_summon_or_dismiss'), +(43263, 'spell_dk_aotd_taunt'), +(43310, 'spell_brewfest_main_ram_buff'), +(43332, 'spell_brewfest_ram_fatigue'), +(43351, 'spell_q11322_q11317_the_cleansing'), +(43416, 'spell_gen_throw_shield'), +(43421, 'spell_hexlord_lifebloom'), +(43450, 'spell_brewfest_apple_trap'), +(43522, 'spell_hexlord_unstable_affliction'), +(43714, 'spell_brewfest_relay_race_force_cast'), +(43723, 'spell_item_demon_broiled_surprise'), +(43874, 'spell_q11396_11399_force_shield_arcane_purple_x3'), +(43882, 'spell_q11396_11399_scourging_crystal_controller_dummy'), +(43907, 'spell_brewfest_reveler_transform'), +(43908, 'spell_brewfest_reveler_transform'), +(43909, 'spell_brewfest_reveler_transform'), +(43910, 'spell_brewfest_reveler_transform'), +(43911, 'spell_brewfest_reveler_transform'), +(43912, 'spell_brewfest_reveler_transform'), +(43913, 'spell_brewfest_reveler_transform'), +(43914, 'spell_brewfest_reveler_transform'), +(43915, 'spell_brewfest_reveler_transform'), +(43916, 'spell_brewfest_reveler_transform'), +(43917, 'spell_brewfest_reveler_transform'), +(44003, 'spell_brewfest_reveler_transform'), +(44004, 'spell_brewfest_reveler_transform'), +(44094, 'spell_brewfest_reveler_transform'), +(44096, 'spell_brewfest_reveler_transform'), +(44198, 'spell_mt_phoenix_burn'), +(44337, 'spell_brewfest_reveler_transform'), +(44338, 'spell_brewfest_reveler_transform'), +(44436, 'spell_hallows_end_tricky_treat'), +(44521, 'spell_gen_bg_preparation'), +(44811, 'spell_kalecgos_spectral_realm_dummy'), +(44869, 'spell_kalecgos_spectral_blast_dummy'), +(44875, 'spell_item_complete_raptor_capture'), +(44935, 'spell_q11520_discovering_your_roots'), +(44936, 'spell_q11515_fel_siphon_dummy'), +(45032, 'spell_kalecgos_curse_of_boundless_agony'), +(45042, 'spell_item_shifting_naaru_silver'), +(45043, 'spell_item_shifting_naaru_silver'), +(45072, 'spell_gen_arcane_charge'), +(45102, 'spell_love_is_in_the_air_romantic_picnic'), +(45141, 'spell_brutallus_burn'), +(45151, 'spell_brutallus_burn'), +(45202, 'spell_item_rocket_chicken'), +(45204, 'spell_gen_clone'), +(45205, 'spell_gen_clone_weapon_aura'), +(45206, 'spell_gen_clone_weapon'), +(45208, 'spell_item_dragon_kite_summon_lightning_bunny'), +(45235, 'spell_eredar_twins_apply_flame_touched'), +(45235, 'spell_eredar_twins_blaze'), +(45246, 'spell_eredar_twins_apply_flame_touched'), +(45248, 'spell_eredar_twins_apply_dark_touched'), +(45253, 'spell_item_dragon_kite_summon_lightning_bunny'), +(45256, 'spell_eredar_twins_apply_dark_touched'), +(45270, 'spell_eredar_twins_apply_dark_touched'), +(45271, 'spell_eredar_twins_apply_dark_touched'), +(45329, 'spell_eredar_twins_apply_dark_touched'), +(45342, 'spell_eredar_twins_apply_flame_touched'), +(45347, 'spell_eredar_twins_handle_touch'), +(45348, 'spell_eredar_twins_handle_touch'), +(45406, 'spell_midsummer_ribbon_pole'), +(45449, 'spell_q11587_arcane_prisoner_rescue'), +(45472, 'spell_gen_parachute'), +(45524, 'spell_dk_chains_of_ice'), +(45625, 'spell_arcane_chains_character_force_cast'), +(45644, 'spell_midsummer_torch_catch'), +(45668, 'spell_q11653_youre_not_so_big_now'), +(45671, 'spell_midsummer_fling_torch'), +(45680, 'spell_gen_select_target_count_7_1'), +(45714, 'spell_felmyst_fog_of_corruption'), +(45716, 'spell_midsummer_torch_quest'), +(45717, 'spell_felmyst_fog_of_corruption_charm'), +(45737, 'spell_kiljaeden_flame_dart'), +(45742, 'spell_q11670_it_was_the_orcs_honest'), +(45759, 'spell_q11670_it_was_the_orcs_honest'), +(45785, 'spell_gen_clone'), +(45785, 'spell_kiljaeden_sinister_reflection_clone'), +(45819, 'spell_midsummer_juggling_torch'), +(45822, 'spell_gen_av_drekthar_presence'), +(45823, 'spell_gen_av_drekthar_presence'), +(45824, 'spell_gen_av_drekthar_presence'), +(45826, 'spell_gen_av_drekthar_presence'), +(45828, 'spell_gen_av_drekthar_presence'), +(45829, 'spell_gen_av_drekthar_presence'), +(45830, 'spell_gen_av_drekthar_presence'), +(45831, 'spell_gen_av_drekthar_presence'), +(45833, 'spell_kiljaeden_power_of_the_blue_flight'), +(45839, 'spell_kiljaeden_vengeance_of_the_blue_flight'), +(45853, 'spell_item_map_of_the_geyser_fields'), +(45856, 'spell_kiljaeden_dragon_breath'), +(45860, 'spell_kiljaeden_dragon_breath'), +(45892, 'spell_kiljaeden_sinister_reflection'), +(45909, 'spell_kiljaeden_armageddon_missile'), +(45921, 'spell_kiljaeden_armageddon_periodic'), +(45976, 'spell_gen_select_target_count_7_1'), +(45996, 'spell_muru_darkness'), +(45997, 'spell_q11719_bloodspore_ruination_45997'), +(46008, 'spell_gen_select_target_count_15_5'), +(46021, 'spell_kalecgos_spectral_realm'), +(46023, 'spell_q11730_ultrasonic_screwdriver'), +(46041, 'spell_muru_summon_blood_elves_periodic'), +(46203, 'spell_item_goblin_weather_machine'), +(46221, 'spell_gen_animal_blood'), +(46230, 'spell_entropius_black_hole_effect'), +(46265, 'spell_entropius_void_zone_visual'), +(46289, 'spell_entropius_negative_energy'), +(46292, 'spell_cataclysm_breath'), +(46337, 'spell_gen_crab_disguise'), +(46394, 'spell_gen_burn_brutallus'), +(46485, 'spell_item_greatmothers_soulcatcher'), +(46584, 'spell_dk_raise_dead'), +(46605, 'spell_kiljaeden_darkness'), +(46610, 'spell_madrigosa_activate_barrier'), +(46619, 'spell_dk_raise_ally_trigger'), +(46620, 'spell_q11919_q11940_drake_hunt'), +(46629, 'spell_gen_disabled_above_73'), +(46630, 'spell_midsummer_torch_quest'), +(46638, 'spell_madrigosa_deactivate_barrier'), +(46642, 'spell_gen_5000_gold'), +(46650, 'spell_felmyst_open_brutallus_back_doors'), +(46680, 'spell_kiljaeden_shadow_spike'), +(46736, 'spell_item_goblin_weather_machine'), +(46738, 'spell_item_goblin_weather_machine'), +(46739, 'spell_item_goblin_weather_machine'), +(46740, 'spell_item_goblin_weather_machine'), +(46747, 'spell_midsummer_fling_torch'), +(46771, 'spell_eredar_twins_apply_flame_touched'), +(47110, 'spell_image_of_drakuru_reagent_check'), +(47130, 'spell_q12014_steady_as_a_rock'), +(47170, 'spell_item_impale_leviroth'), +(47193, 'spell_warl_demonic_empowerment'), +(47336, 'spell_novos_crystal_handler_death'), +(47344, 'spell_request_second_mug'), +(47369, 'spell_send_mug_control_aura'), +(47370, 'spell_send_mug_target_picker'), +(47407, 'spell_direbrew_disarm'), +(47422, 'spell_warl_everlasting_affliction'), +(47496, 'spell_dk_ghoul_explode'), +(47530, 'spell_q12096_q12092_bark'), +(47575, 'spell_q12096_q12092_dummy'), +(47691, 'spell_direbrew_summon_mole_machine_target_picker'), +(47710, 'spell_boss_magus_telestra_summon_telestra_clones'), +(47764, 'spell_boss_magus_telestra_gravity_well'), +(47788, 'spell_pri_guardian_spirit'), +(47911, 'spell_gen_charmed_unit_spell_cooldown'), +(47948, 'spell_pri_pain_and_suffering_proc'), +(47977, 'spell_magic_broom'), +(48018, 'spell_warl_demonic_circle_summon'), +(48020, 'spell_warl_demonic_circle_teleport'), +(48025, 'spell_headless_horseman_mount'), +(48129, 'spell_item_scroll_of_recall'), +(48263, 'spell_dk_presence'), +(48265, 'spell_dk_presence'), +(48266, 'spell_dk_presence'), +(48277, 'spell_svala_ritual_strike'), +(48310, 'spell_transitus_shield_beam'), +(48363, 'spell_q12237_rescue_villager'), +(48388, 'spell_call_wintergarde_gryphon'), +(48391, 'spell_dru_owlkin_frenzy'), +(48397, 'spell_q12237_drop_off_villager'), +(48425, 'spell_gen_select_target_count_7_1'), +(48504, 'spell_dru_living_seed_proc'), +(48522, 'spell_q12243_fire_upon_the_waters'), +(48597, 'spell_dtk_raise_dead'), +(48605, 'spell_dtk_raise_dead'), +(48610, 'spell_shredder_delivery'), +(48620, 'spell_gen_charmed_unit_spell_cooldown'), +(48649, 'spell_item_fetch_ball'), +(48681, 'spell_q12308_escape_from_silverbrook_summon_worgen'), +(48682, 'spell_q12308_escape_from_silverbrook'), +(48707, 'spell_dk_anti_magic_shell_self'), +(48742, 'spell_q12277_wintergarde_mine_explosion'), +(48743, 'spell_dk_death_pact'), +(48762, 'spell_q12274_a_fall_from_grace_costume'), +(48776, 'spell_item_with_mount_speed'), +(48777, 'spell_item_with_mount_speed'), +(48792, 'spell_dk_icebound_fortitude'), +(48812, 'spell_renew_skirmisher'), +(48876, 'spell_utgarde_pinnacle_beast_mark'), +(48917, 'spell_q10041_q10040_who_are_they'), +(48920, 'spell_dred_grievious_bite'), +(49026, 'spell_gen_fixate'), +(49028, 'spell_dk_dancing_rune_weapon'), +(49107, 'spell_vehicle_warhead_fuse'), +(49181, 'spell_warhead_fuse'), +(49206, 'spell_dk_summon_gargoyle'), +(49222, 'spell_dk_bone_shield'), +(49250, 'spell_warhead_detonate'), +(49297, 'spell_winter_veil_racer_rocket_slam'), +(49325, 'spell_winter_veil_racer_slam_hit'), +(49345, 'spell_oculus_call_ruby_emerald_amber_drake'), +(49346, 'spell_oculus_rider_aura'), +(49357, 'spell_item_brewfest_mount_transformation'), +(49380, 'spell_trollgore_consume'), +(49405, 'spell_trollgore_invader_taunt'), +(49427, 'spell_oculus_ride_ruby_emerald_amber_drake_que'), +(49459, 'spell_oculus_ride_ruby_emerald_amber_drake_que'), +(49460, 'spell_oculus_rider_aura'), +(49461, 'spell_oculus_call_ruby_emerald_amber_drake'), +(49462, 'spell_oculus_call_ruby_emerald_amber_drake'), +(49463, 'spell_oculus_ride_ruby_emerald_amber_drake_que'), +(49464, 'spell_oculus_rider_aura'), +(49466, 'spell_item_direbrew_remote'), +(49527, 'spell_tharon_ja_curse_of_life'), +(49551, 'spell_tharon_ja_dummy'), +(49555, 'spell_trollgore_corpse_explode'), +(49560, 'spell_dk_death_grip'), +(49576, 'spell_dk_death_grip'), +(49587, 'spell_q12459_seeds_of_natures_wrath'), +(49592, 'spell_oculus_temporal_rift'), +(49642, 'spell_onslaught_or_call_bone_gryphon'), +(49761, 'spell_wintergrasp_rp_gg'), +(49817, 'spell_q12478_frostmourne_cavern'), +(49838, 'spell_oculus_stop_time'), +(49840, 'spell_oculus_shock_lance'), +(49882, 'spell_gen_default_count_pct_from_max_hp'), +(49889, 'spell_gen_clone'), +(49960, 'spell_dtk_summon_random_drakkari'), +(50133, 'spell_q11396_11399_scourging_crystal_controller'), +(50180, 'spell_item_draenic_pale_ale'), +(50218, 'spell_gen_clone'), +(50240, 'spell_oculus_evasive_maneuvers'), +(50241, 'spell_oculus_evasive_charges'), +(50243, 'spell_item_teach_language'), +(50278, 'spell_barreled_control_aura'), +(50325, 'spell_oculus_soar'), +(50334, 'spell_dru_berserk'), +(50341, 'spell_oculus_touch_the_nightmare'), +(50344, 'spell_oculus_dream_funnel'), +(50419, 'spell_dru_brambles_treant'), +(50421, 'spell_dk_scent_of_blood'), +(50452, 'spell_dk_bloodworms'), +(50453, 'spell_dk_blood_gorged'), +(50461, 'spell_dk_anti_magic_zone'), +(50462, 'spell_dk_anti_magic_shell_raid'), +(50526, 'spell_dk_wandering_plague'), +(50546, 'spell_q12066_bunny_kill_credit'), +(50630, 'spell_gen_eject_all_passengers'), +(50720, 'spell_warr_vigilance'), +(50725, 'spell_warr_vigilance_trigger'), +(50810, 'spell_krystallus_shatter'), +(50811, 'spell_krystallus_shatter_effect'), +(50842, 'spell_dk_pestilence'), +(50999, 'spell_wg_reduce_damage_by_distance'), +(51001, 'spell_hos_dark_matter'), +(51060, 'spell_gen_have_item_auras'), +(51068, 'spell_gen_have_item_auras'), +(51088, 'spell_gen_have_item_auras'), +(51094, 'spell_gen_have_item_auras'), +(51186, 'spell_item_summon_or_dismiss'), +(51188, 'spell_item_summon_or_dismiss'), +(51189, 'spell_item_summon_or_dismiss'), +(51190, 'spell_item_summon_or_dismiss'), +(51191, 'spell_item_summon_or_dismiss'), +(51192, 'spell_item_summon_or_dismiss'), +(51209, 'spell_dk_hungering_cold'), +(51211, 'spell_rog_blade_flurry'), +(51330, 'spell_q12589_shoot_rjr'), +(51403, 'spell_novos_despawn_crystal_handler'), +(51422, 'spell_wg_reduce_damage_by_distance'), +(51519, 'spell_death_knight_initiate_visual'), +(51582, 'spell_item_rocket_boots'), +(51592, 'spell_gen_despawn_self'), +(51640, 'spell_the_flag_of_ownership'), +(51690, 'spell_rog_killing_spree'), +(51719, 'spell_gen_clone'), +(51748, 'spell_gen_charmed_unit_spell_cooldown'), +(51752, 'spell_gen_charmed_unit_spell_cooldown'), +(51756, 'spell_gen_charmed_unit_spell_cooldown'), +(51769, 'spell_q12619_emblazon_runeblade'), +(51770, 'spell_q12619_emblazon_runeblade_effect'), +(51840, 'spell_q12634_despawn_fruit_tosser'), +(51854, 'spell_q12611_deathbolt'), +(51858, 'spell_q12641_death_comes_from_on_high'), +(51904, 'spell_q12641_death_comes_from_on_high_summon_ghouls'), +(51910, 'spell_gen_despawn_self'), +(51957, 'spell_q12620_the_lifewarden_wrath'), +(51961, 'spell_item_chicken_cover'), +(51963, 'spell_pet_dk_gargoyle_strike'), +(51996, 'spell_dk_pet_scaling'), +(52031, 'spell_sha_mana_spring_totem'), +(52033, 'spell_sha_mana_spring_totem'), +(52034, 'spell_sha_mana_spring_totem'), +(52035, 'spell_sha_mana_spring_totem'), +(52036, 'spell_sha_mana_spring_totem'), +(52041, 'spell_sha_healing_stream_totem'), +(52046, 'spell_sha_healing_stream_totem'), +(52047, 'spell_sha_healing_stream_totem'), +(52048, 'spell_sha_healing_stream_totem'), +(52049, 'spell_sha_healing_stream_totem'), +(52050, 'spell_sha_healing_stream_totem'), +(52086, 'spell_azjol_nerub_web_wrap'), +(52090, 'spell_q12659_ahunaes_knife'), +(52107, 'spell_wintergrasp_hide_small_elementals'), +(52143, 'spell_dk_master_of_ghouls'), +(52160, 'spell_shango_tracks'), +(52163, 'spell_shango_tracks'), +(52212, 'spell_dk_death_and_decay'), +(52249, 'spell_gen_visual_dummy_stun'), +(52267, 'spell_gen_despawn_self'), +(52278, 'spell_gen_visual_dummy_stun'), +(52308, 'spell_q12683_take_sputum_sample'), +(52375, 'spell_dk_death_coil'), +(52408, 'spell_gen_seaforium_blast'), +(52417, 'spell_item_massive_seaforium_charge'), +(52438, 'spell_gen_select_target_count_7_1'), +(52449, 'spell_gen_select_target_count_7_1'), +(52479, 'spell_q12698_the_gift_that_keeps_on_giving'), +(52481, 'spell_item_gift_of_the_harvester'), +(52510, 'spell_q12690_burst_at_the_seams'), +(52536, 'spell_azjol_nerub_fixate'), +(52551, 'spell_tur_ragepaw_lifebloom'), +(52610, 'spell_dru_savage_roar'), +(52708, 'spell_boss_salramm_steal_flesh'), +(52751, 'spell_dk_death_gate'), +(52759, 'spell_sha_ancestral_awakening_proc'), +(52845, 'spell_item_brewfest_mount_transformation'), +(52862, 'spell_q12726_song_of_wind_and_water'), +(52864, 'spell_q12726_song_of_wind_and_water'), +(52941, 'spell_q12735_song_of_cleansing'), +(52942, 'spell_loken_pulsing_shockwave'), +(53030, 'spell_hadronox_leech_poison'), +(53032, 'spell_gen_flurry_of_claws'), +(53035, 'spell_hadronox_summon_periodic_champion'), +(53036, 'spell_hadronox_summon_periodic_necromancer'), +(53037, 'spell_hadronox_summon_periodic_crypt_fiend'), +(53094, 'spell_infected_worgen_bite'), +(53110, 'spell_q12779_an_end_to_all_things'), +(53160, 'spell_dk_dancing_rune_weapon_visual'), +(53209, 'spell_hun_chimera_shot'), +(53242, 'spell_tharon_ja_clear_gift_of_tharon_ja'), +(53271, 'spell_hun_masters_call'), +(53350, 'spell_q12730_quenching_mist'), +(53365, 'spell_dk_rune_of_the_fallen_crusader'), +(53385, 'spell_pal_divine_storm'), +(53407, 'spell_pal_judgement_of_justice'), +(53408, 'spell_pal_judgement_of_wisdom'), +(53412, 'spell_hun_invigoration'), +(53457, 'spell_gen_select_target_count_15_1'), +(53458, 'spell_azjol_nerub_impale_summon'), +(53472, 'spell_azjol_nerub_pound'), +(53475, 'spell_gen_oracle_wolvar_reputation'), +(53478, 'spell_hun_last_stand_pet'), +(53487, 'spell_gen_oracle_wolvar_reputation'), +(53520, 'spell_azjol_nerub_carrion_beetels'), +(53601, 'spell_pal_sacred_shield_base'), +(53608, 'spell_cenarion_scout_lifebloom'), +(53642, 'spell_gen_area_aura_select_players'), +(53658, 'spell_chapter5_light_of_dawn_aura'), +(53680, 'spell_chapter5_rebuke'), +(53750, 'spell_item_crazy_alchemists_potion'), +(53768, 'spell_gen_haunted'), +(53797, 'spell_oculus_drake_flag'), +(53798, 'spell_azjol_nerub_fixate'), +(53808, 'spell_item_pygmy_oil'), +(54015, 'spell_gen_oracle_wolvar_reputation'), +(54044, 'spell_hun_pet_carrion_feeder'), +(54171, 'spell_pal_divine_storm_dummy'), +(54190, 'spell_q12805_lifeblood_dummy'), +(54307, 'spell_item_summon_argent_knight'), +(54355, 'spell_gen_mine_sweeper'), +(54363, 'spell_grobbulus_poison'), +(54396, 'spell_optic_link'), +(54420, 'spell_deliver_gryphon'), +(54426, 'spell_gluth_decimate'), +(54566, 'spell_dk_pet_scaling'), +(54646, 'spell_mage_focus_magic'), +(54729, 'spell_winged_steed_of_the_ebon_blade'), +(54732, 'spell_item_gnomish_army_knife'), +(54747, 'spell_mage_burning_determination'), +(54749, 'spell_mage_burning_determination'), +(54798, 'spell_q12851_going_bearback'), +(54801, 'spell_drakkari_colossus_surge'), +(54846, 'spell_dru_glyph_of_starfire'), +(54847, 'spell_gen_select_target_count_15_2'), +(54850, 'spell_drakkari_colossus_emerge'), +(54894, 'spell_gen_visual_dummy_stun'), +(54956, 'spell_galdarah_impaling_charge'), +(54968, 'spell_pal_glyph_of_holy_light'), +(54991, 'spell_drakkari_colossus_face_me'), +(54996, 'spell_gen_charmed_unit_spell_cooldown'), +(54997, 'spell_gen_charmed_unit_spell_cooldown'), +(55004, 'spell_item_nitro_boots'), +(55093, 'spell_sladran_grip_of_sladran'), +(55163, 'spell_moorabi_mojo_frenzy'), +(55233, 'spell_dk_vampiric_blood'), +(55269, 'spell_gen_default_count_pct_from_max_hp'), +(55299, 'spell_galdarah_transform'), +(55342, 'spell_mage_mirror_image'), +(55368, 'spell_q12661_q12669_q12676_q12677_q12713_summon_stefan'), +(55421, 'spell_q12919_gymers_throw'), +(55475, 'spell_gen_grow_flower_patch'), +(55516, 'spell_q12919_gymers_grab'), +(55638, 'spell_gothik_shadow_bolt_volley'), +(55640, 'spell_gen_allow_proc_from_spells_with_cost'), +(55680, 'spell_pri_glyph_of_prayer_of_healing'), +(55693, 'spell_q12823_remove_collapsing_cave_aura'), +(55709, 'spell_hun_pet_heart_of_the_phoenix'), +(55804, 'spell_q12937_relief_for_the_fallen'), +(55895, 'spell_prince_taldaram_flame_sphere_summon'), +(55931, 'spell_prince_taldaram_conjure_flame_sphere'), +(55945, 'spell_gen_spectator_cheer_trigger'), +(56096, 'spell_gen_vendor_bark_trigger'), +(56150, 'spell_jedoga_sacrafice_beam'), +(56159, 'spell_ahn_kahet_swarmer_aura'), +(56246, 'spell_warl_glyph_of_felguard'), +(56278, 'spell_q12987_read_pronouncement'), +(56328, 'spell_random_lightning_visual_effect'), +(56504, 'spell_q13007_iron_colossus'), +(56508, 'spell_q13007_iron_colossus'), +(56513, 'spell_gen_charmed_unit_spell_cooldown'), +(56524, 'spell_gen_charmed_unit_spell_cooldown'), +(56565, 'spell_q13011_bear_flank_master'), +(56575, 'spell_wintergrasp_create_vehicle'), +(56578, 'spell_gen_default_count_pct_from_max_hp'), +(56659, 'spell_wintergrasp_force_building'), +(56661, 'spell_wintergrasp_create_vehicle'), +(56662, 'spell_wintergrasp_force_building'), +(56663, 'spell_wintergrasp_create_vehicle'), +(56664, 'spell_wintergrasp_force_building'), +(56689, 'spell_q13003_thursting_hodirs_spear'), +(56698, 'spell_gen_default_count_pct_from_max_hp'), +(56702, 'spell_shadow_sickle_periodic_damage'), +(56763, 'spell_close_rift'), +(56841, 'spell_hun_glyph_of_arcane_shot'), +(57099, 'spell_gen_mine_sweeper'), +(57283, 'spell_amanitar_remove_mushroom_power'), +(57301, 'spell_item_feast'), +(57385, 'spell_q13086_last_line_of_defence'), +(57407, 'spell_eoe_ph3_surge_of_power'), +(57412, 'spell_q13086_last_line_of_defence'), +(57426, 'spell_item_feast'), +(57496, 'spell_herald_volzaj_insanity'), +(57528, 'spell_gen_clone'), +(57578, 'spell_sartharion_lava_strike'), +(57591, 'spell_sartharion_lava_strike'), +(57593, 'spell_gen_clone_weapon'), +(57594, 'spell_gen_clone_weapon_aura'), +(57607, 'spell_wg_reduce_damage_by_distance'), +(57610, 'spell_wg_reduce_damage_by_distance'), +(57669, 'spell_gen_replenishment'), +(57685, 'spell_gen_creature_permanent_feign_death'), +(57762, 'spell_twisted_visage_lifebloom'), +(57934, 'spell_rog_tricks_of_the_trade'), +(58040, 'spell_destroy_door_seal'), +(58387, 'spell_warr_glyph_of_sunder_armor'), +(58465, 'spell_item_feast'), +(58474, 'spell_item_feast'), +(58601, 'spell_gen_remove_flight_auras'), +(58622, 'spell_wintergrasp_portal'), +(58683, 'spell_rog_savage_combat'), +(58684, 'spell_rog_savage_combat'), +(58759, 'spell_sha_healing_stream_totem'), +(58760, 'spell_sha_healing_stream_totem'), +(58761, 'spell_sha_healing_stream_totem'), +(58778, 'spell_sha_mana_spring_totem'), +(58779, 'spell_sha_mana_spring_totem'), +(58780, 'spell_sha_mana_spring_totem'), +(58875, 'spell_sha_spirit_walk'), +(58886, 'spell_magic_eater_food'), +(58941, 'spell_archavon_rock_shards'), +(58951, 'spell_gen_creature_permanent_feign_death'), +(58983, 'spell_big_blizzard_bear'), +(59061, 'spell_charge_shield_bomber'), +(59065, 'spell_q13369_fate_up_against_your_will'), +(59088, 'spell_warr_improved_spell_reflection'), +(59089, 'spell_warr_improved_spell_reflection'), +(59102, 'spell_gen_default_count_pct_from_max_hp'), +(59103, 'spell_shadow_sickle_periodic_damage'), +(59134, 'spell_dk_death_coil'), +(59193, 'spell_switch_infragreen_bomber_station'), +(59194, 'spell_switch_infragreen_bomber_station'), +(59196, 'spell_switch_infragreen_bomber_station'), +(59237, 'spell_utgarde_pinnacle_beast_mark'), +(59288, 'spell_charge_shield_bomber'), +(59303, 'spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon'), +(59317, 'spell_gen_teleporting'), +(59318, 'spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy'), +(59416, 'spell_dred_raptor_call'), +(59417, 'spell_hadronox_leech_poison'), +(59433, 'spell_azjol_nerub_pound'), +(59452, 'spell_gen_select_target_count_15_2'), +(59511, 'spell_prince_taldaram_flame_sphere_summon'), +(59512, 'spell_prince_taldaram_flame_sphere_summon'), +(59542, 'spell_gen_gift_of_naaru'), +(59543, 'spell_gen_gift_of_naaru'), +(59544, 'spell_gen_gift_of_naaru'), +(59545, 'spell_gen_gift_of_naaru'), +(59547, 'spell_gen_gift_of_naaru'), +(59548, 'spell_gen_gift_of_naaru'), +(59566, 'spell_sha_earthen_power'), +(59622, 'spell_anti_air_rocket_bomber'), +(59628, 'spell_rog_tricks_of_the_trade_proc'), +(59630, 'spell_gen_black_magic_enchant'), +(59640, 'spell_item_underbelly_elixir'), +(59643, 'spell_q13280_13283_plant_battle_standard'), +(59686, 'spell_ticking_time_bomb'), +(59725, 'spell_warr_improved_spell_reflection_trigger'), +(59754, 'spell_dk_rune_tap_party'), +(59789, 'spell_item_oracle_ablutions'), +(59803, 'spell_trollgore_consume'), +(59807, 'spell_trollgore_corpse_explode'), +(59827, 'spell_galdarah_impaling_charge'), +(59837, 'spell_loken_pulsing_shockwave'), +(59910, 'spell_novos_summon_minions'), +(59917, 'spell_gen_disabled_above_70'), +(59972, 'spell_tharon_ja_curse_of_life'), +(59990, 'spell_twisted_visage_lifebloom'), +(60103, 'spell_sha_lava_lash'), +(60123, 'spell_pri_lightwell'), +(60144, 'spell_hun_viper_attack_speed'), +(60218, 'spell_gen_absorb0_hitlimit1'), +(60291, 'spell_volazj_whisper'), +(60292, 'spell_volazj_whisper'), +(60293, 'spell_volazj_whisper'), +(60294, 'spell_volazj_whisper'), +(60295, 'spell_volazj_whisper'), +(60296, 'spell_volazj_whisper'), +(60297, 'spell_volazj_whisper'), +(60320, 'spell_item_scroll_of_recall'), +(60321, 'spell_item_scroll_of_recall'), +(60476, 'spell_item_titanium_seal_of_dalaran'), +(60532, 'spell_gen_default_count_pct_from_max_hp'), +(60535, 'spell_item_light_lamp'), +(60779, 'spell_dru_idol_lifebloom'), +(60864, 'spell_gen_default_count_pct_from_max_hp'), +(60893, 'spell_gen_profession_research'), +(60900, 'spell_q13369_fate_up_against_your_will'), +(60936, 'spell_eoe_ph3_surge_of_power'), +(61013, 'spell_pet_hit_expertise_scalling'), +(61017, 'spell_pet_hit_expertise_scalling'), +(61093, 'spell_fight_fire_bomber'), +(61122, 'spell_item_branns_communicator'), +(61123, 'spell_blight_worm_ingest'), +(61177, 'spell_gen_profession_research'), +(61288, 'spell_gen_profession_research'), +(61336, 'spell_dru_survival_instincts'), +(61408, 'spell_wintergrasp_create_vehicle'), +(61409, 'spell_wintergrasp_force_building'), +(61546, 'spell_krystallus_shatter'), +(61547, 'spell_krystallus_shatter_effect'), +(61551, 'spell_item_toy_train_set'), +(61669, 'spell_hun_aspect_of_the_beast'), +(61678, 'spell_z_check'), +(61697, 'spell_dk_pet_scaling'), +(61698, 'spell_gen_ds_flush_knockback'), +(61756, 'spell_gen_profession_research'), +(61782, 'spell_gen_replenishment'), +(61783, 'spell_sha_feral_spirit_scaling'), +(61784, 'spell_pilgrims_bounty_feast_on_generic'), +(61785, 'spell_pilgrims_bounty_feast_on_generic'), +(61786, 'spell_pilgrims_bounty_feast_on_generic'), +(61787, 'spell_pilgrims_bounty_feast_on_generic'), +(61788, 'spell_pilgrims_bounty_feast_on_generic'), +(61804, 'spell_pilgrims_bounty_serve_generic'), +(61805, 'spell_pilgrims_bounty_serve_generic'), +(61806, 'spell_pilgrims_bounty_serve_generic'), +(61807, 'spell_pilgrims_bounty_serve_generic'), +(61808, 'spell_pilgrims_bounty_serve_generic'), +(61889, 'spell_assembly_meltdown'), +(61968, 'spell_hodir_flash_freeze'), +(61999, 'spell_dk_raise_ally'), +(62014, 'spell_pilgrims_bounty_turkey_tracker'), +(62018, 'spell_algalon_collapse'), +(62019, 'spell_assembly_rune_of_summoning'), +(62038, 'spell_hodir_biting_cold_main_aura'), +(62039, 'spell_hodir_biting_cold_player_aura'), +(62056, 'spell_ulduar_stone_grip'), +(62166, 'spell_ulduar_stone_grip_cast_target'), +(62266, 'spell_algalon_trigger_3_adds'), +(62274, 'spell_shield_of_runes'), +(62292, 'spell_tar_blaze'), +(62309, 'spell_demolisher_ride_vehicle'), +(62311, 'spell_algalon_cosmic_smash_damage'), +(62324, 'spell_vehicle_throw_passenger'), +(62331, 'spell_thorim_trash_impale'), +(62374, 'spell_pursue'), +(62399, 'spell_vehicle_circuit_overload'), +(62418, 'spell_thorim_trash_impale'), +(62475, 'spell_systems_shutdown'), +(62482, 'spell_vehicle_grab_pyrite'), +(62501, 'spell_hodir_shatter_chest'), +(62539, 'spell_gen_eject_passenger'), +(62546, 'spell_ignis_scorch'), +(62552, 'spell_gen_defend'), +(62563, 'spell_gen_mounted_charge'), +(62571, 'spell_item_enchanted_broom_periodic'), +(62575, 'spell_gen_break_shield'), +(62594, 'spell_gen_tournament_pennant'), +(62595, 'spell_gen_tournament_pennant'), +(62596, 'spell_gen_tournament_pennant'), +(62606, 'spell_dru_savage_defense'), +(62626, 'spell_gen_break_shield'), +(62692, 'spell_aura_of_despair'), +(62705, 'spell_auto_repair'), +(62707, 'spell_ignis_grab_initial'), +(62709, 'spell_gen_tournament_counterattack'), +(62717, 'spell_ignis_slag_pot'), +(62719, 'spell_gen_defend'), +(62774, 'spell_gen_summon_tournament_mount'), +(62775, 'spell_xt002_tympanic_tantrum'), +(62779, 'spell_gen_summon_tournament_mount'), +(62780, 'spell_gen_summon_tournament_mount'), +(62781, 'spell_gen_summon_tournament_mount'), +(62782, 'spell_gen_summon_tournament_mount'), +(62783, 'spell_gen_summon_tournament_mount'), +(62784, 'spell_gen_summon_tournament_mount'), +(62785, 'spell_gen_summon_tournament_mount'), +(62786, 'spell_gen_summon_tournament_mount'), +(62787, 'spell_gen_summon_tournament_mount'), +(62807, 'spell_hodir_starlight'), +(62821, 'spell_hodir_toasty_fire'), +(62863, 'spell_gen_tournament_duel'), +(62874, 'spell_gen_mounted_charge'), +(62912, 'spell_thorims_hammer'), +(62960, 'spell_gen_mounted_charge'), +(62976, 'spell_thorim_lightning_pillar_P2'), +(62991, 'spell_gen_bonked'), +(63003, 'spell_gen_mounted_charge'), +(63010, 'spell_gen_mounted_charge'), +(63018, 'spell_xt002_searing_light_spawn_life_spark'), +(63024, 'spell_xt002_gravity_bomb_aura'), +(63025, 'spell_xt002_gravity_bomb_damage'), +(63034, 'spell_gen_on_tournament_mount'), +(63108, 'spell_warl_siphon_life'), +(63120, 'spell_yogg_saron_insane'), +(63233, 'spell_gen_break_shield'), +(63274, 'spell_mimiron_p3wx2_laser_barrage'), +(63276, 'spell_mark_of_the_faceless_periodic'), +(63278, 'spell_mark_of_the_faceless_drainhealth'), +(63305, 'spell_yogg_saron_grim_reprisal'), +(63310, 'spell_warl_glyph_of_shadowflame'), +(63322, 'spell_saronite_vapors_dummy'), +(63338, 'spell_saronite_vapors_damage'), +(63382, 'spell_mimiron_rapid_burst'), +(63394, 'spell_gen_tournament_pennant'), +(63395, 'spell_gen_tournament_pennant'), +(63396, 'spell_gen_tournament_pennant'), +(63397, 'spell_gen_tournament_pennant'), +(63398, 'spell_gen_tournament_pennant'), +(63399, 'spell_gen_tournament_pennant'), +(63401, 'spell_gen_tournament_pennant'), +(63402, 'spell_gen_tournament_pennant'), +(63403, 'spell_gen_tournament_pennant'), +(63404, 'spell_gen_tournament_pennant'), +(63405, 'spell_gen_tournament_pennant'), +(63406, 'spell_gen_tournament_pennant'), +(63416, 'spell_gen_clone_weapon'), +(63418, 'spell_gen_clone_weapon_aura'), +(63421, 'spell_gen_tournament_pennant'), +(63422, 'spell_gen_tournament_pennant'), +(63423, 'spell_gen_tournament_pennant'), +(63425, 'spell_gen_tournament_pennant'), +(63426, 'spell_gen_tournament_pennant'), +(63427, 'spell_gen_tournament_pennant'), +(63428, 'spell_gen_tournament_pennant'), +(63429, 'spell_gen_tournament_pennant'), +(63430, 'spell_gen_tournament_pennant'), +(63431, 'spell_gen_tournament_pennant'), +(63432, 'spell_gen_tournament_pennant'), +(63433, 'spell_gen_tournament_pennant'), +(63434, 'spell_gen_tournament_pennant'), +(63435, 'spell_gen_tournament_pennant'), +(63436, 'spell_gen_tournament_pennant'), +(63474, 'spell_ignis_scorch'), +(63477, 'spell_ignis_slag_pot'), +(63489, 'spell_shield_of_runes'), +(63500, 'spell_gen_tournament_pennant'), +(63501, 'spell_gen_tournament_pennant'), +(63521, 'spell_pal_guarded_by_the_light'), +(63545, 'spell_hodir_periodic_icicle'), +(63606, 'spell_gen_tournament_pennant'), +(63607, 'spell_gen_tournament_pennant'), +(63608, 'spell_gen_tournament_pennant'), +(63609, 'spell_gen_tournament_pennant'), +(63611, 'spell_dk_improved_blood_presence_proc'), +(63661, 'spell_gen_mounted_charge'), +(63663, 'spell_gen_summon_tournament_mount'), +(63711, 'spell_hodir_storm_power'), +(63716, 'spell_kologarn_stone_shout'), +(63720, 'spell_kologarn_stone_shout'), +(63744, 'spell_yogg_saron_target_selectors'), +(63745, 'spell_yogg_saron_target_selectors'), +(63747, 'spell_yogg_saron_target_selectors'), +(63791, 'spell_gen_summon_tournament_mount'), +(63792, 'spell_gen_summon_tournament_mount'), +(63795, 'spell_yogg_saron_sanity_reduce'), +(63802, 'spell_yogg_saron_brain_link'), +(63803, 'spell_yogg_saron_sanity_reduce'), +(63825, 'spell_gen_break_shield'), +(63830, 'spell_yogg_saron_malady_of_the_mind'), +(63830, 'spell_yogg_saron_sanity_reduce'), +(63845, 'spell_gen_create_lance'), +(63881, 'spell_yogg_saron_malady_of_the_mind'), +(63881, 'spell_yogg_saron_sanity_reduce'), +(63944, 'spell_gen_damage_reduction_aura'), +(63981, 'spell_ulduar_stone_grip_cast_target'), +(63985, 'spell_ulduar_stone_grip'), +(64004, 'spell_kologarn_stone_shout'), +(64005, 'spell_kologarn_stone_shout'), +(64059, 'spell_yogg_saron_sanity_reduce'), +(64142, 'spell_gen_upper_deck_create_foam_sword'), +(64161, 'spell_yogg_saron_empowered'), +(64164, 'spell_yogg_saron_lunatic_gaze'), +(64164, 'spell_yogg_saron_sanity_reduce'), +(64168, 'spell_yogg_saron_lunatic_gaze'), +(64168, 'spell_yogg_saron_sanity_reduce'), +(64169, 'spell_yogg_saron_sanity_well'), +(64172, 'spell_yogg_saron_titanic_storm'), +(64174, 'spell_yogg_saron_protective_gaze'), +(64184, 'spell_yogg_saron_in_the_maws_of_the_old_god'), +(64205, 'spell_pal_divine_sacrifice'), +(64217, 'spell_voa_overcharge'), +(64233, 'spell_xt002_gravity_bomb_damage'), +(64234, 'spell_xt002_gravity_bomb_aura'), +(64323, 'spell_item_book_of_glyph_mastery'), +(64342, 'spell_gen_break_shield'), +(64380, 'spell_warr_shattering_throw'), +(64385, 'spell_item_unusual_compass'), +(64392, 'spell_auriaya_sentinel_blast'), +(64411, 'spell_item_blessing_of_ancient_kings'), +(64412, 'spell_algalon_phase_punch'), +(64414, 'spell_load_into_catapult'), +(64415, 'spell_item_valanyr_hammer_of_ancient_kings'), +(64440, 'spell_gen_blade_warding'), +(64440, 'spell_gen_proc_above_75'), +(64440, 'spell_item_blade_ward_enchant'), +(64443, 'spell_algalon_big_bang'), +(64445, 'spell_algalon_remove_phase'), +(64465, 'spell_yogg_saron_shadow_beacon'), +(64467, 'spell_yogg_saron_empowering_shadows'), +(64482, 'spell_orbital_supports'), +(64507, 'spell_gen_break_shield'), +(64555, 'spell_yogg_saron_insane_periodic_trigger'), +(64568, 'spell_gen_proc_above_75'), +(64568, 'spell_item_blood_draining_enchant'), +(64584, 'spell_algalon_big_bang'), +(64590, 'spell_gen_break_shield'), +(64591, 'spell_gen_mounted_charge'), +(64595, 'spell_gen_break_shield'), +(64596, 'spell_algalon_cosmic_smash_damage'), +(64614, 'spell_gen_eject_passenger'), +(64629, 'spell_gen_eject_passenger'), +(64630, 'spell_gen_eject_passenger'), +(64631, 'spell_gen_eject_passenger'), +(64632, 'spell_gen_eject_passenger'), +(64633, 'spell_gen_eject_passenger'), +(64634, 'spell_gen_eject_passenger'), +(64635, 'spell_gen_eject_passenger'), +(64636, 'spell_gen_eject_passenger'), +(64677, 'spell_shield_generator'), +(64679, 'spell_auriaya_sentinel_blast'), +(64686, 'spell_gen_break_shield'), +(64702, 'spell_ulduar_squeezed_lifeless'), +(64740, 'spell_ulduar_energy_sap'), +(64770, 'spell_ulduar_arachnopod_damaged'), +(64844, 'spell_pri_divine_hymn'), +(64876, 'spell_ulduar_energy_sap'), +(64904, 'spell_pri_hymn_of_hope'), +(64981, 'spell_item_vanquished_clutches'), +(65075, 'spell_orbital_supports'), +(65076, 'spell_orbital_supports'), +(65077, 'spell_orbital_supports'), +(65121, 'spell_xt002_searing_light_spawn_life_spark'), +(65123, 'spell_hodir_storm_cloud'), +(65133, 'spell_hodir_storm_cloud'), +(65134, 'spell_hodir_storm_power'), +(65147, 'spell_gen_break_shield'), +(65206, 'spell_yogg_saron_destabilization_matrix'), +(65225, 'spell_sha_fire_elemental_scaling'), +(65226, 'spell_sha_fire_elemental_scaling'), +(65227, 'spell_sha_fire_elemental_scaling'), +(65228, 'spell_sha_fire_elemental_scaling'), +(65266, 'spell_gen_vehicle_scaling'), +(65279, 'spell_voa_lightning_nova'), +(65301, 'spell_yogg_saron_sanity_reduce'), +(65311, 'spell_algalon_supermassive_fail'), +(65418, 'spell_pilgrims_bounty_food'), +(65419, 'spell_pilgrims_bounty_food'), +(65420, 'spell_pilgrims_bounty_food'), +(65421, 'spell_pilgrims_bounty_food'), +(65422, 'spell_pilgrims_bounty_food'), +(65576, 'spell_winter_veil_shoot_air_rifle'), +(65635, 'spell_gen_vehicle_scaling'), +(65636, 'spell_gen_vehicle_scaling'), +(65684, 'spell_valkyr_essence'), +(65686, 'spell_valkyr_essence'), +(65812, 'spell_faction_champion_warl_unstable_affliction'), +(65920, 'spell_pursuing_spikes'), +(65922, 'spell_pursuing_spikes'), +(65923, 'spell_pursuing_spikes'), +(65941, 'spell_warr_shattering_throw'), +(65950, 'spell_valkyr_touch'), +(65956, 'spell_rog_blade_flurry'), +(66001, 'spell_valkyr_touch'), +(66041, 'spell_pilgrims_bounty_food'), +(66093, 'spell_faction_champion_dru_lifebloom'), +(66118, 'spell_gen_leeching_swarm'), +(66218, 'spell_ioc_launch'), +(66240, 'spell_gen_leeching_swarm_dmg'), +(66250, 'spell_pilgrims_bounty_pass_generic'), +(66259, 'spell_pilgrims_bounty_pass_generic'), +(66260, 'spell_pilgrims_bounty_pass_generic'), +(66261, 'spell_pilgrims_bounty_pass_generic'), +(66262, 'spell_pilgrims_bounty_pass_generic'), +(66316, 'spell_gen_50pct_count_pct_from_max_hp'), +(66334, 'spell_toc25_mistress_kiss'), +(66336, 'spell_mistress_kiss_area'), +(66477, 'spell_pilgrims_bounty_food'), +(66480, 'spell_gen_break_shield'), +(66481, 'spell_gen_mounted_charge'), +(66482, 'spell_gen_defend'), +(66515, 'spell_reflective_shield'), +(66630, 'spell_ioc_gunship_portal'), +(66637, 'spell_ioc_gunship_portal'), +(66656, 'spell_ioc_parachute_ic'), +(66666, 'spell_gen_vehicle_scaling'), +(66667, 'spell_gen_vehicle_scaling'), +(66668, 'spell_gen_vehicle_scaling'), +(66672, 'spell_ioc_bomb_blast_criteria'), +(66676, 'spell_ioc_bomb_blast_criteria'), +(66690, 'spell_voa_flaming_cinder'), +(66725, 'spell_koralon_meteor_fists'), +(66741, 'spell_q14112_14145_chum_the_water'), +(66808, 'spell_flame_warder_meteor_fists'), +(66862, 'spell_eadric_radiance'), +(67019, 'spell_item_flask_of_the_north'), +(67076, 'spell_mistress_kiss_area'), +(67077, 'spell_mistress_kiss_area'), +(67078, 'spell_mistress_kiss_area'), +(67100, 'spell_gen_50pct_count_pct_from_max_hp'), +(67101, 'spell_gen_50pct_count_pct_from_max_hp'), +(67102, 'spell_gen_50pct_count_pct_from_max_hp'), +(67176, 'spell_valkyr_essence'), +(67177, 'spell_valkyr_essence'), +(67178, 'spell_valkyr_essence'), +(67197, 'spell_toc5_light_rain'), +(67222, 'spell_valkyr_essence'), +(67223, 'spell_valkyr_essence'), +(67224, 'spell_valkyr_essence'), +(67281, 'spell_valkyr_touch'), +(67282, 'spell_valkyr_touch'), +(67283, 'spell_valkyr_touch'), +(67292, 'spell_toc5_light_rain'), +(67296, 'spell_valkyr_touch'), +(67297, 'spell_valkyr_touch'), +(67298, 'spell_valkyr_touch'), +(67335, 'spell_igb_gunship_fall_teleport'), +(67393, 'spell_gen_eject_passenger'), +(67489, 'spell_item_runic_healing_injector'), +(67533, 'spell_winter_veil_shoot_air_rifle'), +(67630, 'spell_gen_leeching_swarm'), +(67681, 'spell_eadric_radiance'), +(67698, 'spell_gen_allow_proc_from_spells_with_cost'), +(67752, 'spell_gen_allow_proc_from_spells_with_cost'), +(67799, 'spell_item_mind_amplify_dish'), +(67905, 'spell_toc25_mistress_kiss'), +(67906, 'spell_toc25_mistress_kiss'), +(67907, 'spell_toc25_mistress_kiss'), +(67957, 'spell_faction_champion_dru_lifebloom'), +(67958, 'spell_faction_champion_dru_lifebloom'), +(67959, 'spell_faction_champion_dru_lifebloom'), +(68077, 'spell_ioc_repair_turret'), +(68154, 'spell_faction_champion_warl_unstable_affliction'), +(68155, 'spell_faction_champion_warl_unstable_affliction'), +(68156, 'spell_faction_champion_warl_unstable_affliction'), +(68160, 'spell_flame_warder_meteor_fists'), +(68161, 'spell_koralon_meteor_fists'), +(68198, 'spell_pos_rimefang_frost_nova'), +(68282, 'spell_gen_mounted_charge'), +(68284, 'spell_gen_mounted_charge'), +(68321, 'spell_gen_mounted_charge'), +(68361, 'spell_hun_animal_handler'), +(68498, 'spell_gen_mounted_charge'), +(68501, 'spell_gen_mounted_charge'), +(68504, 'spell_gen_break_shield'), +(68529, 'spell_love_in_air_perfume_immune'), +(68530, 'spell_love_in_air_perfume_immune'), +(68576, 'spell_gen_eject_all_passengers'), +(68614, 'spell_apothecary_cologne_spill'), +(68644, 'spell_apothecary_validate_area'), +(68646, 'spell_gen_leeching_swarm'), +(68647, 'spell_gen_leeching_swarm'), +(68721, 'spell_igb_rocket_pack'), +(68786, 'spell_garfrost_permafrost'), +(68793, 'spell_bronjahm_magic_bane'), +(68798, 'spell_apothecary_perfume_spill'), +(68870, 'spell_bronjahm_soulstorm_visual'), +(68875, 'spell_wailing_souls_periodic'), +(68921, 'spell_bronjahm_soulstorm_targeting'), +(68965, 'spell_apothecary_lingering_fumes'), +(68966, 'spell_apothecary_throw_perfume'), +(68980, 'spell_the_lich_king_harvest_soul'), +(68984, 'spell_the_lich_king_cast_back_to_caster'), +(69008, 'spell_bronjahm_soulstorm_channel_ooc'), +(69012, 'spell_krick_explosive_barrage'), +(69020, 'spell_exploding_orb_auto_grow'), +(69030, 'spell_the_lich_king_valkyr_target_search'), +(69037, 'spell_the_lich_king_summon_into_air'), +(69038, 'spell_apothecary_throw_cologne'), +(69049, 'spell_bronjahm_soulstorm_targeting'), +(69050, 'spell_bronjahm_magic_bane'), +(69055, 'spell_marrowgar_bone_slice'), +(69057, 'spell_marrowgar_bone_spike_graveyard'), +(69069, 'spell_shield_of_bones'), +(69075, 'spell_marrowgar_bone_storm'), +(69110, 'spell_the_lich_king_ice_burst_target_search'), +(69140, 'spell_marrowgar_coldflame'), +(69195, 'spell_festergut_pungent_blight'), +(69200, 'spell_the_lich_king_raging_spirit'), +(69222, 'spell_gen_throw_shield'), +(69290, 'spell_festergut_blighted_spores'), +(69366, 'spell_dru_moonkin_form_passive'), +(69377, 'spell_item_runescroll_of_fortitude'), +(69382, 'spell_the_lich_king_lights_favor'), +(69383, 'spell_the_lich_king_dark_hunger'), +(69397, 'spell_the_lich_king_soul_rip'), +(69399, 'spell_igb_cannon_blast'), +(69401, 'spell_igb_incinerating_blast'), +(69409, 'spell_the_lich_king_soul_reaper'), +(69470, 'spell_igb_periodic_trigger_with_power_cost'), +(69483, 'spell_deathwhisper_dark_reckoning'), +(69483, 'spell_icc_dark_reckoning'), +(69487, 'spell_igb_overheat'), +(69487, 'spell_igb_periodic_trigger_with_power_cost'), +(69516, 'spell_icc_yd_summon_undead'), +(69538, 'spell_rotface_little_ooze_combine'), +(69553, 'spell_rotface_large_ooze_combine'), +(69603, 'spell_pos_blight'), +(69604, 'spell_pos_blight'), +(69610, 'spell_rotface_large_ooze_buff_combine'), +(69641, 'spell_gen_gryphon_wyvern_mount_check'), +(69649, 'spell_sindragosa_frost_breath'), +(69664, 'spell_q20438_q24556_aquantos_laundry'), +(69672, 'spell_gen_sunreaver_disguise'), +(69673, 'spell_gen_silver_covenant_disguise'), +(69674, 'spell_rotface_mutated_infection'), +(69678, 'spell_igb_rocket_artillery'), +(69679, 'spell_igb_rocket_artillery_explosion'), +(69682, 'spell_item_sleepy_willy'), +(69705, 'spell_igb_below_zero'), +(69712, 'spell_sindragosa_ice_tomb'), +(69712, 'spell_sindragosa_ice_tomb_dummy'), +(69712, 'spell_sindragosa_ice_tomb_filter'), +(69732, 'spell_item_lil_phylactery'), +(69762, 'spell_gen_allow_proc_from_spells_with_cost'), +(69762, 'spell_sindragosa_unchained_magic'), +(69766, 'spell_sindragosa_instability'), +(69832, 'spell_rotface_unstable_ooze_explosion'), +(69839, 'spell_rotface_unstable_ooze_explosion_init'), +(69891, 'spell_gen_clone_weapon'), +(69892, 'spell_gen_clone_weapon'), +(69893, 'spell_gen_clone_weapon_aura'), +(69896, 'spell_gen_clone_weapon_aura'), +(70017, 'spell_hor_gunship_cannon_fire'), +(70053, 'spell_svalna_revive_champion'), +(70078, 'spell_svalna_caress_of_death'), +(70104, 'spell_igb_teleport_to_enemy_ship'), +(70107, 'spell_sindragosa_permeating_chill'), +(70117, 'spell_sindragosa_icy_grip'), +(70120, 'spell_igb_on_gunship_deck'), +(70121, 'spell_igb_on_gunship_deck'), +(70122, 'spell_sindragosa_icy_grip_jump'), +(70126, 'spell_sindragosa_frost_beacon'), +(70127, 'spell_sindragosa_mystic_buffet'), +(70132, 'spell_pos_empowered_blizzard'), +(70157, 'spell_sindragosa_ice_tomb_trap'), +(70172, 'spell_igb_cannon_blast'), +(70174, 'spell_igb_incinerating_blast'), +(70207, 'spell_shield_of_bones'), +(70285, 'spell_pos_blight'), +(70286, 'spell_pos_blight'), +(70292, 'spell_pos_glacial_strike'), +(70308, 'spell_putricide_mutation_init'), +(70311, 'spell_putricide_mutated_transformation'), +(70331, 'spell_igb_check_for_players'), +(70336, 'spell_garfrost_permafrost'), +(70337, 'spell_the_lich_king_necrotic_plague'), +(70338, 'spell_the_lich_king_necrotic_plague_jump'), +(70342, 'spell_putricide_slime_puddle_spawn'), +(70345, 'spell_putricide_grow_stacker'), +(70346, 'spell_putricide_slime_puddle'), +(70348, 'spell_igb_rocket_pack_useable'), +(70351, 'spell_putricide_unstable_experiment'), +(70360, 'spell_putricide_eat_ooze'), +(70397, 'spell_igb_burning_pitch_selector'), +(70402, 'spell_putricide_mutated_transformation_dmg'), +(70403, 'spell_igb_burning_pitch_selector'), +(70405, 'spell_putricide_mutated_transformation_dismiss'), +(70443, 'spell_igb_explosion'), +(70444, 'spell_igb_explosion'), +(70447, 'spell_putricide_ooze_channel'), +(70459, 'spell_putricide_ooze_eruption_searcher'), +(70477, 'spell_bh_cleanse_quel_delar'), +(70497, 'spell_the_lich_king_summon_into_air'), +(70498, 'spell_the_lich_king_vile_spirits'), +(70499, 'spell_the_lich_king_vile_spirits_visual'), +(70501, 'spell_the_lich_king_vile_spirit_move_target_search'), +(70534, 'spell_the_lich_king_vile_spirit_damage_target_search'), +(70536, 'spell_icc_sprit_alarm'), +(70539, 'spell_putricide_regurgitated_ooze'), +(70541, 'spell_the_lich_king_infest'), +(70545, 'spell_icc_sprit_alarm'), +(70546, 'spell_icc_sprit_alarm'), +(70547, 'spell_icc_sprit_alarm'), +(70548, 'spell_bh_cleanse_quel_delar'), +(70588, 'spell_valithria_suppression'), +(70592, 'spell_gen_creature_permanent_feign_death'), +(70598, 'spell_sindragosa_s_fury'), +(70609, 'spell_igb_rocket_artillery'), +(70614, 'spell_q24545_aod_special'), +(70628, 'spell_gen_creature_permanent_feign_death'), +(70672, 'spell_putricide_gaseous_bloat'), +(70672, 'spell_putricide_ooze_channel'), +(70691, 'spell_dru_t10_restoration_4p_bonus'), +(70723, 'spell_dru_t10_balance_4p_bonus'), +(70733, 'spell_icc_stoneform'), +(70739, 'spell_icc_geist_alarm'), +(70740, 'spell_icc_geist_alarm'), +(70743, 'spell_q24545_aod_special'), +(70769, 'spell_gen_divine_storm_cd_reset'), +(70790, 'spell_q24545_aod_special'), +(70803, 'spell_gen_proc_not_self'), +(70805, 'spell_gen_proc_on_self'), +(70808, 'spell_sha_t10_restoration_4p_bonus'), +(70811, 'spell_sha_item_t10_elemental_2p_bonus'), +(70814, 'spell_marrowgar_bone_slice'), +(70826, 'spell_marrowgar_bone_spike_graveyard'), +(70834, 'spell_marrowgar_bone_storm'), +(70835, 'spell_marrowgar_bone_storm'), +(70836, 'spell_marrowgar_bone_storm'), +(70842, 'spell_deathwhisper_mana_barrier'), +(70871, 'spell_blood_queen_essence_of_the_blood_queen'), +(70877, 'spell_blood_queen_frenzied_bloodthirst'), +(70911, 'spell_putricide_unbound_plague_dmg'), +(70912, 'spell_dreamwalker_decay_periodic_timer'), +(70912, 'spell_dreamwalker_summon_suppresser'), +(70913, 'spell_dreamwalker_decay_periodic_timer'), +(70915, 'spell_dreamwalker_decay_periodic_timer'), +(70916, 'spell_dreamwalker_decay_periodic_timer'), +(70920, 'spell_putricide_unbound_plague'), +(70921, 'spell_dreamwalker_summoner'), +(70933, 'spell_dreamwalker_summoner'), +(70936, 'spell_dreamwalker_summon_suppresser_effect'), +(70937, 'spell_mage_glyph_of_eternal_water'), +(70946, 'spell_blood_queen_vampiric_bite'), +(70961, 'spell_icc_shattered_bones'), +(70980, 'spell_icc_web_wrap'), +(71032, 'spell_dreamwalker_summoner'), +(71056, 'spell_sindragosa_frost_breath'), +(71057, 'spell_sindragosa_frost_breath'), +(71058, 'spell_sindragosa_frost_breath'), +(71078, 'spell_dreamwalker_summoner'), +(71085, 'spell_dreamwalker_mana_void'), +(71123, 'spell_stinky_precious_decimate'), +(71168, 'spell_item_unsated_craving'), +(71169, 'spell_item_shadows_fate'), +(71201, 'spell_igb_battle_experience_check'), +(71219, 'spell_festergut_pungent_blight'), +(71222, 'spell_festergut_blighted_spores'), +(71224, 'spell_rotface_mutated_infection'), +(71252, 'spell_icc_yh_volley'), +(71255, 'spell_putricide_choking_gas_bomb'), +(71268, 'spell_blood_queen_swarming_shadows_floor_dmg'), +(71274, 'spell_icc_yf_frozen_orb'), +(71281, 'spell_pos_slave_trigger_closest'), +(71316, 'spell_pos_glacial_strike'), +(71317, 'spell_pos_glacial_strike'), +(71335, 'spell_igb_burning_pitch'), +(71339, 'spell_igb_burning_pitch'), +(71340, 'spell_blood_queen_pact_of_the_darkfallen_dmg'), +(71341, 'spell_blood_queen_pact_of_the_darkfallen_dmg_target'), +(71342, 'spell_big_love_rocket'), +(71350, 'spell_frostwarden_handler_focus_fire'), +(71357, 'spell_frostwarden_handler_order_whelp'), +(71376, 'spell_rimefang_icy_blast'), +(71390, 'spell_blood_queen_pact_of_the_darkfallen'), +(71441, 'spell_rotface_unstable_ooze_explosion_suicide'), +(71450, 'spell_gen_aura_service_uniform'), +(71462, 'spell_svalna_remove_spear'), +(71474, 'spell_blood_queen_frenzied_bloodthirst'), +(71475, 'spell_blood_queen_vampiric_bite'), +(71476, 'spell_blood_queen_vampiric_bite'), +(71477, 'spell_blood_queen_vampiric_bite'), +(71503, 'spell_putricide_mutated_transformation'), +(71610, 'spell_item_echoes_of_light'), +(71615, 'spell_putricide_tear_gas_effect'), +(71641, 'spell_item_echoes_of_light'), +(71718, 'spell_taldaram_summon_flame_ball'), +(71756, 'spell_taldaram_ball_of_inferno_flame'), +(71806, 'spell_taldaram_glittering_sparks'), +(71811, 'spell_the_lich_king_jump'), +(71841, 'spell_pet_gen_valkyr_guardian_smite'), +(71842, 'spell_pet_gen_valkyr_guardian_smite'), +(71848, 'spell_item_sleepy_willy'), +(71865, 'spell_item_trauma'), +(71868, 'spell_item_trauma'), +(71874, 'spell_item_toxic_wasteling'), +(71875, 'spell_item_necrotic_touch'), +(71877, 'spell_item_necrotic_touch'), +(71899, 'spell_blood_queen_bloodbolt'), +(71900, 'spell_blood_queen_bloodbolt'), +(71901, 'spell_blood_queen_bloodbolt'), +(71902, 'spell_blood_queen_bloodbolt'), +(71903, 'spell_item_shadowmourne'), +(71905, 'spell_item_shadowmourne_soul_fragment'), +(71941, 'spell_dreamwalker_twisted_nightmares'), +(71943, 'spell_blood_council_summon_shadow_resonance'), +(71963, 'spell_blood_queen_presence_of_the_darkfallen'), +(71964, 'spell_blood_queen_presence_of_the_darkfallen'), +(71966, 'spell_putricide_unstable_experiment'), +(71967, 'spell_putricide_unstable_experiment'), +(71968, 'spell_putricide_unstable_experiment'), +(71970, 'spell_dreamwalker_nightmare_cloud'), +(72040, 'spell_taldaram_summon_flame_ball'), +(72053, 'spell_valanar_kinetic_bomb_summon'), +(72054, 'spell_valanar_kinetic_bomb_absorb'), +(72080, 'spell_valanar_kinetic_bomb'), +(72087, 'spell_valanar_kinetic_bomb_knockback'), +(72088, 'spell_marrowgar_bone_spike_graveyard'), +(72089, 'spell_marrowgar_bone_spike_graveyard'), +(72134, 'spell_igb_explosion_main'), +(72137, 'spell_igb_explosion_main'), +(72155, 'spell_icc_harvest_blight_specimen'), +(72162, 'spell_icc_harvest_blight_specimen'), +(72176, 'spell_deathbringer_blood_link_blood_beast_aura'), +(72178, 'spell_deathbringer_blood_link_aura'), +(72202, 'spell_deathbringer_blood_link'), +(72219, 'spell_festergut_gastric_bloat'), +(72224, 'spell_dreamwalker_summon_portal'), +(72262, 'spell_the_lich_king_quake'), +(72286, 'spell_invincible'), +(72340, 'spell_igb_teleport_players_on_victory'), +(72368, 'spell_hor_shared_suffering'), +(72369, 'spell_hor_shared_suffering'), +(72371, 'spell_deathbringer_blood_power'), +(72378, 'spell_deathbringer_blood_nova_targeting'), +(72385, 'spell_deathbringer_boiling_blood'), +(72429, 'spell_the_lich_king_mass_resurrection'), +(72431, 'spell_the_lich_king_jump_remove_aura'), +(72441, 'spell_deathbringer_boiling_blood'), +(72442, 'spell_deathbringer_boiling_blood'), +(72443, 'spell_deathbringer_boiling_blood'), +(72451, 'spell_putricide_mutated_plague'), +(72455, 'spell_putricide_gaseous_bloat'), +(72455, 'spell_putricide_ooze_channel'), +(72456, 'spell_putricide_slime_puddle'), +(72457, 'spell_putricide_regurgitated_ooze'), +(72463, 'spell_putricide_mutated_plague'), +(72465, 'spell_sindragosa_soul_preservation'), +(72480, 'spell_dreamwalker_summon_portal'), +(72508, 'spell_putricide_mutated_transformation_dismiss'), +(72509, 'spell_putricide_mutated_transformation_dismiss'), +(72510, 'spell_putricide_mutated_transformation_dismiss'), +(72511, 'spell_putricide_mutated_transformation_dmg'), +(72512, 'spell_putricide_mutated_transformation_dmg'), +(72513, 'spell_putricide_mutated_transformation_dmg'), +(72527, 'spell_putricide_eat_ooze'), +(72528, 'spell_sindragosa_mystic_buffet'), +(72529, 'spell_sindragosa_mystic_buffet'), +(72530, 'spell_sindragosa_mystic_buffet'), +(72551, 'spell_festergut_gastric_bloat'), +(72552, 'spell_festergut_gastric_bloat'), +(72553, 'spell_festergut_gastric_bloat'), +(72585, 'spell_icc_soul_missile'), +(72595, 'spell_the_lich_king_restore_soul'), +(72618, 'spell_putricide_clear_aura_effect_value'), +(72635, 'spell_blood_queen_swarming_shadows_floor_dmg'), +(72636, 'spell_blood_queen_swarming_shadows_floor_dmg'), +(72637, 'spell_blood_queen_swarming_shadows_floor_dmg'), +(72671, 'spell_putricide_mutated_plague'), +(72672, 'spell_putricide_mutated_plague'), +(72705, 'spell_marrowgar_coldflame_bonestorm'), +(72752, 'spell_pvp_trinket_wotf_shared_cd'), +(72754, 'spell_the_lich_king_defile'), +(72757, 'spell_pvp_trinket_wotf_shared_cd'), +(72782, 'spell_taldaram_ball_of_inferno_flame'), +(72783, 'spell_taldaram_ball_of_inferno_flame'), +(72784, 'spell_taldaram_ball_of_inferno_flame'), +(72832, 'spell_putricide_gaseous_bloat'), +(72832, 'spell_putricide_ooze_channel'), +(72833, 'spell_putricide_gaseous_bloat'), +(72833, 'spell_putricide_ooze_channel'), +(72836, 'spell_putricide_ooze_channel'), +(72837, 'spell_putricide_ooze_channel'), +(72838, 'spell_putricide_ooze_channel'), +(72854, 'spell_putricide_unbound_plague_dmg'), +(72855, 'spell_putricide_unbound_plague_dmg'), +(72856, 'spell_putricide_unbound_plague_dmg'), +(72864, 'spell_frost_giant_death_plague'), +(72868, 'spell_putricide_slime_puddle'), +(72869, 'spell_putricide_slime_puddle'), +(72875, 'spell_putricide_regurgitated_ooze'), +(72876, 'spell_putricide_regurgitated_ooze'), +(72999, 'spell_blood_council_shadow_prison_damage'), +(73001, 'spell_blood_council_shadow_prison'), +(73022, 'spell_rotface_mutated_infection'), +(73023, 'spell_rotface_mutated_infection'), +(73031, 'spell_festergut_pungent_blight'), +(73032, 'spell_festergut_pungent_blight'), +(73033, 'spell_festergut_blighted_spores'), +(73034, 'spell_festergut_blighted_spores'), +(73058, 'spell_deathbringer_blood_nova_targeting'), +(73061, 'spell_sindragosa_frost_breath'), +(73062, 'spell_sindragosa_frost_breath'), +(73063, 'spell_sindragosa_frost_breath'), +(73064, 'spell_sindragosa_frost_breath'), +(73076, 'spell_gen_throw_shield'), +(73159, 'spell_the_lich_king_play_movie'), +(73488, 'spell_the_lich_king_life_siphon'), +(73530, 'spell_the_lich_king_shadow_trap_visual'), +(73579, 'spell_the_lich_king_summon_into_air'), +(73582, 'spell_the_lich_king_trigger_vile_spirit'), +(73650, 'spell_the_lich_king_restore_soul'), +(73655, 'spell_the_lich_king_teleport_to_frostmourne_hc'), +(73708, 'spell_the_lich_king_defile'), +(73709, 'spell_the_lich_king_defile'), +(73710, 'spell_the_lich_king_defile'), +(73779, 'spell_the_lich_king_infest'), +(73780, 'spell_the_lich_king_infest'), +(73781, 'spell_the_lich_king_infest'), +(73782, 'spell_the_lich_king_life_siphon'), +(73783, 'spell_the_lich_king_life_siphon'), +(73784, 'spell_the_lich_king_life_siphon'), +(73785, 'spell_the_lich_king_necrotic_plague_jump'), +(73786, 'spell_the_lich_king_necrotic_plague_jump'), +(73787, 'spell_the_lich_king_necrotic_plague_jump'), +(73797, 'spell_the_lich_king_soul_reaper'), +(73798, 'spell_the_lich_king_soul_reaper'), +(73799, 'spell_the_lich_king_soul_reaper'), +(73912, 'spell_the_lich_king_necrotic_plague'), +(73913, 'spell_the_lich_king_necrotic_plague'), +(73914, 'spell_the_lich_king_necrotic_plague'), +(74282, 'spell_the_lich_king_shadow_trap_periodic'), +(74296, 'spell_the_lich_king_harvest_soul'), +(74297, 'spell_the_lich_king_harvest_soul'), +(74300, 'spell_the_lich_king_summon_into_air'), +(74302, 'spell_the_lich_king_summon_spirit_bomb'), +(74325, 'spell_the_lich_king_harvest_soul'), +(74341, 'spell_the_lich_king_summon_spirit_bomb'), +(74342, 'spell_the_lich_king_summon_spirit_bomb'), +(74343, 'spell_the_lich_king_summon_spirit_bomb'), +(74396, 'spell_mage_fingers_of_frost_proc'), +(74445, 'spell_the_lich_king_cast_back_to_caster'), +(74452, 'spell_saviana_conflagration_init'), +(74455, 'spell_saviana_conflagration_throwback'), +(74490, 'spell_gen_creature_permanent_feign_death'), +(74505, 'spell_baltharus_enervating_brand_trigger'), +(74562, 'spell_halion_fiery_combustion'), +(74567, 'spell_halion_mark_of_combustion'), +(74610, 'spell_halion_combustion_summon'), +(74630, 'spell_gen_mod_radius_by_caster_scale'), +(74638, 'spell_halion_meteor_strike_targeting'), +(74641, 'spell_halion_meteor_strike_marker'), +(74696, 'spell_halion_meteor_strike_spread'), +(74768, 'spell_halion_twilight_cutter_periodic'), +(74769, 'spell_halion_twilight_cutter'), +(74792, 'spell_halion_soul_consumption'), +(74795, 'spell_halion_mark_of_consumption'), +(74800, 'spell_halion_consumption_summon'), +(74802, 'spell_gen_mod_radius_by_caster_scale'), +(74804, 'spell_halion_summon_exit_portals'), +(74805, 'spell_halion_summon_exit_portals'), +(74807, 'spell_halion_twilight_realm'), +(74808, 'spell_halion_twilight_phasing'), +(74812, 'spell_halion_leave_twilight_realm'), +(74856, 'spell_blazing_hippogryph'), +(74960, 'spell_gen_select_target_count_30_1'), +(75063, 'spell_halion_twilight_division'), +(75102, 'spell_voljin_war_drums'), +(75396, 'spell_halion_clear_debuffs'), +(75415, 'spell_ruby_sanctum_rallying_shout'), +(75420, 'spell_mount_check'), +(75509, 'spell_halion_twilight_mending'), +(75614, 'spell_celestial_steed'), +(75731, 'spell_item_instant_statue'), +(75874, 'spell_gen_mod_radius_by_caster_scale'), +(75875, 'spell_gen_mod_radius_by_caster_scale'), +(75876, 'spell_gen_mod_radius_by_caster_scale'), +(75882, 'spell_gen_mod_radius_by_caster_scale'), +(75883, 'spell_gen_mod_radius_by_caster_scale'), +(75884, 'spell_gen_mod_radius_by_caster_scale'), +(75886, 'spell_halion_blazing_aura'), +(75887, 'spell_halion_blazing_aura'), +(75973, 'spell_x53_touring_rocket'), +(76096, 'spell_item_lil_xt'), +(76098, 'spell_item_lil_xt'), +(77844, 'spell_halion_twilight_cutter'), +(77845, 'spell_halion_twilight_cutter'), +(77846, 'spell_halion_twilight_cutter'), +(100101, 'spell_valkyr_ball_periodic_dummy'); + +-- Restoring deleted spell_ranks for Threat of Thassarian +DELETE FROM `spell_ranks` WHERE `first_spell_id` IN (59133, 66216); +INSERT INTO `spell_ranks` (`first_spell_id`,`spell_id`,`rank`) VALUES +(59133, 59133, 1), +(59133, 66988, 2), +(59133, 66989, 3), +(59133, 66990, 4), +(59133, 66991, 5), +(59133, 66992, 6); + +-- Restoring spell_proc_events to how it was before the commit. +DROP TABLE IF EXISTS `spell_proc_event`; +CREATE TABLE IF NOT EXISTS `spell_proc_event` ( + `entry` MEDIUMINT(9) NOT NULL DEFAULT '0', + `SchoolMask` TINYINT(4) NOT NULL DEFAULT '0', + `SpellFamilyName` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `SpellFamilyMask0` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `SpellFamilyMask1` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `SpellFamilyMask2` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `procFlags` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `procEx` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `procPhase` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `ppmRate` FLOAT NOT NULL DEFAULT '0', + `CustomChance` FLOAT NOT NULL DEFAULT '0', + `Cooldown` INT(10) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`entry`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4; + +DELETE FROM `spell_proc_event`; + +INSERT INTO `spell_proc_event` (`entry`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `procFlags`, `procEx`, `procPhase`, `ppmRate`, `CustomChance`, `Cooldown`) VALUES +(-66799, 0, 15, 4194304, 0, 0, 16, 0, 0, 0, 0, 0), +(-65661, 0, 15, 4194321, 537001988, 0, 16, 0, 0, 0, 100, 0), +(-64127, 0, 6, 1, 1, 0, 0, 0, 0, 0, 0, 0), +(-63730, 0, 6, 2048, 4, 0, 0, 0, 0, 0, 0, 0), +(-63373, 0, 11, 2147483648, 0, 0, 65536, 0, 0, 0, 0, 0), +(-63156, 126, 5, 1, 192, 0, 65536, 0, 0, 0, 0, 0), +(-62764, 0, 9, 0, 268435456, 0, 65536, 0, 0, 0, 100, 0), +(-61846, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(-61680, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-59088, 0, 4, 0, 2, 0, 1024, 0, 4, 0, 0, 0), +(-58872, 0, 0, 0, 0, 0, 0, 270403, 0, 0, 0, 0), +(-57878, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0), +(-57470, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 15000), +(-56636, 0, 4, 32, 0, 0, 0, 262144, 0, 0, 0, 5500), +(-56342, 0, 9, 24, 134217728, 409600, 0, 0, 0, 0, 0, 22000), +(-55666, 0, 15, 1, 134217728, 0, 0, 0, 0, 0, 0, 0), +(-54747, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(-54639, 0, 15, 4194304, 65536, 0, 0, 0, 0, 0, 0, 0), +(-53709, 2, 10, 16384, 0, 0, 0, 0, 0, 0, 0, 0), +(-53695, 0, 10, 8388608, 0, 8, 16, 0, 0, 0, 0, 0), +(-53671, 0, 10, 8388608, 0, 0, 0, 0, 0, 0, 0, 0), +(-53569, 0, 10, 2097152, 65536, 0, 0, 2, 0, 0, 0, 0), +(-53551, 0, 10, 4096, 0, 0, 0, 0, 0, 0, 0, 0), +(-53527, 1, 10, 0, 0, 4, 1024, 1, 0, 0, 100, 0), +(-53501, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-53486, 0, 10, 8388608, 163840, 0, 0, 262146, 0, 0, 0, 0), +(-53380, 0, 10, 8388608, 163840, 0, 0, 262146, 0, 0, 0, 0), +(-53290, 0, 9, 2048, 1, 512, 0, 2, 0, 0, 0, 0), +(-53256, 0, 9, 2048, 8388609, 0, 0, 2, 0, 0, 0, 0), +(-53234, 0, 9, 131072, 1, 1, 0, 2, 0, 0, 0, 0), +(-53228, 0, 9, 32, 16777216, 0, 0, 0, 0, 0, 0, 0), +(-53221, 0, 9, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-53215, 0, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(-53178, 0, 9, 0, 268435456, 0, 65536, 0, 0, 0, 100, 0), +(-52795, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(-52127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(-51940, 0, 0, 0, 0, 0, 16384, 0, 0, 0, 0, 0), +(-51692, 0, 8, 516, 0, 0, 0, 0, 0, 0, 0, 0), +(-51672, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 1000), +(-51664, 0, 8, 131072, 8, 0, 0, 0, 0, 0, 0, 0), +(-51634, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-51627, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0), +(-51625, 0, 8, 268476416, 0, 0, 0, 0, 0, 0, 0, 0), +(-51562, 0, 11, 256, 0, 16, 0, 0, 0, 0, 0, 0), +(-51556, 0, 11, 192, 0, 16, 0, 2, 0, 0, 0, 0), +(-51523, 0, 11, 0, 1, 0, 65536, 0, 0, 0, 50, 0), +(-51521, 0, 11, 0, 16, 0, 0, 0, 1, 0, 0, 1), +(-51474, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(-51459, 0, 15, 0, 536870912, 0, 20, 0, 0, 0, 0, 0), +(-50880, 0, 15, 0, 67108864, 0, 0, 0, 0, 0, 0, 0), +(-49467, 0, 15, 16, 131072, 0, 0, 0, 0, 0, 0, 0), +(-49223, 0, 15, 17, 134348800, 0, 0, 0, 0, 0, 0, 0), +(-49219, 0, 15, 0, 536870912, 0, 20, 0, 0, 0, 0, 0), +(-49217, 0, 15, 0, 0, 2, 0, 0, 0, 0, 0, 500), +(-49208, 0, 15, 4194304, 65536, 0, 0, 0, 0, 0, 0, 0), +(-49188, 0, 15, 0, 131072, 0, 0, 0, 0, 0, 0, 0), +(-49149, 0, 15, 6, 131074, 0, 0, 0, 0, 0, 0, 0), +(-49018, 0, 15, 20971520, 0, 0, 0, 0, 0, 0, 0, 0), +(-49004, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0), +(-48988, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-48539, 0, 7, 16, 67108864, 0, 262144, 0, 0, 0, 0, 0), +(-48516, 0, 7, 5, 0, 0, 0, 2, 0, 0, 0, 30000), +(-48506, 0, 7, 5, 0, 0, 0, 0, 0, 0, 0, 0), +(-48496, 0, 7, 96, 33554434, 0, 0, 2, 0, 0, 0, 0), +(-48483, 0, 7, 34816, 1088, 0, 0, 0, 0, 0, 0, 0), +(-47580, 0, 6, 0, 0, 64, 0, 65536, 0, 0, 0, 0), +(-47569, 0, 6, 16384, 0, 0, 16384, 0, 0, 0, 0, 0), +(-47516, 0, 6, 6144, 65536, 0, 0, 0, 0, 0, 0, 0), +(-47509, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-47263, 32, 5, 0, 0, 0, 0, 2, 0, 0, 0, 20000), +(-47258, 0, 5, 0, 8388608, 0, 0, 65536, 0, 0, 0, 0), +(-47245, 0, 5, 2, 0, 0, 0, 1, 0, 0, 0, 0), +(-47201, 0, 5, 16393, 262144, 0, 0, 0, 0, 0, 0, 0), +(-47195, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(-46945, 0, 4, 0, 65536, 0, 0, 0, 0, 0, 0, 0), +(-46913, 0, 4, 64, 1028, 0, 0, 262144, 0, 0, 0, 0), +(-46867, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-46854, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-45234, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-44557, 0, 3, 32, 0, 0, 0, 0, 0, 0, 0, 6000), +(-44449, 0, 3, 551686775, 102472, 0, 0, 2, 0, 0, 0, 0), +(-44445, 0, 3, 19, 69632, 0, 0, 0, 0, 0, 0, 0), +(-44442, 0, 3, 8388608, 64, 0, 0, 65536, 0, 0, 0, 1000), +(-41635, 0, 0, 0, 0, 0, 664232, 0, 0, 0, 0, 0), +(-35541, 0, 0, 0, 0, 0, 8388608, 0, 0, 0, 0, 0), +(-35100, 0, 9, 4096, 0, 1, 0, 0, 0, 0, 0, 0), +(-34950, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-34935, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8000), +(-34914, 0, 6, 8192, 0, 0, 131073, 0, 0, 0, 0, 0), +(-34753, 0, 6, 6144, 4, 4096, 0, 2, 0, 0, 0, 0), +(-34500, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-34497, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-33881, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-33191, 0, 6, 8421376, 1024, 0, 0, 0, 0, 0, 0, 0), +(-33150, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-33142, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-33076, 0, 0, 0, 0, 0, 664232, 0, 0, 0, 0, 0), +(-32385, 0, 5, 1, 262144, 0, 0, 0, 0, 0, 0, 0), +(-31876, 0, 10, 8388608, 0, 0, 0, 262144, 0, 0, 0, 0), +(-31871, 0, 10, 16, 0, 0, 16384, 0, 0, 0, 0, 0), +(-31833, 0, 10, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0), +(-31656, 4, 3, 134217728, 0, 0, 0, 0, 0, 0, 0, 0), +(-31571, 0, 3, 0, 34, 0, 16384, 0, 4, 0, 0, 0), +(-31569, 0, 3, 65536, 0, 0, 0, 0, 0, 0, 0, 0), +(-31244, 0, 8, 4063232, 9, 0, 0, 52, 0, 0, 0, 0), +(-31124, 0, 8, 16777222, 0, 0, 0, 0, 0, 0, 0, 0), +(-30881, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(-30701, 28, 0, 0, 0, 0, 664232, 0, 0, 0, 100, 0), +(-30675, 0, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0), +(-30299, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-30293, 0, 5, 897, 8519872, 0, 0, 0, 0, 0, 0, 0), +(-30160, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-29834, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(-29593, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0), +(-29441, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0), +(-29074, 84, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-27811, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-20925, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(-20500, 0, 4, 268435456, 0, 0, 0, 0, 0, 0, 0, 0), +(-20335, 0, 10, 8388608, 0, 0, 16, 0, 0, 0, 100, 0), +(-20234, 0, 10, 32768, 0, 0, 0, 0, 0, 0, 0, 0), +(-20210, 0, 10, 3221225472, 65536, 0, 0, 2, 0, 0, 0, 0), +(-20049, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-19572, 0, 9, 8388608, 0, 0, 262144, 0, 0, 0, 0, 0), +(-19184, 0, 9, 16, 8192, 262144, 0, 0, 4, 0, 0, 0), +(-18119, 0, 5, 0, 8388608, 0, 0, 0, 0, 0, 0, 0), +(-18096, 0, 5, 256, 8388608, 0, 0, 2, 0, 0, 0, 0), +(-18094, 0, 5, 10, 0, 0, 262144, 262144, 0, 0, 0, 0), +(-17793, 0, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(-17106, 0, 7, 524288, 0, 0, 0, 0, 0, 0, 0, 0), +(-16958, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-16952, 0, 7, 233472, 1024, 262144, 0, 2, 0, 0, 0, 0), +(-16880, 72, 7, 103, 58720258, 0, 0, 2, 1, 0, 0, 0), +(-16850, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(-16511, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-16487, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-16257, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 500), +(-16256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-16180, 0, 11, 448, 0, 16, 0, 2, 0, 0, 100, 0), +(-16176, 0, 11, 448, 0, 16, 0, 2, 0, 0, 0, 0), +(-16086, 4, 11, 0, 262144, 0, 196608, 0, 0, 0, 0, 0), +(-15337, 0, 6, 8396800, 2, 0, 327680, 2, 0, 0, 100, 0), +(-14892, 0, 6, 268443136, 65540, 0, 0, 2, 0, 0, 0, 0), +(-14531, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-14186, 0, 8, 1082131720, 6, 0, 0, 2, 0, 0, 0, 1000), +(-14156, 0, 8, 4063232, 8, 0, 0, 0, 4, 0, 0, 0), +(-13983, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0), +(-13754, 0, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0), +(-13165, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(-12966, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(-12834, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-12797, 0, 4, 1024, 0, 0, 0, 0, 0, 0, 0, 0), +(-12319, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-12311, 0, 4, 2048, 1, 0, 0, 0, 0, 0, 0, 0), +(-12298, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0), +(-12289, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(-12281, 0, 4, 2858419268, 4194565, 0, 0, 0, 0, 0, 0, 6000), +(-11255, 0, 3, 16384, 0, 0, 0, 0, 0, 0, 0, 0), +(-11213, 0, 3, 0, 0, 0, 0, 2359299, 0, 0, 0, 0), +(-11185, 0, 3, 128, 0, 0, 327680, 0, 0, 0, 0, 0), +(-11180, 16, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(-11119, 4, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-11095, 0, 3, 16, 0, 0, 0, 0, 0, 0, 0, 0), +(-9799, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(-5952, 0, 8, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(-1463, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0), +(-974, 0, 0, 0, 0, 0, 139944, 0, 0, 0, 0, 3000), +(-588, 0, 0, 0, 0, 0, 0, 262144, 0, 0, 0, 0), +(-324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(1719, 0, 4, 778044484, 4212549, 0, 0, 2, 0, 0, 0, 0), +(1784, 0, 0, 0, 0, 0, 0, 262144, 0, 0, 0, 0), +(3232, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(4524, 0, 0, 0, 0, 0, 1048576, 262144, 0, 0, 0, 0), +(6346, 0, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0), +(7383, 1, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0), +(7434, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(8178, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(9452, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(9782, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(9784, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(11129, 4, 3, 12582935, 200768, 0, 0, 0, 0, 0, 0, 0), +(12169, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(12322, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(12999, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(13000, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0), +(13001, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0), +(13002, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0), +(13163, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0), +(15088, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(15128, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(15257, 32, 6, 0, 0, 0, 327680, 0, 0, 0, 33, 0), +(15277, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(15286, 32, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(15331, 32, 6, 0, 0, 0, 327680, 0, 0, 0, 66, 0), +(15332, 32, 6, 0, 0, 0, 327680, 0, 0, 0, 100, 0), +(15346, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(15600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0), +(16164, 0, 11, 2416967875, 266240, 0, 69968, 2097154, 0, 0, 0, 0), +(16550, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(16620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(16624, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(16864, 0, 0, 0, 0, 0, 87060, 2162688, 0, 3.5, 0, 0), +(17364, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(17495, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(17619, 0, 13, 0, 0, 0, 34816, 3, 0, 0, 0, 0), +(18820, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(19577, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(20128, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(20131, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(20132, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(20164, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0), +(20165, 0, 0, 0, 0, 0, 0, 1027, 0, 10, 0, 0), +(20166, 0, 0, 0, 0, 0, 0, 1027, 0, 12, 0, 0), +(20182, 0, 0, 0, 0, 0, 0, 262211, 0, 0, 0, 0), +(20185, 0, 0, 0, 0, 0, 1048576, 0, 0, 15, 0, 0), +(20186, 0, 0, 0, 0, 0, 1048576, 0, 0, 15, 0, 0), +(20375, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(20705, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(20784, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(20911, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0), +(21084, 3, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(21185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(21882, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(21890, 0, 4, 712396527, 876, 0, 0, 0, 0, 0, 0, 0), +(22007, 0, 3, 2097185, 0, 0, 0, 65536, 0, 0, 0, 0), +(22618, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(22648, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(23547, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0), +(23548, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(23551, 0, 11, 192, 0, 0, 0, 0, 0, 0, 0, 0), +(23552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(23572, 0, 11, 192, 0, 0, 0, 0, 0, 0, 0, 0), +(23578, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(23581, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(23686, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(23688, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(23689, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(23721, 0, 9, 2048, 0, 0, 0, 0, 0, 0, 0, 0), +(23920, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(24353, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(24389, 0, 3, 12582935, 64, 0, 0, 0, 1, 0, 0, 0), +(24658, 0, 0, 0, 0, 0, 82192, 0, 1, 0, 0, 0), +(24905, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(24932, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 6000), +(25050, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(25669, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(25899, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0), +(26016, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(26107, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0), +(26119, 0, 11, 2416967683, 0, 0, 65536, 65536, 0, 0, 0, 0), +(26128, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0), +(26135, 0, 10, 8388608, 0, 0, 0, 65536, 0, 0, 0, 0), +(26480, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(26605, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(27419, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(27498, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(27521, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 15000), +(27656, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(27774, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(27787, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(28305, 0, 0, 0, 0, 0, 4, 3, 0, 0, 100, 0), +(28460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5000), +(28716, 0, 7, 16, 0, 0, 262144, 0, 0, 0, 0, 0), +(28719, 0, 7, 32, 0, 0, 0, 2, 0, 0, 0, 0), +(28744, 0, 7, 64, 0, 0, 278528, 0, 0, 0, 0, 0), +(28752, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(28789, 0, 10, 3221225472, 0, 0, 0, 0, 0, 0, 0, 0), +(28802, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(28809, 0, 6, 4096, 0, 0, 0, 2, 0, 0, 0, 0), +(28812, 0, 8, 33554438, 0, 0, 0, 2, 0, 0, 0, 0), +(28816, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(28823, 0, 11, 192, 0, 0, 0, 0, 0, 0, 0, 0), +(28847, 0, 7, 32, 0, 0, 0, 0, 0, 0, 0, 0), +(28849, 0, 11, 128, 0, 0, 0, 0, 0, 0, 0, 0), +(29150, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29307, 0, 0, 0, 0, 0, 4, 65539, 0, 0, 100, 0), +(29385, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0), +(29455, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(29501, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29624, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29625, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29626, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29632, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29633, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29634, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29635, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29636, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29637, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(29977, 0, 3, 12582935, 64, 0, 0, 0, 0, 0, 0, 0), +(30003, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(30823, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0), +(30937, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(31221, 0, 8, 4196352, 0, 0, 1024, 0, 0, 0, 0, 0), +(31222, 0, 8, 4196352, 0, 0, 1024, 0, 0, 0, 0, 0), +(31223, 0, 8, 4196352, 0, 0, 1024, 0, 0, 0, 0, 0), +(31394, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(31794, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(31801, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(31904, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(32216, 0, 4, 0, 256, 0, 16, 0, 4, 0, 0, 0), +(32409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(32587, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(32642, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(32734, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(32748, 0, 8, 0, 1, 0, 320, 0, 1, 0, 0, 0), +(32776, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(32777, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(32837, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 45000), +(32844, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(32885, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(33089, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(33127, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0), +(33297, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(33299, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(33510, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0), +(33648, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(33719, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(33746, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(33757, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 3000), +(33759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(33953, 0, 0, 0, 0, 0, 278528, 3, 0, 0, 0, 45000), +(34074, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0), +(34080, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0), +(34138, 0, 11, 128, 0, 0, 0, 0, 0, 0, 0, 0), +(34139, 0, 10, 1073741824, 0, 0, 0, 0, 0, 0, 0, 0), +(34258, 0, 10, 8388608, 0, 0, 0, 262144, 0, 0, 0, 0), +(34262, 0, 10, 8388608, 0, 0, 0, 262144, 0, 0, 0, 0), +(34320, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(34355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(34477, 0, 9, 0, 0, 0, 349524, 0, 0, 0, 100, 0), +(34584, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(34586, 0, 0, 0, 0, 0, 0, 0, 0, 1.5, 0, 0), +(34598, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(34749, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0), +(34774, 0, 0, 0, 0, 0, 0, 0, 0, 1.5, 0, 20000), +(34783, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(34827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(35077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(35080, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 60000), +(35083, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(35086, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(35121, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(36032, 0, 3, 4096, 32768, 0, 0, 0, 1, 0, 0, 0), +(36096, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(36111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(36541, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(37165, 0, 8, 2098176, 0, 0, 0, 0, 0, 0, 0, 0), +(37168, 0, 8, 4063232, 9, 0, 0, 0, 4, 0, 0, 0), +(37170, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(37173, 0, 8, 750519704, 262, 0, 0, 0, 0, 0, 0, 30000), +(37189, 0, 10, 3221225472, 0, 0, 0, 2, 0, 0, 0, 60000), +(37193, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(37195, 0, 10, 8388608, 0, 0, 0, 262144, 0, 0, 0, 0), +(37197, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 45000), +(37213, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(37214, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(37227, 0, 11, 448, 0, 0, 0, 2, 0, 0, 0, 60000), +(37237, 0, 11, 1, 0, 0, 0, 2, 0, 0, 0, 0), +(37247, 8, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 45000), +(37377, 32, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(37379, 32, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(37384, 0, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(37443, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(37447, 0, 3, 0, 256, 0, 17408, 0, 0, 0, 100, 15000), +(37514, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0), +(37516, 0, 4, 1024, 0, 0, 0, 0, 0, 0, 0, 0), +(37519, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0), +(37523, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(37528, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(37536, 0, 4, 65536, 0, 0, 0, 0, 0, 0, 0, 0), +(37568, 0, 6, 2048, 0, 0, 0, 0, 0, 0, 0, 0), +(37594, 0, 6, 4096, 0, 0, 0, 0, 0, 0, 0, 0), +(37600, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(37601, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(37603, 0, 6, 32768, 0, 0, 0, 0, 0, 0, 0, 0), +(37655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(37657, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3000), +(38026, 1, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0), +(38031, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(38290, 0, 0, 0, 0, 0, 0, 0, 0, 1.6, 0, 0), +(38299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15000), +(38326, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(38327, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(38334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(38347, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(38350, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(38394, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0), +(38857, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(39027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(39372, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(39437, 4, 5, 4964, 192, 0, 0, 65536, 0, 0, 0, 0), +(39442, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), +(39443, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(39530, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(39958, 0, 0, 0, 0, 0, 0, 0, 0, 0.7, 0, 40000), +(40407, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(40438, 0, 6, 32832, 0, 0, 0, 0, 0, 0, 0, 0), +(40442, 0, 7, 20, 1088, 0, 0, 0, 1, 0, 0, 0), +(40444, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(40458, 0, 4, 33554432, 1537, 0, 0, 0, 0, 0, 0, 0), +(40463, 0, 11, 129, 16, 0, 0, 0, 0, 0, 0, 0), +(40470, 0, 10, 3229614080, 0, 0, 0, 262144, 0, 0, 0, 0), +(40475, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0), +(40478, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(40482, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(40485, 0, 9, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(40899, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(41034, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0), +(41260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(41262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(41350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(41381, 0, 0, 0, 0, 0, 0, 256, 0, 0, 0, 0), +(41393, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0), +(41434, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 45000), +(41469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0), +(41989, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, 0, 0), +(42083, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(42135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90000), +(42136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90000), +(42368, 0, 10, 1073741824, 0, 0, 0, 0, 0, 0, 0, 0), +(42370, 0, 11, 128, 0, 0, 0, 0, 0, 0, 0, 0), +(42760, 0, 0, 0, 0, 0, 245966, 0, 0, 0, 20, 0), +(42770, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(43338, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(43443, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(43726, 0, 10, 1073741824, 0, 0, 0, 0, 0, 0, 0, 0), +(43728, 0, 11, 128, 0, 0, 0, 0, 0, 0, 0, 0), +(43737, 0, 7, 0, 1088, 0, 0, 0, 0, 0, 0, 10000), +(43739, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(43741, 0, 10, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0), +(43745, 0, 10, 0, 512, 0, 0, 0, 0, 0, 0, 0), +(43748, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(43750, 0, 11, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(43819, 0, 0, 0, 0, 0, 0, 65536, 1, 0, 0, 0), +(44404, 0, 3, 536870945, 36864, 0, 0, 0, 0, 0, 0, 0), +(44543, 0, 3, 1049120, 4096, 0, 65536, 0, 7, 0, 7, 0), +(44545, 0, 3, 1049120, 4096, 0, 65536, 0, 7, 0, 15, 0), +(44546, 0, 3, 1049120, 4096, 0, 69632, 0, 0, 0, 5, 3000), +(44548, 0, 3, 1049120, 4096, 0, 69632, 0, 0, 0, 10, 3000), +(44549, 0, 3, 1049120, 4096, 0, 69632, 0, 0, 0, 15, 3000), +(44835, 0, 7, 0, 128, 0, 16, 0, 0, 0, 0, 0), +(45054, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15000), +(45057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(45354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(45355, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(45469, 0, 15, 16, 0, 0, 16, 0, 0, 0, 0, 0), +(45481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(45482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(45483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(45484, 0, 0, 0, 0, 0, 16384, 0, 0, 0, 0, 45000), +(46025, 32, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(46092, 0, 10, 1073741824, 0, 0, 0, 0, 0, 0, 0, 0), +(46098, 0, 11, 128, 0, 0, 0, 0, 0, 0, 0, 0), +(46569, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(46662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20000), +(46832, 0, 7, 1, 0, 0, 0, 65536, 0, 0, 0, 0), +(46910, 0, 4, 64, 0, 0, 20, 0, 0, 5.5, 0, 0), +(46911, 0, 4, 64, 0, 0, 20, 0, 0, 7.5, 0, 0), +(46916, 0, 4, 2097152, 0, 0, 0, 0, 4, 0, 0, 0), +(46951, 0, 4, 1024, 64, 0, 0, 0, 0, 0, 0, 0), +(46952, 0, 0, 1024, 64, 0, 0, 0, 0, 0, 0, 0), +(46953, 0, 0, 1024, 64, 0, 0, 0, 0, 0, 0, 0), +(47981, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(48833, 0, 7, 0, 1088, 0, 0, 0, 0, 0, 0, 0), +(48835, 0, 10, 8388608, 0, 0, 0, 262144, 0, 0, 0, 0), +(48837, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(49027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 20000), +(49028, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(49194, 0, 15, 8192, 0, 0, 0, 0, 0, 0, 0, 0), +(49222, 0, 0, 0, 0, 0, 139944, 0, 0, 0, 0, 2000), +(49542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 20000), +(49543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 20000), +(49592, 0, 0, 0, 0, 0, 664232, 262144, 0, 0, 100, 0), +(49622, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(50240, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0), +(50421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000), +(50781, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 6000), +(50871, 0, 9, 0, 1342177280, 0, 0, 2, 0, 0, 100, 0), +(51123, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(51127, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0), +(51128, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0), +(51129, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0), +(51130, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0), +(51346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(51349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(51352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(51359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(51414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(51528, 0, 0, 0, 0, 0, 0, 0, 0, 2.5, 0, 0), +(51529, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0), +(51530, 0, 0, 0, 0, 0, 0, 0, 0, 7.5, 0, 0), +(51531, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0), +(51532, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0), +(51682, 0, 8, 0, 524288, 0, 0, 0, 0, 0, 0, 0), +(51698, 0, 0, 0, 0, 0, 0, 2, 4, 0, 33, 1000), +(51700, 0, 0, 0, 0, 0, 0, 2, 4, 0, 66, 1000), +(51701, 0, 0, 0, 0, 0, 0, 2, 4, 0, 100, 1000), +(51915, 0, 0, 0, 0, 0, 16777216, 0, 0, 0, 100, 600000), +(52020, 0, 7, 32768, 1048576, 0, 0, 0, 0, 0, 0, 0), +(52420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(52423, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0), +(52437, 1, 4, 536870912, 0, 0, 16, 0, 4, 0, 0, 0), +(52898, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(53386, 48, 15, 8195, 6, 128, 349456, 0, 0, 0, 0, 0), +(53397, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(53583, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(53585, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(53601, 0, 0, 0, 0, 0, 688808, 0, 0, 0, 0, 6000), +(53646, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 20000), +(53736, 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, 0), +(54278, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(54404, 0, 0, 0, 0, 0, 0, 4, 0, 0, 100, 0), +(54486, 0, 0, 536870945, 36864, 0, 0, 0, 0, 0, 0, 0), +(54488, 0, 0, 536870945, 36864, 0, 0, 0, 0, 0, 0, 0), +(54489, 0, 0, 536870945, 36864, 0, 0, 0, 0, 0, 0, 0), +(54490, 0, 0, 536870945, 36864, 0, 0, 0, 0, 0, 0, 0), +(54646, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(54695, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(54707, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(54738, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(54754, 0, 7, 16, 0, 0, 0, 0, 0, 0, 0, 0), +(54808, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(54815, 0, 7, 32768, 0, 0, 16, 0, 0, 0, 0, 0), +(54821, 0, 7, 4096, 0, 0, 16, 0, 0, 0, 0, 0), +(54832, 0, 7, 0, 4096, 0, 16384, 0, 0, 0, 0, 0), +(54838, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(54841, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3000), +(54845, 0, 7, 4, 0, 0, 65536, 0, 0, 0, 0, 0), +(54909, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 20000), +(54925, 2, 10, 0, 512, 0, 0, 0, 0, 0, 0, 0), +(54937, 0, 10, 2147483648, 0, 0, 0, 0, 0, 0, 0, 0), +(54939, 0, 10, 32768, 0, 0, 0, 0, 0, 0, 0, 0), +(55198, 0, 11, 448, 0, 0, 16384, 2, 0, 0, 0, 0), +(55380, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(55381, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 15000), +(55440, 0, 11, 64, 0, 0, 0, 0, 0, 0, 0, 0), +(55610, 0, 15, 0, 67108864, 0, 4096, 0, 0, 0, 0, 0), +(55640, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 45000), +(55677, 0, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(55680, 0, 6, 512, 0, 0, 0, 0, 0, 0, 0, 0), +(55681, 0, 6, 32768, 0, 0, 262144, 0, 0, 0, 0, 0), +(55689, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(55717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5000), +(55747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(55768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(55776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(56218, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(56249, 0, 5, 0, 0, 1024, 0, 0, 0, 0, 0, 0), +(56355, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(56364, 0, 3, 0, 16777216, 0, 0, 0, 0, 0, 0, 0), +(56372, 0, 3, 0, 128, 0, 16384, 0, 0, 0, 0, 0), +(56374, 0, 3, 0, 16384, 0, 16384, 0, 0, 0, 0, 0), +(56375, 0, 3, 16777216, 0, 0, 65536, 0, 0, 0, 0, 0), +(56451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3000), +(56800, 0, 8, 4, 0, 0, 16, 0, 0, 0, 0, 0), +(56816, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0), +(56817, 0, 15, 0, 536870912, 0, 0, 0, 0, 0, 0, 0), +(56821, 0, 8, 2, 0, 0, 0, 2, 0, 0, 0, 0), +(56845, 0, 9, 8, 0, 0, 2097152, 0, 0, 0, 0, 0), +(57345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(57351, 0, 0, 0, 0, 0, 1782780, 0, 0, 0, 0, 0), +(57352, 0, 0, 0, 0, 0, 332116, 0, 0, 0, 0, 45000), +(57870, 0, 9, 8388608, 0, 0, 262144, 0, 0, 0, 0, 0), +(57907, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(57989, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0), +(58357, 0, 4, 64, 0, 0, 0, 2, 0, 0, 0, 0), +(58364, 0, 4, 1024, 0, 0, 0, 0, 0, 0, 0, 0), +(58372, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(58375, 0, 4, 0, 512, 0, 65552, 0, 1, 0, 100, 0), +(58386, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0), +(58410, 0, 0, 0, 0, 0, 0, 65539, 0, 0, 0, 0), +(58413, 0, 8, 0, 524288, 0, 0, 0, 0, 0, 0, 0), +(58426, 0, 8, 4196352, 0, 0, 1024, 0, 0, 0, 0, 0), +(58442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15000), +(58444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5000), +(58616, 0, 15, 16777216, 0, 0, 0, 0, 0, 0, 0, 0), +(58620, 0, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(58626, 0, 15, 33554432, 0, 0, 0, 0, 0, 0, 0, 0), +(58642, 0, 15, 0, 134217728, 0, 16, 0, 0, 0, 0, 0), +(58644, 0, 15, 0, 4, 0, 0, 0, 0, 0, 0, 0), +(58647, 0, 15, 0, 4, 0, 0, 0, 0, 0, 0, 0), +(58677, 0, 15, 8192, 0, 0, 0, 0, 0, 0, 0, 0), +(58901, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(59176, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(59327, 0, 15, 134217728, 0, 0, 0, 0, 0, 0, 0, 0), +(59345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(59630, 0, 0, 0, 0, 0, 69648, 0, 1, 0, 0, 35000), +(59725, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(59887, 0, 0, 0, 0, 0, 87040, 3, 1, 0, 0, 0), +(59888, 0, 0, 0, 0, 0, 87040, 3, 0, 0, 0, 0), +(59889, 0, 0, 0, 0, 0, 87040, 3, 0, 0, 0, 0), +(59890, 0, 0, 0, 0, 0, 87040, 3, 0, 0, 0, 0), +(59891, 0, 0, 0, 0, 0, 87040, 3, 0, 0, 0, 0), +(60061, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60063, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 45000), +(60066, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(60132, 0, 15, 16, 134348800, 0, 0, 0, 0, 0, 0, 0), +(60170, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0), +(60172, 0, 5, 262144, 0, 0, 0, 0, 0, 0, 0, 0), +(60176, 0, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0), +(60221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60317, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60436, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15000), +(60490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60493, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60503, 1, 4, 4, 0, 0, 16, 65536, 0, 0, 0, 0), +(60519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60524, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(60529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(60537, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(60564, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60571, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60572, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60573, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60574, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60575, 0, 11, 2416967680, 0, 0, 0, 0, 0, 0, 0, 0), +(60617, 0, 0, 0, 0, 0, 0, 32, 0, 0, 100, 0), +(60710, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(60717, 0, 7, 2, 0, 0, 0, 0, 0, 0, 100, 0), +(60719, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(60722, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(60724, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(60726, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(60770, 0, 11, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(60818, 0, 10, 0, 512, 0, 0, 0, 0, 0, 0, 0), +(60826, 0, 15, 20971520, 0, 0, 0, 0, 0, 0, 0, 0), +(61062, 0, 3, 0, 256, 0, 17408, 0, 0, 0, 100, 15000), +(61188, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(61257, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0), +(61324, 0, 10, 0, 131072, 0, 0, 0, 0, 0, 0, 0), +(61356, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 90000), +(61618, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(61848, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0), +(62114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(62115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(62147, 0, 15, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(62337, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0), +(62459, 0, 15, 4, 0, 0, 0, 0, 0, 0, 0, 0), +(62600, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(62933, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0), +(63086, 0, 9, 0, 0, 65536, 0, 0, 0, 0, 0, 0), +(63108, 0, 5, 2, 0, 0, 0, 262144, 0, 0, 0, 0), +(63251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(63310, 0, 5, 0, 65536, 0, 65536, 1027, 0, 0, 0, 0), +(63320, 0, 5, 2147745792, 0, 32768, 1024, 0, 0, 0, 0, 0), +(63335, 0, 15, 0, 2, 0, 0, 0, 0, 0, 0, 0), +(63611, 0, 0, 0, 0, 0, 332116, 0, 0, 0, 0, 0), +(64343, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0), +(64411, 0, 0, 0, 0, 0, 279552, 786432, 0, 0, 0, 0), +(64415, 0, 0, 0, 0, 0, 0, 524288, 0, 0, 0, 45000), +(64440, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 20000), +(64571, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10000), +(64714, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(64738, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(64742, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(64752, 0, 7, 8392704, 256, 2097152, 0, 0, 0, 0, 0, 0), +(64786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(64792, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(64824, 0, 7, 2097152, 0, 0, 0, 0, 0, 0, 0, 0), +(64860, 0, 9, 0, 1, 0, 0, 0, 0, 0, 0, 0), +(64867, 0, 3, 536870945, 4096, 0, 0, 0, 0, 0, 0, 45000), +(64882, 0, 10, 0, 1048576, 0, 0, 0, 0, 0, 0, 0), +(64890, 0, 10, 0, 65536, 0, 0, 2, 0, 0, 0, 0), +(64908, 0, 6, 8192, 0, 0, 0, 0, 0, 0, 0, 0), +(64912, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(64914, 0, 8, 65536, 0, 0, 0, 0, 0, 0, 0, 0), +(64928, 0, 11, 1, 0, 0, 0, 2, 0, 0, 0, 0), +(64936, 0, 4, 4096, 0, 0, 69632, 0, 0, 0, 100, 0), +(64938, 0, 4, 2097216, 0, 0, 0, 2, 0, 0, 0, 0), +(64952, 0, 7, 0, 1088, 0, 0, 0, 0, 0, 0, 0), +(64955, 0, 10, 0, 64, 0, 0, 0, 0, 0, 0, 0), +(64964, 0, 15, 0, 536870912, 0, 0, 0, 0, 0, 0, 0), +(64976, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0), +(64999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(65002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(65005, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 45000), +(65013, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 45000), +(65020, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(65025, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(66808, 0, 0, 0, 0, 0, 4, 0, 0, 0, 100, 0), +(66865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 3000), +(66889, 0, 0, 0, 0, 0, 4, 0, 0, 0, 100, 0), +(67115, 0, 15, 20971520, 0, 0, 0, 0, 0, 0, 0, 45000), +(67151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(67209, 1, 8, 1048576, 0, 0, 327680, 0, 0, 0, 0, 0), +(67210, 0, 8, 4294967295, 4294967295, 4294967295, 0, 0, 0, 0, 0, 0), +(67353, 0, 7, 32768, 1049856, 0, 0, 0, 0, 0, 0, 0), +(67356, 8, 7, 16, 0, 0, 0, 0, 0, 0, 0, 0), +(67361, 0, 7, 2, 0, 0, 262144, 0, 0, 0, 0, 0), +(67363, 0, 10, 2147483648, 0, 0, 0, 0, 0, 0, 0, 10000), +(67365, 0, 10, 0, 2048, 0, 262144, 0, 0, 0, 0, 6000), +(67379, 0, 10, 0, 262144, 0, 0, 0, 0, 0, 0, 0), +(67381, 0, 15, 0, 536870912, 0, 0, 0, 0, 0, 0, 10000), +(67384, 0, 15, 16, 134348800, 0, 0, 0, 0, 0, 80, 10000), +(67386, 0, 11, 1, 0, 0, 65536, 0, 1, 0, 0, 6000), +(67389, 0, 11, 256, 0, 0, 16384, 0, 1, 0, 0, 8000), +(67392, 0, 11, 0, 0, 4, 16, 0, 0, 0, 0, 0), +(67530, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 5000), +(67653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50000), +(67667, 0, 0, 0, 0, 0, 16384, 0, 1, 0, 0, 45000), +(67670, 0, 0, 0, 0, 0, 65536, 0, 1, 0, 0, 45000), +(67672, 0, 0, 0, 0, 0, 8388948, 0, 0, 0, 0, 45000), +(67698, 0, 0, 0, 0, 0, 87040, 3, 1, 0, 0, 0), +(67702, 1, 0, 0, 0, 0, 332116, 262147, 0, 0, 35, 45000), +(67712, 0, 0, 0, 0, 0, 69632, 2, 0, 0, 0, 2000), +(67752, 0, 0, 0, 0, 0, 87040, 3, 1, 0, 0, 0), +(67758, 0, 0, 0, 0, 0, 69632, 2, 0, 0, 0, 2000), +(67771, 1, 0, 0, 0, 0, 332116, 262147, 0, 0, 35, 45000), +(68051, 1, 4, 4, 0, 0, 16, 0, 0, 0, 0, 0), +(68160, 0, 0, 0, 0, 0, 4, 0, 0, 0, 100, 0), +(69056, 0, 0, 0, 0, 0, 0, 2048, 0, 0, 0, 0), +(69172, 0, 0, 4294967295, 4294967295, 4294967295, 0, 65539, 0, 0, 0, 0), +(69173, 0, 0, 4294967295, 4294967295, 4294967295, 0, 65539, 0, 0, 0, 0), +(69580, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0), +(69739, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(69755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(69762, 0, 0, 0, 0, 0, 87040, 3, 1, 0, 100, 0), +(70652, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0), +(70664, 0, 7, 16, 0, 0, 0, 0, 0, 0, 0, 0), +(70672, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(70723, 0, 7, 5, 0, 0, 65536, 2, 0, 0, 100, 0), +(70727, 0, 9, 0, 0, 0, 64, 0, 0, 0, 0, 0), +(70730, 0, 9, 16384, 4096, 0, 262144, 0, 0, 0, 0, 0), +(70748, 0, 3, 0, 2097152, 0, 1024, 0, 0, 0, 0, 0), +(70756, 0, 10, 2097152, 65536, 0, 0, 0, 0, 0, 0, 0), +(70761, 0, 10, 0, 2147500032, 1, 1024, 0, 0, 0, 0, 0), +(70803, 0, 8, 4063232, 8, 0, 0, 0, 0, 0, 0, 0), +(70805, 0, 8, 0, 131072, 0, 0, 0, 0, 0, 0, 1000), +(70807, 0, 11, 0, 0, 16, 0, 0, 0, 0, 100, 0), +(70808, 0, 11, 256, 0, 0, 0, 2, 0, 0, 0, 0), +(70811, 0, 11, 3, 0, 0, 0, 0, 1, 0, 0, 0), +(70817, 0, 11, 0, 4096, 0, 65536, 0, 0, 0, 0, 0), +(70830, 0, 11, 0, 131072, 0, 0, 0, 0, 0, 0, 0), +(70841, 0, 5, 4, 256, 0, 262144, 0, 0, 0, 0, 0), +(70844, 0, 4, 256, 0, 0, 0, 0, 0, 0, 0, 0), +(70854, 0, 4, 0, 16, 0, 0, 0, 0, 0, 0, 0), +(70871, 0, 0, 0, 0, 0, 69972, 3, 0, 0, 100, 0), +(71039, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(71174, 0, 7, 4096, 256, 0, 262144, 0, 0, 0, 0, 0), +(71176, 0, 7, 2097154, 0, 0, 262144, 0, 0, 0, 0, 0), +(71178, 0, 7, 16, 0, 0, 262144, 0, 0, 0, 0, 0), +(71186, 0, 10, 0, 32768, 0, 0, 0, 0, 0, 0, 0), +(71191, 0, 10, 0, 65536, 0, 0, 0, 0, 0, 0, 0), +(71194, 0, 10, 0, 1048576, 0, 0, 0, 0, 0, 0, 0), +(71198, 0, 11, 268435456, 0, 0, 0, 0, 0, 0, 0, 0), +(71214, 0, 11, 5120, 16, 0, 16, 0, 0, 0, 0, 6000), +(71217, 0, 11, 0, 0, 16, 16384, 0, 0, 0, 0, 0), +(71226, 0, 15, 16, 134348800, 0, 0, 0, 0, 0, 0, 0), +(71228, 0, 15, 0, 536870912, 0, 0, 0, 0, 0, 0, 0), +(71402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(71404, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 50000), +(71406, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0), +(71494, 0, 0, 0, 0, 0, 0, 16255, 0, 0, 0, 0), +(71519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105000), +(71540, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(71545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0), +(71562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105000), +(71564, 126, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0), +(71567, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 400), +(71585, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 45000), +(71604, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 100, 10000), +(71606, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100000), +(71611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(71634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(71637, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100000), +(71640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000), +(71642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(71645, 0, 0, 0, 0, 0, 65536, 3, 1, 0, 0, 45000), +(71770, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(71865, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0), +(71868, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0), +(71880, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(71892, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), +(71903, 0, 0, 0, 0, 0, 0, 1049603, 0, 0, 75, 0), +(72059, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0), +(72176, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(72178, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(72256, 0, 0, 0, 0, 0, 4, 65536, 0, 0, 0, 0), +(72413, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60000), +(72417, 0, 0, 0, 0, 0, 327680, 0, 0, 0, 0, 60000), +(72455, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(72673, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 100, 10000), +(72674, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 100, 10000), +(72675, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 100, 10000), +(72832, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(72833, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(73878, 0, 0, 0, 0, 0, 0, 65536, 0, 0, 0, 0), +(74396, 84, 3, 685904631, 1151040, 0, 65536, 3, 0, 0, 0, 0), +(75455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(75457, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(16372, 0, 0, 0, 0, 0, 131072, 1, 0, 0, 100, 0), +(75475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(75481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45000), +(71761, 0, 3, 0, 1048576, 0, 0, 256, 0, 0, 0, 0), +(56841, 0, 9, 2048, 2048, 2048, 256, 0, 0, 0, 0, 0), +(16166, 0, 11, 3, 4096, 0, 0, 0, 1, 0, 0, 0), +(16188, 8, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(16246, 0, 11, 2551185859, 5120, 16, 87376, 0, 1, 0, 0, 0), +(17116, 8, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(4341, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(28200, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(63280, 0, 11, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(65007, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), +(21747, 0, 10, 0, 0, 0, 20, 0, 0, 20, 0, 50000), +(-16689, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1000), +(71756, 0, 0, 0, 0, 0, 0, 1027, 2, 0, 0, 0); + +-- Restoring the command +DELETE FROM `command` WHERE `name`='reload spell_proc_event'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES +('reload spell_proc_event', 3, 'Syntax: .reload spell_proc_event\nReload spell_proc_event table.'); + +DELETE FROM `updates` WHERE `name` = '2022_10_02_01.sql'; diff --git a/src/server/game/Combat/ThreatMgr.cpp b/src/server/game/Combat/ThreatMgr.cpp index 51c38a0ce..91751f22a 100644 --- a/src/server/game/Combat/ThreatMgr.cpp +++ b/src/server/game/Combat/ThreatMgr.cpp @@ -46,7 +46,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMas return threat; if (Player* modOwner = hatedUnit->GetSpellModOwner()) - modOwner->ApplySpellMod(threatSpell->Id, threat); + modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat); } return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 6b9c4b666..512e7c39e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2751,8 +2751,8 @@ void Creature::AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_t uint32 categorycooldown = categoryId ? spellInfo->CategoryRecoveryTime : 0; if (Player* modOwner = GetSpellModOwner()) { - modOwner->ApplySpellMod(spellInfo->Id, spellcooldown); - modOwner->ApplySpellMod(spellInfo->Id, categorycooldown); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, spellcooldown); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, categorycooldown); } SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e152cfe42..79d8565cd 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -764,7 +764,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) case DAMAGE_LAVA: case DAMAGE_SLIME: { - DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK); + DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE); Unit::CalcAbsorbResist(dmgInfo); absorb = dmgInfo.GetAbsorb(); resist = dmgInfo.GetResist(); @@ -7058,22 +7058,21 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, } } -void Player::CastItemCombatSpell(DamageInfo const& damageInfo) +void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx) { - Unit* target = damageInfo.GetVictim(); if (!target || !target->IsAlive() || target == this) return; // Xinef: do not use disarmed weapons, special exception - shaman ghost wolf form // Xinef: normal forms proc on hit enchants / built in item bonuses - if (!CanUseAttackType(damageInfo.GetAttackType()) || GetShapeshiftForm() == FORM_GHOSTWOLF) + if (!CanUseAttackType(attType) || GetShapeshiftForm() == FORM_GHOSTWOLF) return; for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { // If usable, try to cast item spell if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType())) + if (!item->IsBroken()) if (ItemTemplate const* proto = item->GetTemplate()) { // Additional check for weapons @@ -7081,7 +7080,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo) { // offhand item cannot proc from main hand hit etc EquipmentSlots slot; - switch (damageInfo.GetAttackType()) + switch (attType) { case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; @@ -7100,20 +7099,19 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo) continue; } - CastItemCombatSpell(damageInfo, item, proto); + CastItemCombatSpell(target, attType, procVictim, procEx, item, proto); } } } -void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto) +void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto) { -// if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto)) -// return; + if (!sScriptMgr->CanCastItemCombatSpell(this, target, attType, procVictim, procEx, item, proto)) + return; // Can do effect if any damage done to target - // for done procs allow normal + critical + absorbs by default - bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0; - if (canTrigger) + if (procVictim & PROC_FLAG_TAKEN_DAMAGE) + //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) { for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i) { @@ -7134,15 +7132,11 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT continue; } - // not allow proc extra attack spell at extra attack - if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - return; - float chance = (float)spellInfo->ProcChance; if (spellData.SpellPPMRate) { - uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType()); + uint32 WeaponSpeed = GetAttackTime(attType); chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo); } else if (chance > 100.0f) @@ -7150,8 +7144,8 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT chance = GetWeaponProcChance(); } - if (roll_chance_f(chance)/* && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item)*/) - CastSpell(damageInfo.GetVictim(), spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); + if (roll_chance_f(chance) && sScriptMgr->OnCastItemCombatSpell(this, target, spellInfo, item)) + CastSpell(target, spellInfo->Id, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); } } @@ -7173,14 +7167,14 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT if (entry && entry->procEx) { // Check hit/crit/dodge/parry requirement - if ((entry->procEx & damageInfo.GetHitMask()) == 0) + if ((entry->procEx & procEx) == 0) continue; } else { // Can do effect if any damage done to target - // for done procs allow normal + critical + absorbs by default - if (!canTrigger) + if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE)) + //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)) continue; } @@ -7203,7 +7197,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT } // Apply spell mods - ApplySpellMod(pEnchant->spellid[s], chance); + ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance); // Shiv has 100% chance to apply the poison if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT) @@ -7226,7 +7220,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT if (spellInfo->IsPositive()) CastSpell(this, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); else - CastSpell(damageInfo.GetVictim(), spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); + CastSpell(target, spellInfo, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), item); } } } @@ -9571,11 +9565,9 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod if (!mod || !spellInfo) return false; - // First time this aura applies a mod to us and is out of charges - if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura)) - { + // Mod out of charges + if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end()) return false; - } // +duration to infinite duration spells making them limited if (mod->op == SPELLMOD_DURATION && spellInfo->GetDuration() == -1) @@ -9617,46 +9609,50 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) LOG_DEBUG("spells.aura", "Player::AddSpellMod {}", mod->spellId); uint16 Opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; - flag96 modMask; - for (uint8 i = 0; i < 3; ++i) + int i = 0; + flag96 _mask = 0; + for (int eff = 0; eff < 96; ++eff) { - for (uint32 eff = 0; eff < 32; ++eff) - { - modMask[i] = uint32(1) << eff; - if ((mod->mask & modMask)) - { - int32 val = 0; - for (SpellModifier* spellMod : m_spellMods[mod->op]) - { - if (spellMod->type == mod->type && (spellMod->mask & modMask)) - { - val += spellMod->value; - } - } - val += apply ? mod->value : -(mod->value); - WorldPacket data(Opcode, (1 + 1 + 4)); - data << uint8(eff + 32 * i); - data << uint8(mod->op); - data << int32(val); - SendDirectMessage(&data); - } - } + if (eff != 0 && eff % 32 == 0) + _mask[i++] = 0; - modMask[i] = 0; + _mask[i] = uint32(1) << (eff - (32 * i)); + if (mod->mask & _mask) + { + int32 val = 0; + for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) + { + if ((*itr)->type == mod->type && (*itr)->mask & _mask) + val += (*itr)->value; + } + val += apply ? mod->value : -(mod->value); + WorldPacket data(Opcode, (1 + 1 + 4)); + data << uint8(eff); + data << uint8(mod->op); + data << int32(val); + SendDirectMessage(&data); + } } if (apply) { - m_spellMods[mod->op].insert(mod); + m_spellMods[mod->op].push_back(mod); + if (getClass() == CLASS_MAGE) + m_spellMods[mod->op].sort(MageSpellModPred()); + else + m_spellMods[mod->op].sort(SpellModPred()); } else { - m_spellMods[mod->op].erase(mod); + m_spellMods[mod->op].remove(mod); + // mods bound to aura will be removed in AuraEffect::~AuraEffect + if (!mod->ownerAura) + delete mod; } } // Restore spellmods in case of failed cast -void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/) +void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) { if (!spell || spell->m_appliedMods.empty()) return; @@ -9665,16 +9661,16 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* au for (uint8 i = 0; i < MAX_SPELLMOD; ++i) { - for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr) + for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr) { SpellModifier* mod = *itr; - // Spellmods without charged aura set cannot be charged - if (!mod->ownerAura->IsUsingCharges()) + // Spellmods without aura set cannot be charged + if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges()) continue; // Restore only specific owner aura mods - if (ownerAuraId && mod->spellId != ownerAuraId) + if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id)) continue; if (aura && mod->ownerAura != aura) @@ -9695,14 +9691,27 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* au // only see the first of its modifier restored) aurasQueue.push_back(mod->ownerAura); - // add charges back to aura - mod->ownerAura->ModCharges(1); + // add mod charges back to mod + if (mod->charges == -1) + mod->charges = 1; + else + mod->charges++; + + // Do not set more spellmods than available + if (mod->ownerAura->GetCharges() < mod->charges) + mod->charges = mod->ownerAura->GetCharges(); + + // Skip this check for now - aura charges may change due to various reason + /// @todo track these changes correctly + //ASSERT (mod->ownerAura->GetCharges() <= mod->charges); } } - for (Aura* aura : aurasQueue) + for (std::list::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr) { - spell->m_appliedMods.erase(aura); + Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr); + if (iterMod != spell->m_appliedMods.end()) + spell->m_appliedMods.erase(iterMod); } // Xinef: clear the list just do be sure @@ -9710,32 +9719,77 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* au spell->m_appliedMods.clear(); } -void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/) +void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura) { for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i) - if (Spell* spell = m_currentSpells[i]) - RestoreSpellMods(spell, ownerAuraId, aura); + if (m_currentSpells[i]) + RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura); } -void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell) +void Player::RemoveSpellMods(Spell* spell) { if (!spell) return; - // don't do anything with no charges - if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges()) + if (spell->m_appliedMods.empty()) return; - // register inside spell, proc system uses this to drop charges - spell->m_appliedMods.insert(mod->ownerAura); + SpellInfo const* const spellInfo = spell->m_spellInfo; + + for (uint8 i = 0; i < MAX_SPELLMOD; ++i) + { + for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();) + { + SpellModifier* mod = *itr; + ++itr; + + // spellmods without aura set cannot be charged + if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges()) + continue; + + // check if mod affected this spell + Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura); + if (iterMod == spell->m_appliedMods.end()) + continue; + + // remove from list + // leave this here, if spell have two mods it will remove 2 charges - wrong + spell->m_appliedMods.erase(iterMod); + + // MAGE T8P4 BONUS + if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE ) + { + SpellInfo const* sp = mod->ownerAura->GetSpellInfo(); + // Missile Barrage, Hot Streak, Brain Freeze (trigger spell - Fireball!) + if( sp->SpellIconID == 3261 || sp->SpellIconID == 2999 || sp->SpellIconID == 2938 ) + if( AuraEffect* aurEff = GetAuraEffectDummy(64869) ) + if( roll_chance_i(aurEff->GetAmount()) ) + { + mod->charges = 1; + continue; + } + } + + if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE)) + itr = m_spellMods[i].begin(); + } + } } -bool Player::HasSpellModApplied(SpellModifier* mod, Spell* spell) +void Player::DropModCharge(SpellModifier* mod, Spell* spell) { - if (!spell) - return false; + // don't handle spells with proc_event entry defined + // this is a temporary workaround, because all spellmods should be handled like that + if (sSpellMgr->GetSpellProcEvent(mod->spellId)) + return; - return spell->m_appliedMods.count(mod->ownerAura) != 0; + if (spell && mod->ownerAura && mod->charges > 0) + { + if (--mod->charges == 0) + mod->charges = -1; + + spell->m_appliedMods.insert(mod->ownerAura); + } } void Player::SetSpellModTakingSpell(Spell* spell, bool apply) @@ -10633,7 +10687,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (rec > 0) { int32 oldRec = rec; - ApplySpellMod(spellInfo->Id, rec, spell); + ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell); if (oldRec != rec) { useSpellCooldown = true; @@ -10642,7 +10696,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS)) { - ApplySpellMod(spellInfo->Id, catrec, spell); + ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell); } if (int32 cooldownMod = GetTotalAuraModifier(SPELL_AURA_MOD_COOLDOWN)) @@ -11418,7 +11472,6 @@ void Player::ApplyEquipCooldown(Item* pItem) if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_NO_EQUIP_COOLDOWN)) return; - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { _Spell const& spellData = pItem->GetTemplate()->Spells[i]; @@ -11427,15 +11480,11 @@ void Player::ApplyEquipCooldown(Item* pItem) if (!spellData.SpellId) continue; - // apply proc cooldown to equip auras if we have any + // xinef: apply hidden cooldown for procs if (spellData.SpellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP) { - SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(spellData.SpellId); - if (!procEntry) - continue; - - if (Aura* itemAura = GetAura(spellData.SpellId, GetGUID(), pItem->GetGUID())) - itemAura->AddProcCooldown(now + procEntry->Cooldown); + // xinef: uint32(-1) special marker for proc cooldowns + AddSpellCooldown(spellData.SpellId, uint32(-1), 30 * IN_MILLISECONDS); continue; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b0b03bbc4..73a652459 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -89,10 +89,10 @@ typedef void(*bgZoneRef)(Battleground*, WorldPacket&); #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) // Note: SPELLMOD_* values is aura types in fact -enum SpellModType : uint8 +enum SpellModType { - SPELLMOD_FLAT = SPELL_AURA_ADD_FLAT_MODIFIER, - SPELLMOD_PCT = SPELL_AURA_ADD_PCT_MODIFIER + SPELLMOD_FLAT = 107, // SPELL_AURA_ADD_FLAT_MODIFIER + SPELLMOD_PCT = 108 // SPELL_AURA_ADD_PCT_MODIFIER }; // 2^n values, Player::m_isunderwater is a bitmask. These are Trinity internal values, they are never send to any client @@ -180,9 +180,10 @@ enum TalentTree // talent tabs // Spell modifier (used for modify other spells) struct SpellModifier { - SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), mask(), ownerAura(_ownerAura) {} - SpellModOp op; - SpellModType type; + SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), mask(), ownerAura(_ownerAura) {} + SpellModOp op : 8; + SpellModType type : 8; + int16 charges : 16; int32 value{0}; flag96 mask; uint32 spellId{0}; @@ -191,7 +192,7 @@ struct SpellModifier typedef std::unordered_map PlayerTalentMap; typedef std::unordered_map PlayerSpellMap; -typedef std::unordered_set SpellModContainer; +typedef std::list SpellModList; typedef GuidList WhisperListContainer; @@ -1729,14 +1730,13 @@ public: SpellCooldowns& GetSpellCooldownMap() { return m_spellCooldowns; } void AddSpellMod(SpellModifier* mod, bool apply); - static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); + bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); bool HasSpellMod(SpellModifier* mod, Spell* spell); - template - void ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell = nullptr) const; + template T ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr, bool temporaryPet = false); + void RemoveSpellMods(Spell* spell); void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr); void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr); - static void ApplyModToSpell(SpellModifier* mod, Spell* spell); - static bool HasSpellModApplied(SpellModifier* mod, Spell* spell); + void DropModCharge(SpellModifier* mod, Spell* spell); void SetSpellModTakingSpell(Spell* spell, bool apply); [[nodiscard]] bool HasSpellCooldown(uint32 spell_id) const override; @@ -2166,9 +2166,9 @@ public: void ApplyItemEquipSpell(Item* item, bool apply, bool form_change = false); void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool form_change = false); void UpdateEquipSpellsAtFormChange(); - void CastItemCombatSpell(DamageInfo const& damageInfo); - void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto); + void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx); void CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex); + void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto); void SendEquipmentSetList(); void SetEquipmentSet(uint32 index, EquipmentSet eqset); @@ -2551,7 +2551,7 @@ public: // mt maps [[nodiscard]] const PlayerTalentMap& GetTalentMap() const { return m_talents; } [[nodiscard]] uint32 GetNextSave() const { return m_nextSave; } - [[nodiscard]] SpellModContainer const& GetSpellModContainer(uint32 type) const { return m_spellMods[type]; } + [[nodiscard]] SpellModList const& GetSpellModList(uint32 type) const { return m_spellMods[type]; } void SetServerSideVisibility(ServerSideVisibilityType type, AccountTypes sec); void SetServerSideVisibilityDetect(ServerSideVisibilityType type, AccountTypes sec); @@ -2756,7 +2756,7 @@ public: uint32 m_baseHealthRegen; int32 m_spellPenetrationItemMod; - SpellModContainer m_spellMods[MAX_SPELLMOD]; + SpellModList m_spellMods[MAX_SPELLMOD]; //uint32 m_pad; // Spell* m_spellModTakingSpell; // Spell for which charges are dropped in spell::finish @@ -2940,132 +2940,130 @@ void AddItemsSetItem(Player* player, Item* item); void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); // "the bodies of template functions must be made available in a header file" -template -void Player::ApplySpellMod(uint32 spellId, T& basevalue, Spell* spell) const +template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell, bool temporaryPet) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) - return; + { + return 0; + } - float totalmul = 1.f; + float totalmul = 1.0f; int32 totalflat = 0; + auto calculateSpellMod = [&](SpellModifier* mod) + { + // xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras + if (temporaryPet && mod->charges != 0) + { + return; + } + + if (mod->type == SPELLMOD_FLAT) + { + // xinef: do not allow to consume more than one 100% crit increasing spell + if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100) + { + return; + } + + int32 flatValue = mod->value; + + // SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100) + if (mod->op == SPELLMOD_THREAT) + { + flatValue /= 100; + } + + totalflat += flatValue; + } + else if (mod->type == SPELLMOD_PCT) + { + // skip percent mods for null basevalue (most important for spell mods with charges) + if (basevalue == T(0) || totalmul == 0.0f) + { + return; + } + + // special case (skip > 10sec spell casts for instant cast setting) + if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) + { + return; + } + // xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied + else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) + { + return; + } + // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied + else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) + { + return; + } + + // xinef: those two mods should be multiplicative (Glyph of Renew) + if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) + { + totalmul *= CalculatePct(1.0f, 100.0f + mod->value); + } + else + { + totalmul += CalculatePct(1.0f, mod->value); + } + } + + DropModCharge(mod, spell); + }; + // Drop charges for triggering spells instead of triggered ones if (m_spellModTakingSpell) - spell = m_spellModTakingSpell; - - switch (op) { - // special case, if a mod makes spell instant, only consume that mod - case SPELLMOD_CASTING_TIME: - { - SpellModifier* modInstantSpell = nullptr; - for (SpellModifier* mod : m_spellMods[SPELLMOD_CASTING_TIME]) - { - if (!IsAffectedBySpellmod(spellInfo, mod, spell)) - { - continue; - } - - if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100) - { - modInstantSpell = mod; - break; - } - } - - if (modInstantSpell) - { - Player::ApplyModToSpell(modInstantSpell, spell); - basevalue = T(0); - return; - } - break; - } - - // special case if two mods apply 100% critical chance, only consume one - case SPELLMOD_CRITICAL_CHANCE: - { - SpellModifier* modCritical = nullptr; - for (auto mod : m_spellMods[SPELLMOD_CRITICAL_CHANCE]) - { - if (!IsAffectedBySpellmod(spellInfo, mod, spell)) - { - continue; - } - - if (mod->type == SPELLMOD_FLAT && mod->value >= 100) - { - modCritical = mod; - break; - } - } - - if (modCritical) - { - Player::ApplyModToSpell(modCritical, spell); - basevalue = T(100); - return; - } - break; - } - - default: - break; + spell = m_spellModTakingSpell; } + SpellModifier* chargedMod = nullptr; for (auto mod : m_spellMods[op]) { - if (!IsAffectedBySpellmod(spellInfo, mod, spell)) - continue; - - switch (mod->type) + // Charges can be set only for mods with auras + if (!mod->ownerAura) { - case SPELLMOD_FLAT: - totalflat += mod->value; - break; - case SPELLMOD_PCT: - { - // skip percent mods for null basevalue (most important for spell mods with charges) - if (basevalue == T(0)) - { - continue; - } - - // special case (skip > 10s spell casts for instant cast setting) - if (op == SPELLMOD_CASTING_TIME) - { - if (mod->value <= -100 && basevalue >= T(10000)) - { - continue; - } - } - - totalmul += CalculatePct(1.f, mod->value); - break; - } + ASSERT(!mod->charges); } - /*// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied - else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) + if (!IsAffectedBySpellmod(spellInfo, mod, spell)) + { continue; - // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied - else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) - continue; - // xinef: those two mods should be multiplicative (Glyph of Renew) - if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) - totalmul *= CalculatePct(1.0f, 100.0f + mod->value); - else - totalmul += CalculatePct(1.0f, mod->value);*/ + } - Player::ApplyModToSpell(mod, spell); + if (mod->ownerAura->IsUsingCharges()) + { + if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority)) + { + chargedMod = mod; + } + + continue; + } + + calculateSpellMod(mod); } + + if (chargedMod) + { + calculateSpellMod(chargedMod); + } + float diff = 0.0f; if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION) + { diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat; + } else + { diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat; - basevalue = T((float)basevalue + diff); -} + } + basevalue = T((float)basevalue + diff); + return T(diff); +} #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2ab51a89e..d190cbdcd 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -98,92 +98,44 @@ float playerBaseMoveSpeed[MAX_MOVE_TYPE] = 3.14f // MOVE_PITCH_RATE }; -DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType, uint32 cleanDamage) - : m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), - m_damageType(damageType), m_attackType(attackType), m_absorb(0), m_resist(0), m_block(0), m_hitMask(0), m_cleanDamage(cleanDamage) +// Used for prepare can/can`t triggr aura +static bool InitTriggerAuraData(); +// Define can trigger auras +static bool isTriggerAura[TOTAL_AURAS]; +// Define can't trigger auras (need for disable second trigger) +static bool isNonTriggerAura[TOTAL_AURAS]; +// Triggered always, even from triggered spells +static bool isAlwaysTriggeredAura[TOTAL_AURAS]; +// Prepare lists +static bool procPrepared = InitTriggerAuraData(); + +DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage) + : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask), + m_damageType(_damageType), m_attackType(BASE_ATTACK), m_cleanDamage(cleanDamage) { + m_absorb = 0; + m_resist = 0; + m_block = 0; } DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo) : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)), m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.absorb), m_resist(dmgInfo.resist), m_block(dmgInfo.blocked_amount), - m_hitMask(0), m_cleanDamage(dmgInfo.cleanDamage) + m_cleanDamage(dmgInfo.cleanDamage) { - switch (dmgInfo.TargetState) - { - case VICTIMSTATE_IS_IMMUNE: - m_hitMask |= PROC_HIT_IMMUNE; - break; - case VICTIMSTATE_BLOCKS: - m_hitMask |= PROC_HIT_FULL_BLOCK; - break; - } - - if (dmgInfo.HitInfo & (HITINFO_PARTIAL_ABSORB | HITINFO_FULL_ABSORB)) - { - m_hitMask |= PROC_HIT_ABSORB; - } - - if (dmgInfo.HitInfo & HITINFO_FULL_RESIST) - { - m_hitMask |= PROC_HIT_FULL_RESIST; - } - - if (m_block) - { - m_hitMask |= PROC_HIT_BLOCK; - } - - bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || - (m_hitMask & (PROC_HIT_IMMUNE | PROC_HIT_FULL_BLOCK)) != 0; - - switch (dmgInfo.hitOutCome) - { - case MELEE_HIT_MISS: - m_hitMask |= PROC_HIT_MISS; - break; - case MELEE_HIT_DODGE: - m_hitMask |= PROC_HIT_DODGE; - break; - case MELEE_HIT_PARRY: - m_hitMask |= PROC_HIT_PARRY; - break; - case MELEE_HIT_EVADE: - m_hitMask |= PROC_HIT_EVADE; - break; - case MELEE_HIT_BLOCK: - case MELEE_HIT_CRUSHING: - case MELEE_HIT_GLANCING: - case MELEE_HIT_NORMAL: - if (!damageNullified) - m_hitMask |= PROC_HIT_NORMAL; - break; - case MELEE_HIT_CRIT: - if (!damageNullified) - m_hitMask |= PROC_HIT_CRITICAL; - break; - } } -DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 /* hitMask */) +DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType) : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_spellInfo(spellNonMeleeDamage.spellInfo), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType), - m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), - m_hitMask(0), m_cleanDamage(spellNonMeleeDamage.cleanDamage) + m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), + m_cleanDamage(spellNonMeleeDamage.cleanDamage) { - if (spellNonMeleeDamage.blocked) - { - m_hitMask |= PROC_HIT_BLOCK; - } - if (spellNonMeleeDamage.absorb) - { - m_hitMask |= PROC_HIT_ABSORB; - } } void DamageInfo::ModifyDamage(int32 amount) { - amount = std::max(amount, -static_cast(GetDamage())); + amount = std::min(amount, int32(GetDamage())); m_damage += amount; } @@ -192,7 +144,6 @@ void DamageInfo::AbsorbDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_absorb += amount; m_damage -= amount; - m_hitMask |= PROC_HIT_ABSORB; } void DamageInfo::ResistDamage(uint32 amount) @@ -200,11 +151,6 @@ void DamageInfo::ResistDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_resist += amount; m_damage -= amount; - if (!m_damage) - { - m_hitMask |= PROC_HIT_FULL_RESIST; - m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL); - } } void DamageInfo::BlockDamage(uint32 amount) @@ -212,37 +158,6 @@ void DamageInfo::BlockDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_block += amount; m_damage -= amount; - m_hitMask |= PROC_HIT_BLOCK; - if (!m_damage) - { - m_hitMask |= PROC_HIT_FULL_BLOCK; - m_hitMask &= ~(PROC_HIT_NORMAL | PROC_HIT_CRITICAL); - } -} - -uint32 DamageInfo::GetHitMask() const -{ - return m_hitMask; -} - -HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask) - : m_healer(healer), m_target(target), m_heal(heal), m_effectiveHeal(0), m_absorb(0), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_hitMask(0) -{ -} - -void HealInfo::AbsorbHeal(uint32 amount) -{ - amount = std::min(amount, GetHeal()); - m_absorb += amount; - m_heal -= amount; - amount = std::min(amount, GetEffectiveHeal()); - m_effectiveHeal -= amount; - m_hitMask |= PROC_HIT_ABSORB; -} - -uint32 HealInfo::GetHitMask() const -{ - return m_hitMask; } uint32 DamageInfo::GetUnmitigatedDamage() const @@ -316,7 +231,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; - m_extraAttacks = 0; m_canDualWield = false; m_rootTimes = 0; @@ -403,6 +317,8 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), _oldFactionId = 0; _isWalkingBeforeCharm = false; + + _lastExtraAttackSpell = 0; } //////////////////////////////////////////////////////////// @@ -528,6 +444,23 @@ void Unit::Update(uint32 p_time) } } + _lastDamagedTargetGuid = ObjectGuid::Empty; + if (_lastExtraAttackSpell) + { + while (!extraAttacksTargets.empty()) + { + auto itr = extraAttacksTargets.begin(); + ObjectGuid targetGuid = itr->first; + uint32 count = itr->second; + extraAttacksTargets.erase(itr); + if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid)) + { + HandleProcExtraAttackFor(victim, count); + } + } + _lastExtraAttackSpell = 0; + } + // not implemented before 3.0.2 // xinef: if attack time > 0, reduce by diff // if on next update, attack time < 0 assume player didnt attack - set to 0 @@ -960,7 +893,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage } else { - DamageInfo sharedDamageInfo(attacker, shareDamageTarget, shareDamage, spellProto, damageSchoolMask, damagetype, BASE_ATTACK); + DamageInfo sharedDamageInfo(attacker, shareDamageTarget, shareDamage, spellProto, damageSchoolMask, damagetype); Unit::CalcAbsorbResist(sharedDamageInfo, true); shareAbsorb = sharedDamageInfo.GetAbsorb(); shareResist = sharedDamageInfo.GetResist(); @@ -1089,7 +1022,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage //if (attacker && victim->GetTypeId() == TYPEID_PLAYER && victim != attacker) //victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); // pussywizard: optimization - Unit::Kill(attacker, victim, durabilityLoss, cleanDamage ? cleanDamage->attackType : BASE_ATTACK, spellProto); + Unit::Kill(attacker, victim, durabilityLoss, cleanDamage ? cleanDamage->attackType : BASE_ATTACK, spellProto, damageSpell); } else { @@ -1386,7 +1319,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama uint32 crit_bonus = damage; // Apply crit_damage bonus for melee spells if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, crit_bonus); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); damage += crit_bonus; // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE @@ -1413,11 +1346,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // double blocked amount if block is critical if (victim->isBlockCritical()) damageInfo->blocked *= 2; - if (damage <= int32(damageInfo->blocked)) - { + if (damage < int32(damageInfo->blocked)) damageInfo->blocked = uint32(damage); - damageInfo->fullBlock = true; - } damage -= damageInfo->blocked; cleanDamage += damageInfo->blocked; @@ -1471,18 +1401,14 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->damage = std::max(0, damage); // Calculate absorb resist - DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE); - Unit::CalcAbsorbResist(dmgInfo); - damageInfo->absorb = dmgInfo.GetAbsorb(); - damageInfo->resist = dmgInfo.GetResist(); - - if (damageInfo->absorb) - damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); - - if (damageInfo->resist) - damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); - - damageInfo->damage = dmgInfo.GetDamage(); + if (damageInfo->damage > 0) + { + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); + damageInfo->damage = dmgInfo.GetDamage(); + } } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell /*= nullptr*/) @@ -1527,6 +1453,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo = 0; damageInfo->procAttacker = PROC_FLAG_NONE; damageInfo->procVictim = PROC_FLAG_NONE; + damageInfo->procEx = PROC_EX_NONE; damageInfo->hitOutCome = MELEE_HIT_EVADE; if (!victim) @@ -1557,6 +1484,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam damageInfo->HitInfo |= HITINFO_NORMALSWING; damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE; + damageInfo->procEx |= PROC_EX_IMMUNE; return; } @@ -1589,23 +1517,27 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam case MELEE_HIT_EVADE: damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND; damageInfo->TargetState = VICTIMSTATE_EVADES; + damageInfo->procEx |= PROC_EX_EVADE; damageInfo->damage = 0; damageInfo->cleanDamage = 0; return; case MELEE_HIT_MISS: damageInfo->HitInfo |= HITINFO_MISS; damageInfo->TargetState = VICTIMSTATE_INTACT; + damageInfo->procEx |= PROC_EX_MISS; damageInfo->damage = 0; damageInfo->cleanDamage = 0; break; case MELEE_HIT_NORMAL: damageInfo->TargetState = VICTIMSTATE_HIT; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; break; case MELEE_HIT_CRIT: { damageInfo->HitInfo |= HITINFO_CRITICALHIT; damageInfo->TargetState = VICTIMSTATE_HIT; + damageInfo->procEx |= PROC_EX_CRITICAL_HIT; // Crit bonus calc damageInfo->damage += damageInfo->damage; float mod = 0.0f; @@ -1630,17 +1562,20 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam } case MELEE_HIT_PARRY: damageInfo->TargetState = VICTIMSTATE_PARRY; + damageInfo->procEx |= PROC_EX_PARRY; damageInfo->cleanDamage += damageInfo->damage; damageInfo->damage = 0; break; case MELEE_HIT_DODGE: damageInfo->TargetState = VICTIMSTATE_DODGE; + damageInfo->procEx |= PROC_EX_DODGE; damageInfo->cleanDamage += damageInfo->damage; damageInfo->damage = 0; break; case MELEE_HIT_BLOCK: damageInfo->TargetState = VICTIMSTATE_HIT; damageInfo->HitInfo |= HITINFO_BLOCK; + damageInfo->procEx |= PROC_EX_BLOCK; damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); // double blocked amount if block is critical if (damageInfo->target->isBlockCritical()) @@ -1649,8 +1584,10 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam { damageInfo->TargetState = VICTIMSTATE_BLOCKS; damageInfo->blocked_amount = damageInfo->damage; + damageInfo->procEx |= PROC_EX_FULL_BLOCK; } - + else + damageInfo->procEx |= PROC_EX_NORMAL_HIT; damageInfo->damage -= damageInfo->blocked_amount; damageInfo->cleanDamage += damageInfo->blocked_amount; break; @@ -1658,6 +1595,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam { damageInfo->HitInfo |= HITINFO_GLANCING; damageInfo->TargetState = VICTIMSTATE_HIT; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; int32 leveldif = int32(victim->getLevel()) - int32(getLevel()); if (leveldif > 3) leveldif = 3; @@ -1669,6 +1607,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam case MELEE_HIT_CRUSHING: damageInfo->HitInfo |= HITINFO_CRUSHING; damageInfo->TargetState = VICTIMSTATE_HIT; + damageInfo->procEx |= PROC_EX_NORMAL_HIT; // 150% normal damage damageInfo->damage += (damageInfo->damage / 2); break; @@ -1710,6 +1649,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam if (damageInfo->absorb) { damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); + damageInfo->procEx |= PROC_EX_ABSORB; } if (damageInfo->resist) @@ -1795,10 +1735,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) } if (GetTypeId() == TYPEID_PLAYER) - { - DamageInfo dmgInfo(*damageInfo); - ToPlayer()->CastItemCombatSpell(dmgInfo); - } + ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx); // Do effect if any damage done to target if (damageInfo->damage) @@ -1833,7 +1770,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) uint32 absorb = 0; - DamageInfo dmgInfo(victim, this, damage, i_spellProto, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); + DamageInfo dmgInfo(victim, this, damage, i_spellProto, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE); Unit::CalcAbsorbResist(dmgInfo); absorb = dmgInfo.GetAbsorb(); damage = dmgInfo.GetDamage(); @@ -1899,7 +1836,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, co if (spellInfo) if (Player* modOwner = attacker->GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, armor); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor); AuraEffectList const& ResIgnoreAurasAb = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j) @@ -2077,25 +2014,31 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) } // Ignore Absorption Auras - float auraAbsorbMod = victim->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, dmgInfo.GetSchoolMask());; - AuraEffectList const& abilityAbsorbAuras = victim->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); - for (AuraEffect const* aurEff : abilityAbsorbAuras) + float auraAbsorbMod = 0; + if (attacker) { - if (!(aurEff->GetMiscValue() & schoolMask)) - continue; + AuraEffectList const& AbsIgnoreAurasA = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL); + for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr) + { + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; - if (!aurEff->IsAffectedOnSpell(spellInfo)) - continue; + if ((*itr)->GetAmount() > auraAbsorbMod) + auraAbsorbMod = float((*itr)->GetAmount()); + } - if (aurEff->GetAmount() > auraAbsorbMod) - auraAbsorbMod = float(aurEff->GetAmount()); + AuraEffectList const& AbsIgnoreAurasB = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); + for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr) + { + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; + + if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo)) + auraAbsorbMod = float((*itr)->GetAmount()); + } + RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); } - RoundToInterval(auraAbsorbMod, 0.f, 100.f); - - int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod); - dmgInfo.ModifyDamage(-absorbIgnoringDamage); - // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB)); @@ -2242,9 +2185,11 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) uint32 splitted_absorb = 0; uint32 splitted_resist = 0; - DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, schoolMask, dmgInfo.GetDamageType(), BASE_ATTACK); + uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, schoolMask, dmgInfo.GetDamageType()); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { + procEx |= PROC_EX_IMMUNE; splittedDmgInfo.AbsorbDamage(splitted); } else @@ -2257,6 +2202,10 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) splitted_resist = splittedDmgInfo.GetResist(); splitted = splittedDmgInfo.GetDamage(); + // create procs + createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); + caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr, -1, nullptr, &splittedDmgInfo); + if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo(), splitted, schoolMask, splitted_absorb, splitted_resist, false, 0, false); @@ -2307,9 +2256,11 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) uint32 splitted_absorb = 0; uint32 splitted_resist = 0; - DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, splitSchoolMask, dmgInfo.GetDamageType(), BASE_ATTACK); + uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, splitSchoolMask, dmgInfo.GetDamageType()); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { + procEx |= PROC_EX_IMMUNE; splittedDmgInfo.AbsorbDamage(splitted); } else @@ -2322,6 +2273,10 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) splitted_resist = splittedDmgInfo.GetResist(); splitted = splittedDmgInfo.GetDamage(); + // create procs + createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); + caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); + if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo, splitted, splitSchoolMask, splitted_absorb, splitted_resist, false, 0, false); @@ -2421,6 +2376,11 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case + if (!extra && _lastExtraAttackSpell) + { + _lastExtraAttackSpell = 0; + } + bool meleeAttack = true; // melee attack spell casted at main hand attack only - no normal melee dmg dealt @@ -2460,11 +2420,16 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A Unit::DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb); SendAttackStateUpdate(&damageInfo); - DamageInfo dmgInfo(damageInfo); - ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); + //TriggerAurasProcOnEvent(damageInfo); + + _lastDamagedTargetGuid = victim->GetGUID(); DealMeleeDamage(&damageInfo, true); + DamageInfo dmgInfo(damageInfo); + Unit::ProcDamageAndSpell(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, + damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo); + if (GetTypeId() == TYPEID_PLAYER) LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.", GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist); @@ -2571,15 +2536,31 @@ bool Unit::GetMeleeAttackPoint(Unit* attacker, Position& pos) return true; } -void Unit::HandleProcExtraAttackFor(Unit* victim) +void Unit::HandleProcExtraAttackFor(Unit* victim, uint32 count) { - while (m_extraAttacks) + while (count) { + --count; AttackerStateUpdate(victim, BASE_ATTACK, true); - --m_extraAttacks; } } +void Unit::AddExtraAttacks(uint32 count) +{ + ObjectGuid targetGUID = _lastDamagedTargetGuid; + if (!targetGUID) + { + if (ObjectGuid selection = GetTarget()) + { + targetGUID = selection; // Spell was cast directly (not triggered by aura) + } + else + return; + } + + extraAttacksTargets[targetGUID] += count; +} + MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const { // This is only wrapper @@ -3149,7 +3130,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo // Spellmod from SPELLMOD_RESIST_MISS_CHANCE if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, modHitChance); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance); // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask); @@ -3279,6 +3260,8 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca reflectchance += (*i)->GetAmount(); if (reflectchance > 0 && roll_chance_i(reflectchance)) { + // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) + //ProcDamageAndSpell(victim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, spell); return SPELL_MISS_REFLECT; } } @@ -5990,20 +5973,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, SendSpellNonMeleeDamageLog(&log); } -void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) +void Unit::ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase) { - WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK; - if (typeMaskActor) - { - ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); - } - - if (typeMaskActionTarget && actionTarget) - { - actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType); - } - - TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + // Not much to do if no flags are set. + if (procAttacker && actor) + actor->ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase); + // Now go on with a victim's events'n'auras + // Not much to do if no flags are set or there is no victim + if (victim && victim->IsAlive() && procVictim) + victim->ProcDamageAndSpellFor(true, actor, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo, procPhase); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) @@ -6184,6 +6162,3458 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType SendAttackStateUpdate(&dmgInfo); } +//victim may be nullptr +bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc /*= nullptr*/) +{ + SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); + uint32 effIndex = triggeredByAura->GetEffIndex(); + int32 triggerAmount = triggeredByAura->GetAmount(); + + Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER + ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; + + uint32 triggered_spell_id = 0; + uint32 cooldown_spell_id = 0; // for random trigger, will be one of the triggered spell to avoid repeatable triggers + // otherwise, it's the triggered_spell_id by default + Unit* target = victim; + int32 basepoints0 = 0; + ObjectGuid originalCaster; + + switch (dummySpell->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + switch (dummySpell->Id) + { + // Overkill + case 58426: + { + triggered_spell_id = 58427; + break; + } + // Unstable Power + case 24658: + { + if (!procSpell || procSpell->Id == 24659) + return false; + // Need remove one 24659 aura + RemoveAuraFromStack(24659); + return true; + } + // Restless Strength + case 24661: + { + // Need remove one 24662 aura + RemoveAuraFromStack(24662); + return true; + } + // Mark of Malice + case 33493: + { + if (triggeredByAura->GetBase()->GetCharges() > 1) + return true; + + target = this; + triggered_spell_id = 33494; + break; + } + // Twisted Reflection (boss spell) + case 21063: + triggered_spell_id = 21064; + break; + // Vampiric Aura (boss spell) + case 38196: + { + basepoints0 = 3 * damage; // 300% + if (basepoints0 < 0) + return false; + + triggered_spell_id = 31285; + target = this; + break; + } + // Aura of Madness (Darkmoon Card: Madness trinket) + //===================================================== + // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior) + // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid) + // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid) + // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes) + // 41005 Manic: +35 haste (spell, melee and ranged) (All classes) + // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) + // 41011 Martyr Complex: +35 stamina (All classes) + // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) + case 39446: + { + if (GetTypeId() != TYPEID_PLAYER || !IsAlive()) + return false; + + // Select class defined buff + switch (getClass()) + { + case CLASS_PALADIN: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409 + case CLASS_DRUID: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409 + triggered_spell_id = RAND(39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409); + cooldown_spell_id = 39511; + break; + case CLASS_ROGUE: // 39511, 40997, 40998, 41002, 41005, 41011 + case CLASS_WARRIOR: // 39511, 40997, 40998, 41002, 41005, 41011 + case CLASS_DEATH_KNIGHT: + triggered_spell_id = RAND(39511, 40997, 40998, 41002, 41005, 41011); + cooldown_spell_id = 39511; + break; + case CLASS_PRIEST: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 + case CLASS_SHAMAN: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 + case CLASS_MAGE: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 + case CLASS_WARLOCK: // 40999, 41002, 41005, 41009, 41011, 41406, 41409 + triggered_spell_id = RAND(40999, 41002, 41005, 41009, 41011, 41406, 41409); + cooldown_spell_id = 40999; + break; + case CLASS_HUNTER: // 40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409 + triggered_spell_id = RAND(40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409); + cooldown_spell_id = 40997; + break; + default: + return false; + } + + target = this; + if (roll_chance_i(10)) + ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); // TODO: It should be moved to database, shouldn't it? + break; + } + // Sunwell Exalted Caster Neck (??? neck) + // cast ??? Light's Wrath if Exalted by Aldor + // cast ??? Arcane Bolt if Exalted by Scryers + case 46569: + return false; // old unused version + // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck) + // cast 45479 Light's Wrath if Exalted by Aldor + // cast 45429 Arcane Bolt if Exalted by Scryers + case 45481: + { + Player* player = ToPlayer(); + if (!player) + return false; + + // Get Aldor reputation rank + if (player->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45479; + break; + } + // Get Scryers reputation rank + if (player->GetReputationRank(934) == REP_EXALTED) + { + // triggered at positive/self casts also, current attack target used then + if (target && IsFriendlyTo(target)) + { + target = GetVictim(); + if (!target) + { + target = player->GetSelectedUnit(); + if (!target) + return false; + } + if (IsFriendlyTo(target)) + return false; + } + + triggered_spell_id = 45429; + break; + } + return false; + } + // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck) + // cast 45480 Light's Strength if Exalted by Aldor + // cast 45428 Arcane Strike if Exalted by Scryers + case 45482: + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45480; + break; + } + // Get Scryers reputation rank + if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45428; + break; + } + return false; + } + // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck) + // cast 45431 Arcane Insight if Exalted by Aldor + // cast 45432 Light's Ward if Exalted by Scryers + case 45483: + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45432; + break; + } + // Get Scryers reputation rank + if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45431; + break; + } + return false; + } + // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck) + // cast 45478 Light's Salvation if Exalted by Aldor + // cast 45430 Arcane Surge if Exalted by Scryers + case 45484: + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + // Get Aldor reputation rank + if (ToPlayer()->GetReputationRank(932) == REP_EXALTED) + { + target = this; + triggered_spell_id = 45478; + break; + } + // Get Scryers reputation rank + if (ToPlayer()->GetReputationRank(934) == REP_EXALTED) + { + triggered_spell_id = 45430; + break; + } + return false; + } + // Kill command + case 58914: + { + // Remove aura stack from pet + RemoveAuraFromStack(58914); + Unit* owner = GetOwner(); + if (!owner) + return true; + // reduce the owner's aura stack + owner->RemoveAuraFromStack(34027); + return true; + } + // Vampiric Touch (generic, used by some boss) + case 52723: + case 60501: + { + triggered_spell_id = 52724; + basepoints0 = damage / 2; + target = this; + break; + } + // Divine purpose + case 31871: + case 31872: + { + // Roll chane + if (!victim || !victim->IsAlive() || !roll_chance_i(triggerAmount)) + return false; + + // Remove any stun effect on target + victim->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL); + return true; + } + // Glyph of Life Tap + case 63320: + { + triggered_spell_id = 63321; // Life Tap + break; + } + case 71519: // Deathbringer's Will Normal + { + if (GetTypeId() != TYPEID_PLAYER || HasSpellCooldown(71484)) + return false; + + AddSpellCooldown(71484, 0, cooldown); + + std::vector RandomSpells; + switch (getClass()) + { + case CLASS_WARRIOR: + case CLASS_PALADIN: + case CLASS_DEATH_KNIGHT: + RandomSpells.push_back(71484); + RandomSpells.push_back(71491); + RandomSpells.push_back(71492); + break; + case CLASS_SHAMAN: + case CLASS_ROGUE: + RandomSpells.push_back(71486); + RandomSpells.push_back(71485); + RandomSpells.push_back(71492); + break; + case CLASS_DRUID: + RandomSpells.push_back(71484); + RandomSpells.push_back(71485); + RandomSpells.push_back(71492); + break; + case CLASS_HUNTER: + RandomSpells.push_back(71486); + RandomSpells.push_back(71491); + RandomSpells.push_back(71485); + break; + default: + return false; + } + if (RandomSpells.empty()) // shouldn't happen + return false; + + uint8 rand_spell = irand(0, (RandomSpells.size() - 1)); + CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); + break; + } + case 71562: // Deathbringer's Will Heroic + { + if (GetTypeId() != TYPEID_PLAYER || HasSpellCooldown(71561)) + return false; + + AddSpellCooldown(71561, 0, cooldown); + + std::vector RandomSpells; + switch (getClass()) + { + case CLASS_WARRIOR: + case CLASS_PALADIN: + case CLASS_DEATH_KNIGHT: + RandomSpells.push_back(71561); + RandomSpells.push_back(71559); + RandomSpells.push_back(71560); + break; + case CLASS_SHAMAN: + case CLASS_ROGUE: + RandomSpells.push_back(71558); + RandomSpells.push_back(71556); + RandomSpells.push_back(71560); + break; + case CLASS_DRUID: + RandomSpells.push_back(71561); + RandomSpells.push_back(71556); + RandomSpells.push_back(71560); + break; + case CLASS_HUNTER: + RandomSpells.push_back(71558); + RandomSpells.push_back(71559); + RandomSpells.push_back(71556); + break; + default: + return false; + } + if (RandomSpells.empty()) // shouldn't happen + return false; + + uint8 rand_spell = irand(0, (RandomSpells.size() - 1)); + CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster); + break; + } + // Freya, Petrified Bark + case 62933: + case 62337: + { + if (!victim) + return false; + + int32 dmg = damage; + victim->CastCustomSpell(this, 62379, &dmg, 0, 0, true); + return true; + } + // Trial of the Champion, Earth Shield + case 67534: + { + const int32 dmg = (int32)damage; + CastCustomSpell(this, 67535, &dmg, nullptr, nullptr, true, 0, triggeredByAura, triggeredByAura->GetCasterGUID()); + return true; + } + // Trial of the Crusader, Faction Champions, Retaliation + case 65932: + { + // check attack comes not from behind + if (!victim || !HasInArc(M_PI, victim)) + return false; + + triggered_spell_id = 65934; + break; + } + // Pit of Saron, Tyrannus, Overlord's Brand + case 69172: // everything except for DoTs + { + if (!target) + return false; + if (Unit* caster = triggeredByAura->GetCaster()) + { + if (procFlag & (PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS)) + { + int32 dmg = 5.5f * damage; + target->CastCustomSpell(caster, 69190, &dmg, 0, 0, true); + } + else + { + if (caster->GetVictim()) + { + int32 dmg = damage; + target->CastCustomSpell(caster->GetVictim(), 69189, &dmg, 0, 0, true); + } + } + } + return true; + } + // Pit of Saron, Tyrannus, Overlord's Brand + case 69173: // only DoTs + { + if (!target) + return false; + if (Unit* caster = triggeredByAura->GetCaster()) + { + if (procEx & PROC_EX_INTERNAL_HOT) + { + int32 dmg = 5.5f * damage; + target->CastCustomSpell(caster, 69190, &dmg, 0, 0, true); + } + else + { + if (caster->GetVictim()) + { + int32 dmg = damage; + target->CastCustomSpell(caster->GetVictim(), 69189, &dmg, 0, 0, true); + } + } + } + return true; + } + // Icecrown Citadel, Lady Deathwhisper, Vampiric Might + case 70674: + { + if (Unit* caster = triggeredByAura->GetCaster()) + { + int32 dmg = 3 * damage; + caster->CastCustomSpell(caster, 70677, &dmg, 0, 0, true); + } + return true; + } + // Item: Purified Shard of the Gods + case 69755: + { + triggered_spell_id = ((procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69733 : 69729); + break; + } + // Item: Shiny Shard of the Gods + case 69739: + { + triggered_spell_id = ((procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69734 : 69730); + break; + } + // VoA: Meteor Fists koralon + case 66725: + case 68161: + { + triggered_spell_id = 66765; // handled by spell_difficulty + break; + } + } + break; + } + case SPELLFAMILY_MAGE: + { + // Magic Absorption + if (dummySpell->SpellIconID == 459) // only this spell has SpellIconID == 459 and dummy aura + { + if (getPowerType() != POWER_MANA) + return false; + + // mana reward + basepoints0 = CalculatePct(int32(GetMaxPower(POWER_MANA)), triggerAmount); + target = this; + triggered_spell_id = 29442; + break; + } + // Hot Streak + if (dummySpell->SpellIconID == 2999) + { + if (effIndex != 0) + return false; + AuraEffect* counter = triggeredByAura->GetBase()->GetEffect(EFFECT_1); + if (!counter) + return true; + + // Count spell criticals in a row in second aura + if (procEx & PROC_EX_CRITICAL_HIT) + { + counter->SetAmount(counter->GetAmount() * 2); + if (counter->GetAmount() < 100) // not enough + return true; + // Crititcal counted -> roll chance + if (roll_chance_i(triggerAmount)) + CastSpell(this, 48108, true, castItem, triggeredByAura); + } + counter->SetAmount(25); + return true; + } + // Incanter's Regalia set (add trigger chance to Mana Shield) + if (dummySpell->SpellFamilyFlags[0] & 0x8000) + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + target = this; + triggered_spell_id = 37436; + break; + } + switch (dummySpell->Id) + { + // Glyph of Polymorph + case 56375: + { + if (!target) + return false; + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed. + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); + target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); + return true; + } + // Glyph of Icy Veins + case 56374: + { + RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false); + RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + return true; + } + // Glyph of Ice Block + case 56372: + { + Player* player = ToPlayer(); + if (!player) + return false; + + SpellCooldowns const cooldowns = player->GetSpellCooldowns(); + // remove cooldowns on all ranks of Frost Nova + for (SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr) + { + SpellInfo const* cdSpell = sSpellMgr->GetSpellInfo(itr->first); + // Frost Nova + if (cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE + && cdSpell->SpellFamilyFlags[0] & 0x00000040) + player->RemoveSpellCooldown(cdSpell->Id, true); + } + break; + } + } + break; + } + case SPELLFAMILY_WARRIOR: + { + switch (dummySpell->Id) + { + // Victorious + case 32216: + { + RemoveAura(dummySpell->Id); + return false; + } + } + + // Second Wind + if (dummySpell->SpellIconID == 1697) + { + // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example) + if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) + return false; + // Need stun or root mechanic + if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN)))) + return false; + + switch (dummySpell->Id) + { + case 29838: + triggered_spell_id = 29842; + break; + case 29834: + triggered_spell_id = 29841; + break; + case 42770: + triggered_spell_id = 42771; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled spell id: {} (SW)", dummySpell->Id); + return false; + } + + target = this; + break; + } + break; + } + case SPELLFAMILY_WARLOCK: + { + // Seed of Corruption + if (dummySpell->SpellFamilyFlags[1] & 0x00000010) + { + if (procSpell && procSpell->SpellFamilyFlags[1] & 0x8000) + return false; + // if damage is more than need or target die from damage deal finish spell + if (triggeredByAura->GetAmount() <= int32(damage) || GetHealth() <= damage) + { + // remember guid before aura delete + ObjectGuid casterGuid = triggeredByAura->GetCasterGUID(); + + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); + + uint32 spell = sSpellMgr->GetSpellWithRank(27285, dummySpell->GetRank()); + + // Cast finish spell (triggeredByAura already not exist!) + if (Unit* caster = ObjectAccessor::GetUnit(*this, casterGuid)) + { + this->CastSpell(this, 37826, true); // VISUAL! + caster->CastSpell(this, spell, true, castItem); + } + + return true; // no hidden cooldown + } + + // Damage counting + triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage); + return true; + } + // Seed of Corruption (Mobs cast) - no die req + if (dummySpell->SpellFamilyFlags.IsEqual(0, 0, 0) && dummySpell->SpellIconID == 1932) + { + // if damage is more than need deal finish spell + if (triggeredByAura->GetAmount() <= int32(damage)) + { + // remember guid before aura delete + ObjectGuid casterGuid = triggeredByAura->GetCasterGUID(); + + // Remove aura (before cast for prevent infinite loop handlers) + RemoveAurasDueToSpell(triggeredByAura->GetId()); + + // Cast finish spell (triggeredByAura already not exist!) + if (Unit* caster = ObjectAccessor::GetUnit(*this, casterGuid)) + { + this->CastSpell(this, 37826, true); // VISUAL! + caster->CastSpell(this, 32865, true, castItem); + } + return true; // no hidden cooldown + } + // Damage counting + triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage); + return true; + } + switch (dummySpell->Id) + { + // Nightfall + case 18094: + case 18095: + // Glyph of corruption + case 56218: + { + target = this; + triggered_spell_id = 17941; + break; + } + // Soul Leech + case 30293: + case 30295: + case 30296: + { + // Improved Soul Leech + AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); + for (Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i) + { + if ((*i)->GetId() == 54117 || (*i)->GetId() == 54118) + { + if ((*i)->GetEffIndex() != 0) + continue; + basepoints0 = int32((*i)->GetAmount()); + target = GetGuardianPet(); + if (target) + { + // regen mana for pet + CastCustomSpell(target, 54607, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); + } + // regen mana for caster + CastCustomSpell(this, 59117, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); + // Get second aura of spell for replenishment effect on party + if (AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1)) + { + // Replenishment - roll chance + if (roll_chance_i(aurEff->GetAmount())) + { + CastSpell(this, 57669, true, castItem, triggeredByAura); + } + } + break; + } + } + // health + basepoints0 = CalculatePct(int32(damage), triggerAmount); + target = this; + triggered_spell_id = 30294; + break; + } + // Shadowflame (Voidheart Raiment set bonus) + case 37377: + { + triggered_spell_id = 37379; + break; + } + // Pet Healing (Corruptor Raiment or Rift Stalker Armor) + case 37381: + { + target = GetGuardianPet(); + if (!target) + return false; + + // heal amount + basepoints0 = CalculatePct(int32(damage), triggerAmount); + triggered_spell_id = 37382; + break; + } + // Shadowflame Hellfire (Voidheart Raiment set bonus) + case 39437: + { + triggered_spell_id = 37378; + break; + } + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Body and Soul + if (dummySpell->SpellIconID == 2218) + { + // Proc only from Abolish desease on self cast + if (procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount)) + return false; + triggered_spell_id = 64136; + target = this; + break; + } + switch (dummySpell->Id) + { + // Vampiric Embrace + case 15286: + { + if (!victim || !victim->IsAlive() || procSpell->SpellFamilyFlags[1] & 0x80000) + return false; + + // heal amount + int32 total = CalculatePct(int32(damage), triggerAmount); + int32 team = total / 5; + int32 self = total - team; + CastCustomSpell(this, 15290, &team, &self, nullptr, true, castItem, triggeredByAura); + return true; // no hidden cooldown + } + // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen) + case 40438: + { + // Shadow Word: Pain + if (procSpell->SpellFamilyFlags[0] & 0x8000) + triggered_spell_id = 40441; + // Renew + else if (procSpell->SpellFamilyFlags[0] & 0x40) + triggered_spell_id = 40440; + else + return false; + + target = this; + break; + } + // Improved Shadowform + case 47570: + case 47569: + { + if (!roll_chance_i(triggerAmount)) + return false; + + RemoveMovementImpairingAuras(true); + break; + } + // Glyph of Dispel Magic + case 55677: + { + // Dispel Magic shares spellfamilyflag with abolish disease + if (procSpell->SpellIconID != 74) + return false; + if (!target || !target->IsFriendlyTo(this)) + return false; + + basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount)); + triggered_spell_id = 56131; + break; + } + // Oracle Healing Bonus ("Garments of the Oracle" set) + case 26169: + { + // heal amount + basepoints0 = int32(CalculatePct(damage, 10)); + target = this; + triggered_spell_id = 26170; + break; + } + // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set + case 39372: + { + if (!procSpell || (procSpell->GetSchoolMask() & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0) + return false; + + // heal amount + basepoints0 = CalculatePct(int32(damage), triggerAmount); + target = this; + triggered_spell_id = 39373; + break; + } + // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus) + case 28809: + { + triggered_spell_id = 28810; + break; + } + // Priest T10 Healer 2P Bonus + case 70770: + // Flash Heal + if (procSpell->SpellFamilyFlags[0] & 0x800) + { + triggered_spell_id = 70772; + SpellInfo const* blessHealing = sSpellMgr->GetSpellInfo(triggered_spell_id); + if (!blessHealing || !victim) + return false; + basepoints0 = int32(CalculatePct(damage, triggerAmount) / (blessHealing->GetMaxDuration() / blessHealing->Effects[0].Amplitude)); + victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_HEAL, basepoints0); + return true; + } + break; + } + break; + } + case SPELLFAMILY_DRUID: + { + switch (dummySpell->Id) + { + // Glyph of Innervate + case 54832: + { + if (procSpell->SpellIconID != 62) + return false; + + int32 mana_perc = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcValue(); + basepoints0 = int32(CalculatePct(GetCreatePowers(POWER_MANA), mana_perc) / 10); + triggered_spell_id = 54833; + target = this; + break; + } + // Glyph of Starfire + case 54845: + { + triggered_spell_id = 54846; + break; + } + // Glyph of Shred + case 54815: + { + if (!target) + return false; + + // try to find spell Rip on the target + if (AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID())) + { + // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip + uint32 CountMin = AurEff->GetBase()->GetMaxDuration(); + + // just Rip's max duration without other spells + uint32 CountMax = AurEff->GetSpellInfo()->GetMaxDuration(); + + // add possible auras' and Glyph of Shred's max duration + CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds + CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds + CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds + + // if min < max -> that means caster didn't cast 3 shred yet + // so set Rip's duration and max duration + if (CountMin < CountMax) + { + AurEff->GetBase()->SetDuration(AurEff->GetBase()->GetDuration() + triggerAmount * IN_MILLISECONDS); + AurEff->GetBase()->SetMaxDuration(CountMin + triggerAmount * IN_MILLISECONDS); + return true; + } + } + // if not found Rip + return false; + } + // Glyph of Rake + case 54821: + { + if (procSpell->SpellVisual[0] == 750 && procSpell->Effects[1].ApplyAuraName == 3) + { + if (target && target->GetTypeId() == TYPEID_UNIT) + { + triggered_spell_id = 54820; + break; + } + } + return false; + } + // Leader of the Pack + case 24932: + { + if (triggerAmount <= 0) + return false; + basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); + target = this; + triggered_spell_id = 34299; + if (triggeredByAura->GetCasterGUID() != GetGUID()) + break; + int32 basepoints1 = CalculatePct(GetMaxPower(Powers(POWER_MANA)), triggerAmount * 2); + // Improved Leader of the Pack + // Check cooldown of heal spell cooldown + if (GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299)) + CastCustomSpell(this, 68285, &basepoints1, 0, 0, true, 0, triggeredByAura); + break; + } + // Healing Touch (Dreamwalker Raiment set) + case 28719: + { + // mana back + basepoints0 = int32(CalculatePct(spellProc->GetPowerCost(), 30)); + target = this; + triggered_spell_id = 28742; + break; + } + // Glyph of Rejuvenation + case 54754: + { + if (!victim || !victim->HealthBelowPct(uint32(triggerAmount))) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + triggered_spell_id = 54755; + break; + } + // Healing Touch Refund (Idol of Longevity trinket) + case 28847: + { + target = this; + triggered_spell_id = 28848; + break; + } + // Mana Restore (Malorne Raiment set / Malorne Regalia set) + case 37288: + case 37295: + { + target = this; + triggered_spell_id = 37238; + break; + } + // Druid Tier 6 Trinket + case 40442: + { + float chance; + + // Starfire + if (procSpell->SpellFamilyFlags[0] & 0x4) + { + triggered_spell_id = 40445; + chance = 25.0f; + } + // Rejuvenation + else if (procSpell->SpellFamilyFlags[0] & 0x10) + { + triggered_spell_id = 40446; + chance = 25.0f; + } + // Mangle (Bear) and Mangle (Cat) + else if (procSpell->SpellFamilyFlags[1] & 0x00000440) + { + triggered_spell_id = 40452; + chance = 40.0f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + target = this; + break; + } + // Maim Interrupt + case 44835: + { + // Deadly Interrupt Effect + triggered_spell_id = 32747; + break; + } + // Item - Druid T10 Restoration 4P Bonus (Rejuvenation) + case 70664: + { + // xinef: proc only from normal Rejuvenation, and proc rejuvenation + if (!victim || !procSpell || procSpell->SpellIconID != 64) + return false; + + Player* caster = ToPlayer(); + if (!caster) + return false; + if (!caster->GetGroup() && victim == this) + return false; + + CastCustomSpell(70691, SPELLVALUE_BASE_POINT0, damage, victim, true); + return true; + } + } + // Eclipse + if (dummySpell->SpellIconID == 2856 && GetTypeId() == TYPEID_PLAYER) + { + if (!procSpell || effIndex != 0) + return false; + + bool isWrathSpell = (procSpell->SpellFamilyFlags[0] & 1); + + if (!roll_chance_f(dummySpell->ProcChance * (isWrathSpell ? 0.6f : 1.0f))) + return false; + + target = this; + if (target->HasAura(isWrathSpell ? 48517 : 48518)) + return false; + + triggered_spell_id = isWrathSpell ? 48518 : 48517; + break; + } + [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. + } + case SPELLFAMILY_ROGUE: + { + switch(dummySpell->Id) + { + // Glyph of Backstab + case 56800: + { + if (victim) + if (AuraEffect* aurEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x100000, 0, 0, GetGUID())) + if (Aura* aur = aurEff->GetBase()) + if (!aur->IsRemoved() && aur->GetDuration() > 0) + if ((aur->GetApplyTime() + aur->GetMaxDuration() / 1000 + 5) > (GameTime::GetGameTime().count() + aur->GetDuration() / 1000) ) + { + aur->SetDuration(aur->GetDuration() + 2000); + return true; + } + return false; + } + // Deadly Throw Interrupt + case 32748: + { + // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw + if (this == victim) + return false; + + triggered_spell_id = 32747; + break; + } + } + // Master of subtlety + if( dummySpell->SpellIconID == 2114 ) + { + triggered_spell_id = 31665; + basepoints0 = triggerAmount; + break; + } + // Cut to the Chase + if (dummySpell->SpellIconID == 2909) + { + // "refresh your Slice and Dice duration to its 5 combo point maximum" + // lookup Slice and Dice + if (AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0)) + { + aur->GetBase()->SetDuration(aur->GetSpellInfo()->GetMaxDuration(), true); + return true; + } + return false; + } + // Deadly Brew + else if (dummySpell->SpellIconID == 2963) + { + triggered_spell_id = 3409; + break; + } + // Quick Recovery + else if (dummySpell->SpellIconID == 2116) + { + if (!procSpell) + return false; + + // energy cost save + basepoints0 = CalculatePct(int32(procSpell->ManaCost), triggerAmount); + if (basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 31663; + break; + } + break; + } + case SPELLFAMILY_HUNTER: + { + switch (dummySpell->SpellIconID) + { + case 2236: // Thrill of the Hunt + { + if (!procSpell) + return false; + + Spell* spell = ToPlayer()->m_spellModTakingSpell; + + // Disable charge drop because of Lock and Load + if (spell) + ToPlayer()->SetSpellModTakingSpell(spell, false); + + // Explosive Shot + if (procSpell->SpellFamilyFlags[2] & 0x200) + { + if (!victim) + return false; + if (AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID())) + basepoints0 = pEff->GetSpellInfo()->CalcPowerCost(this, SpellSchoolMask(pEff->GetSpellInfo()->SchoolMask)) * 4 / 10 / 3; + } + else + basepoints0 = procSpell->CalcPowerCost(this, SpellSchoolMask(procSpell->SchoolMask)) * 4 / 10; + + if (spell) + ToPlayer()->SetSpellModTakingSpell(spell, true); + + if (basepoints0 <= 0) + return false; + + target = this; + triggered_spell_id = 34720; + break; + } + case 3406: // Hunting Party + { + triggered_spell_id = 57669; + target = this; + break; + } + case 3560: // Rapid Recuperation + { + // This effect only from Rapid Killing (mana regen) + if (!(procSpell->SpellFamilyFlags[1] & 0x01000000)) + return false; + + target = this; + + switch (dummySpell->Id) + { + case 53228: // Rank 1 + triggered_spell_id = 56654; + break; + case 53232: // Rank 2 + triggered_spell_id = 58882; + break; + } + break; + } + } + + switch (dummySpell->Id) + { + case 57870: // Glyph of Mend Pet + { + if (!victim) + return false; + + victim->CastSpell(victim, 57894, true, nullptr, nullptr, GetGUID()); + return true; + } + } + break; + } + case SPELLFAMILY_PALADIN: + { + // Light's Beacon - Beacon of Light + if (dummySpell->Id == 53651) + { + if (!victim) + return false; + + // Do not proc from Glyph of Holy Light and Judgement of Light + if (procSpell->Id == 20267 || procSpell->Id == 54968) + { + return false; + } + + Unit* beaconTarget = triggeredByAura->GetBase()->GetCaster(); + if (!beaconTarget || beaconTarget == this || !beaconTarget->GetAura(53563, victim->GetGUID())) + return false; + + basepoints0 = int32(damage); + triggered_spell_id = procSpell->IsRankOf(sSpellMgr->GetSpellInfo(635)) ? 53652 : 53654; + + victim->CastCustomSpell(beaconTarget, triggered_spell_id, &basepoints0, nullptr, nullptr, true, 0, triggeredByAura, victim->GetGUID()); + return true; + } + // Judgements of the Wise + if (dummySpell->SpellIconID == 3017) + { + target = this; + triggered_spell_id = 31930; + // replenishment + CastSpell(this, 57669, true, castItem, triggeredByAura); + break; + } + // Righteous Vengeance + if (dummySpell->SpellIconID == 3025) + { + if (!victim) + return false; + + // 4 damage tick + basepoints0 = triggerAmount * damage / 400; + triggered_spell_id = 61840; + // Add remaining ticks to damage done + victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); + return true; + } + // Sheath of Light + if (dummySpell->SpellIconID == 3030) + { + // 4 healing tick + basepoints0 = triggerAmount * damage / 400; + triggered_spell_id = 54203; + break; + } + switch (dummySpell->Id) + { + // Judgement of Light + case 20185: + { + if (!victim || !victim->IsAlive() || victim->HasSpellCooldown(20267)) + return false; + // 2% of base mana + basepoints0 = int32(victim->CountPctFromMaxHealth(2)); + victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); + victim->AddSpellCooldown(20267, 0, 4 * IN_MILLISECONDS); + return true; + } + // Judgement of Wisdom + case 20186: + { + if (!victim || !victim->IsAlive() || victim->getPowerType() != POWER_MANA || victim->HasSpellCooldown(20268)) + return false; + + // 2% of base mana + basepoints0 = int32(CalculatePct(victim->GetCreateMana(), 2)); + victim->CastCustomSpell(victim, 20268, &basepoints0, nullptr, nullptr, true, 0, triggeredByAura); + victim->AddSpellCooldown(20268, 0, 4 * IN_MILLISECONDS); + return true; + } + // Holy Power (Redemption Armor set) + case 28789: + { + if (!victim) + return false; + + // Set class defined buff + switch (victim->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28790; // Increases the friendly target's armor + break; + default: + return false; + } + break; + } + // Seal of Vengeance (damage calc on apply aura) + case 31801: + { + if (effIndex != 0 || !victim) // effect 1, 2 used by seal unleashing code + return false; + + // At melee attack or Hammer of the Righteous spell damage considered as melee attack + bool stacker = !procSpell || procSpell->Id == 53595; + // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements + bool damager = procSpell && (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)); + + if (!stacker && !damager) + return false; + + triggered_spell_id = 31803; + + // On target with 5 stacks of Holy Vengeance direct damage is done + if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) + { + if (aur->GetStackAmount() == 5) + { + if (stacker) + aur->RefreshDuration(); + + CastSpell(victim, 42463, true, castItem, triggeredByAura); + return true; + } + } + + if (!stacker) + return false; + break; + } + // Seal of Corruption + case 53736: + { + if (effIndex != 0 || !victim) // effect 1, 2 used by seal unleashing code + return false; + + // At melee attack or Hammer of the Righteous spell damage considered as melee attack + bool stacker = !procSpell || procSpell->Id == 53595; + // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements + bool damager = procSpell && (procSpell->EquippedItemClass != -1 || (procSpell->SpellIconID == 243 && procSpell->SpellVisual[0] == 39)); + + if (!stacker && !damager) + return false; + + triggered_spell_id = 53742; + + // On target with 5 stacks of Blood Corruption direct damage is done + if (Aura* aur = victim->GetAura(triggered_spell_id, GetGUID())) + { + if (aur->GetStackAmount() == 5) + { + if (stacker) + aur->RefreshDuration(); + + CastSpell(victim, 53739, true, castItem, triggeredByAura); + return true; + } + } + + if (!stacker) + return false; + break; + } + // Spiritual Attunement + case 31785: + case 33776: + { + // if healed by another unit (victim) + if (this == victim) + return false; + + // dont allow non-positive dots to proc + if (!procSpell || !procSpell->IsPositive()) + return false; + + // heal amount + basepoints0 = int32(CalculatePct(std::min(damage, GetMaxHealth() - GetHealth()), triggerAmount)); + target = this; + + if (basepoints0) + triggered_spell_id = 31786; + break; + } + // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) + case 40470: + { + if (!procSpell) + return false; + + float chance = 0.0f; + + // Flash of light/Holy light + if (procSpell->SpellFamilyFlags[0] & 0xC0000000) + { + triggered_spell_id = 40471; + chance = 15.0f; + } + // Judgement (any) + else if (procSpell->SpellFamilyFlags[0] & 0x800000) + { + triggered_spell_id = 40472; + chance = 50.0f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + break; + } + // Glyph of Holy Light + case 54937: + { + triggered_spell_id = 54968; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + break; + } + // Item - Paladin T8 Holy 2P Bonus + case 64890: + { + triggered_spell_id = 64891; + basepoints0 = triggerAmount * damage / 300; + break; + } + case 71406: // Tiny Abomination in a Jar + case 71545: // Tiny Abomination in a Jar (Heroic) + { + if (!victim || !victim->IsAlive()) + return false; + + CastSpell(this, 71432, true, nullptr, triggeredByAura); + + Aura const* dummy = GetAura(71432); + if (!dummy || dummy->GetStackAmount() < (dummySpell->Id == 71406 ? 8 : 7)) + return false; + + RemoveAurasDueToSpell(71432); + triggered_spell_id = 71433; // default main hand attack + // roll if offhand + if (Player const* player = ToPlayer()) + if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) + triggered_spell_id = 71434; + target = victim; + break; + } + // Item - Icecrown 25 Normal Dagger Proc + case 71880: + { + switch (getPowerType()) + { + case POWER_MANA: + triggered_spell_id = 71881; + break; + case POWER_RAGE: + triggered_spell_id = 71883; + break; + case POWER_ENERGY: + triggered_spell_id = 71882; + break; + case POWER_RUNIC_POWER: + triggered_spell_id = 71884; + break; + default: + return false; + } + break; + } + // Item - Icecrown 25 Heroic Dagger Proc + case 71892: + { + switch (getPowerType()) + { + case POWER_MANA: + triggered_spell_id = 71888; + break; + case POWER_RAGE: + triggered_spell_id = 71886; + break; + case POWER_ENERGY: + triggered_spell_id = 71887; + break; + case POWER_RUNIC_POWER: + triggered_spell_id = 71885; + break; + default: + return false; + } + break; + } + } + break; + } + case SPELLFAMILY_SHAMAN: + { + switch (dummySpell->Id) + { + // Tidal Force + case 55198: + { + // Remove aura stack from caster + RemoveAuraFromStack(55166); + // drop charges + return false; + } + // Totemic Power (The Earthshatterer set) + case 28823: + { + if (!victim) + return false; + + // Set class defined buff + switch (victim->getClass()) + { + case CLASS_PALADIN: + case CLASS_PRIEST: + case CLASS_SHAMAN: + case CLASS_DRUID: + triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d. + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d. + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d. + break; + case CLASS_WARRIOR: + triggered_spell_id = 28827; // Increases the friendly target's armor + break; + default: + return false; + } + break; + } + // Lesser Healing Wave (Totem of Flowing Water Relic) + case 28849: + { + target = this; + triggered_spell_id = 28850; + break; + } + // Windfury Weapon (Passive) 1-8 Ranks + case 33757: + { + Player* player = ToPlayer(); + if (!player || !castItem || !castItem->IsEquipped() || !victim || !victim->IsAlive()) + return false; + + if (triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID()) + return false; + + WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); + if ((attType != BASE_ATTACK && attType != OFF_ATTACK) + || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) + || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) + return false; + + // Now amount of extra power stored in 1 effect of Enchant spell + // Get it by item enchant id + uint32 spellId; + switch (castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT))) + { + case 283: + spellId = 8232; + break; // 1 Rank + case 284: + spellId = 8235; + break; // 2 Rank + case 525: + spellId = 10486; + break; // 3 Rank + case 1669: + spellId = 16362; + break; // 4 Rank + case 2636: + spellId = 25505; + break; // 5 Rank + case 3785: + spellId = 58801; + break; // 6 Rank + case 3786: + spellId = 58803; + break; // 7 Rank + case 3787: + spellId = 58804; + break; // 8 Rank + default: + { + LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non handled item enchantment (rank?) {} for spell id: {} (Windfury)", + castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id); + return false; + } + } + + SpellInfo const* windfurySpellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!windfurySpellInfo) + { + LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: non-existing spell id: {} (Windfury)", spellId); + return false; + } + + int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellInfo, 1); + + // Value gained from additional AP + basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(attType) / 1000); + + if (procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) + triggered_spell_id = 25504; + + if (procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) + triggered_spell_id = 33750; + + // custom cooldown processing case + if (player->HasSpellCooldown(dummySpell->Id)) + return false; + + // apply cooldown before cast to prevent processing itself + player->AddSpellCooldown(dummySpell->Id, 0, 3 * IN_MILLISECONDS); + + // Attack Twice + for (uint32 i = 0; i < 2; ++i) + CastCustomSpell(victim, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); + + return true; + } + // Shaman Tier 6 Trinket + case 40463: + { + if (!procSpell) + return false; + + float chance; + if (procSpell->SpellFamilyFlags[0] & 0x1) + { + triggered_spell_id = 40465; // Lightning Bolt + chance = 15.0f; + } + else if (procSpell->SpellFamilyFlags[0] & 0x80) + { + triggered_spell_id = 40465; // Lesser Healing Wave + chance = 10.0f; + } + else if (procSpell->SpellFamilyFlags[1] & 0x00000010) + { + triggered_spell_id = 40466; // Stormstrike + chance = 50.0f; + } + else + return false; + + if (!roll_chance_f(chance)) + return false; + + target = this; + break; + } + // Glyph of Healing Wave + case 55440: + { + // Not proc from self heals + if (this == victim) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + target = this; + triggered_spell_id = 55533; + break; + } + // Spirit Hunt + case 58877: + { + // Cast on owner + target = GetOwner(); + if (!target) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + triggered_spell_id = 58879; + // Heal wolf + CastCustomSpell(this, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); + break; + } + // Shaman T8 Elemental 4P Bonus + case 64928: + { + basepoints0 = CalculatePct(int32(damage), triggerAmount); + triggered_spell_id = 64930; // Electrified + break; + } + // Shaman T9 Elemental 4P Bonus + case 67228: + { + // Lava Burst + if (procSpell->SpellFamilyFlags[1] & 0x1000) + { + triggered_spell_id = 71824; + SpellInfo const* triggeredSpell = sSpellMgr->GetSpellInfo(triggered_spell_id); + if (!triggeredSpell) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount) / (triggeredSpell->GetMaxDuration() / triggeredSpell->Effects[0].Amplitude); + } + break; + } + // Item - Shaman T10 Elemental 4P Bonus + case 70817: + { + if (!target) + return false; + // try to find spell Flame Shock on the target + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID())) + { + Aura* flameShock = aurEff->GetBase(); + int32 extraTime = 2 * aurEff->GetAmplitude(); + flameShock->SetMaxDuration(flameShock->GetMaxDuration() + extraTime); + flameShock->SetDuration(flameShock->GetDuration() + extraTime); + + return true; + } + // if not found Flame Shock + return false; + } + break; + } + // Frozen Power + if (dummySpell->SpellIconID == 3780) + { + if (!target) + return false; + if (GetDistance(target) < 15.0f) + return false; + float chance = (float)triggerAmount; + if (!roll_chance_f(chance)) + return false; + + triggered_spell_id = 63685; + break; + } + // Ancestral Awakening + if (dummySpell->SpellIconID == 3065) + { + triggered_spell_id = 52759; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + target = this; + break; + } + // Flametongue Weapon (Passive) + if (dummySpell->SpellFamilyFlags[0] & 0x200000) + { + if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->IsAlive() || !castItem || !castItem->IsEquipped()) + return false; + + WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot())); + if ((attType != BASE_ATTACK && attType != OFF_ATTACK) + || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) + || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) + return false; + + float fire_onhit = float(CalculatePct(dummySpell->Effects[EFFECT_0]. CalcValue(), 1.0f)); + + float add_spellpower = (float)(SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + + victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE)); + + // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84% + ApplyPct(add_spellpower, 3.84f); + + // Enchant on Off-Hand and ready? + if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) + { + float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f; + + // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed + basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); + triggered_spell_id = 10444; + } + + // Enchant on Main-Hand and ready? + else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK) + { + float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f; + + // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed + basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); + triggered_spell_id = 10444; + } + + // If not ready, we should return, shouldn't we?! + else + return false; + + CastCustomSpell(victim, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); + return true; + } + // Improved Water Shield + if (dummySpell->SpellIconID == 2287) + { + if (!procSpell) + return false; + + // Default chance for Healing Wave and Riptide + float chance = (float)triggeredByAura->GetAmount(); + + if (procSpell->SpellFamilyFlags[0] & 0x80) + // Lesser Healing Wave - 0.6 of default + chance *= 0.6f; + else if (procSpell->SpellFamilyFlags[0] & 0x100) + // Chain heal - 0.3 of default + chance *= 0.3f; + + if (!roll_chance_f(chance)) + return false; + + // Water Shield + if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0)) + { + uint32 spell = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + CastSpell(this, spell, true, castItem, triggeredByAura); + return true; + } + return false; + } + // Lightning Overload + if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura + { + if(!procSpell || GetTypeId() != TYPEID_PLAYER || !victim) + return false; + + if (procEx & PROC_EX_CRITICAL_HIT) + damage /= 2; + + do + { + uint32 spell = 0; + + if (procSpell->SpellFamilyFlags[0] & 0x2) + { + // 1/3 of 33% if 11% + if (!roll_chance_i(33)) + return false; + + spell = 45297; + } + else + spell = 45284; + + // do not reduce damage-spells have correct basepoints + damage /= 2; + int32 dmg = damage; + + // Cast + CastCustomSpell(victim, spell, &dmg, 0, 0, true, castItem, triggeredByAura); + } while (roll_chance_i(33)); + return true; + } + // Static Shock + if (dummySpell->SpellIconID == 3059) + { + // Lightning Shield + if (AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0)) + { + uint32 spell = sSpellMgr->GetSpellWithRank(26364, aurEff->GetSpellInfo()->GetRank()); + CastSpell(target, spell, true, castItem, triggeredByAura); + aurEff->GetBase()->DropCharge(); + return true; + } + return false; + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Improved Blood Presence + if (dummySpell->SpellIconID == 2636) + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + break; + } + // Butchery + if (dummySpell->SpellIconID == 2664) + { + basepoints0 = triggerAmount; + triggered_spell_id = 50163; + target = this; + break; + } + // Mark of Blood + if (dummySpell->Id == 49005) + { + // TODO: need more info (cooldowns/PPM) + triggered_spell_id = 61607; + break; + } + // Unholy Blight + if (dummySpell->Id == 49194) + { + triggered_spell_id = 50536; + SpellInfo const* unholyBlight = sSpellMgr->GetSpellInfo(triggered_spell_id); + if (!unholyBlight || !victim) + return false; + + basepoints0 = CalculatePct(int32(damage), triggerAmount); + + //Glyph of Unholy Blight + if (AuraEffect* glyph = GetAuraEffect(63332, 0)) + AddPct(basepoints0, glyph->GetAmount()); + + basepoints0 = basepoints0 / (unholyBlight->GetMaxDuration() / unholyBlight->Effects[0].Amplitude); + victim->CastDelayedSpellWithPeriodicAmount(this, triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); + return true; + } + // Vendetta + if (dummySpell->SpellFamilyFlags[0] & 0x10000) + { + basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); + triggered_spell_id = 50181; + target = this; + break; + } + // Necrosis + if (dummySpell->SpellIconID == 2709) + { + basepoints0 = CalculatePct(int32(damage), triggerAmount); + triggered_spell_id = 51460; + break; + } + // Threat of Thassarian + if (dummySpell->SpellIconID == 2023) + { + // Must Dual Wield + if (!procSpell || !haveOffhandWeapon()) + return false; + // Chance as basepoints for dummy aura + if (!roll_chance_i(triggerAmount)) + return false; + + switch (procSpell->Id) + { + // Obliterate + case 49020: + triggered_spell_id = 66198; + break; // Rank 1 + case 51423: + triggered_spell_id = 66972; + break; // Rank 2 + case 51424: + triggered_spell_id = 66973; + break; // Rank 3 + case 51425: + triggered_spell_id = 66974; + break; // Rank 4 + + // Frost Strike + case 49143: + triggered_spell_id = 66196; + break; // Rank 1 + case 51416: + triggered_spell_id = 66958; + break; // Rank 2 + case 51417: + triggered_spell_id = 66959; + break; // Rank 3 + case 51418: + triggered_spell_id = 66960; + break; // Rank 4 + case 51419: + triggered_spell_id = 66961; + break; // Rank 5 + case 55268: + triggered_spell_id = 66962; + break; // Rank 6 + + // Plague Strike + case 45462: + triggered_spell_id = 66216; + break; // Rank 1 + case 49917: + triggered_spell_id = 66988; + break; // Rank 2 + case 49918: + triggered_spell_id = 66989; + break; // Rank 3 + case 49919: + triggered_spell_id = 66990; + break; // Rank 4 + case 49920: + triggered_spell_id = 66991; + break; // Rank 5 + case 49921: + triggered_spell_id = 66992; + break; // Rank 6 + + // Death Strike + case 49998: + triggered_spell_id = 66188; + break; // Rank 1 + case 49999: + triggered_spell_id = 66950; + break; // Rank 2 + case 45463: + triggered_spell_id = 66951; + break; // Rank 3 + case 49923: + triggered_spell_id = 66952; + break; // Rank 4 + case 49924: + triggered_spell_id = 66953; + break; // Rank 5 + + // Rune Strike + case 56815: + triggered_spell_id = 66217; + break; // Rank 1 + + // Blood Strike + case 45902: + triggered_spell_id = 66215; + break; // Rank 1 + case 49926: + triggered_spell_id = 66975; + break; // Rank 2 + case 49927: + triggered_spell_id = 66976; + break; // Rank 3 + case 49928: + triggered_spell_id = 66977; + break; // Rank 4 + case 49929: + triggered_spell_id = 66978; + break; // Rank 5 + case 49930: + triggered_spell_id = 66979; + break; // Rank 6 + default: + return false; + } + + // This should do, restore spell mod so next attack can also use this! + // crit chance for first strike is already computed + ToPlayer()->RestoreSpellMods(m_currentSpells[CURRENT_GENERIC_SPELL], 51124, nullptr); // Killing Machine + ToPlayer()->RestoreSpellMods(m_currentSpells[CURRENT_GENERIC_SPELL], 49796, nullptr); // Deathchill + + // Xinef: Somehow basepoints are divided by 2 which is later divided by 2 (offhand multiplier) + SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); + if (triggerEntry->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) + basepoints0 = triggerEntry->Effects[EFFECT_0].BasePoints * 2; + + SetCantProc(true); + if(basepoints0) + CastCustomSpell(target, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); + else + CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); + SetCantProc(false); + return true; + } + // Runic Power Back on Snare/Root + if (dummySpell->Id == 61257) + { + // only for spells and hit/crit (trigger start always) and not start from self casted spells + if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) + return false; + // Need snare or root mechanic + if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE)))) + return false; + triggered_spell_id = 61258; + target = this; + break; + } + // Sudden Doom + if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER) + { + SpellChainNode const* chain = nullptr; + // get highest rank of the Death Coil spell + PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + // check if shown in spell book + if (!itr->second->Active || !itr->second->IsInSpec(ToPlayer()->GetActiveSpec()) || itr->second->State == PLAYERSPELL_REMOVED) + continue; + + SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(itr->first); + if (!spellProto) + continue; + + if (spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT + && spellProto->SpellFamilyFlags[0] & 0x2000) + { + SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first); + + // No chain entry or entry lower than found entry + if (!chain || !newChain || (chain->rank < newChain->rank)) + { + triggered_spell_id = itr->first; + chain = newChain; + } + else + continue; + // Found spell is last in chain - do not need to look more + // Optimisation for most common case + if (chain && chain->last->Id == itr->first) + break; + } + } + } + break; + } + case SPELLFAMILY_POTION: + { + // alchemist's stone + if (dummySpell->Id == 17619) + { + if (procSpell->SpellFamilyName == SPELLFAMILY_POTION) + { + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) + { + if (procSpell->Effects[i].Effect == SPELL_EFFECT_HEAL) + { + triggered_spell_id = 21399; + } + else if (procSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) + { + triggered_spell_id = 21400; + } + else + continue; + + basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f); + CastCustomSpell(this, triggered_spell_id, &basepoints0, nullptr, nullptr, true, nullptr, triggeredByAura); + } + return true; + } + } + break; + } + case SPELLFAMILY_PET: + { + switch (dummySpell->SpellIconID) + { + // Guard Dog + case 201: + { + if (!victim) + return false; + + triggered_spell_id = 54445; + target = this; + float addThreat = float(CalculatePct(procSpell->Effects[0].CalcValue(this), triggerAmount)); + victim->AddThreat(this, addThreat); + break; + } + // Silverback + case 1582: + triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800; + target = this; + break; + } + break; + } + default: + break; + } + + // if not handled by custom case, get triggered spell from dummySpell proto + if (!triggered_spell_id) + triggered_spell_id = dummySpell->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; + + // processed charge only counting case + if (!triggered_spell_id) + return true; + + SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); + if (!triggerEntry) + { + LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: Spell {} has non-existing triggered spell {}", dummySpell->Id, triggered_spell_id); + return false; + } + + if (cooldown_spell_id == 0) + cooldown_spell_id = triggered_spell_id; + + if (cooldown) + { + if (HasSpellCooldown(cooldown_spell_id)) + return false; + + AddSpellCooldown(cooldown_spell_id, 0, cooldown); + } + + if(basepoints0) + CastCustomSpell(target, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster); + else + CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); + + return true; +} + +// Used in case when access to whole aura is needed +// All procs should be handled like this... +bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool* handled) +{ + SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); + + switch (dummySpell->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch (dummySpell->Id) + { + // Nevermelting Ice Crystal + case 71564: + RemoveAuraFromStack(71564); + *handled = true; + break; + // Gaseous Bloat + case 70672: + case 72455: + case 72832: + case 72833: + { + if (Unit* caster = triggeredByAura->GetCaster()) + if (victim && caster->GetGUID() == victim->GetGUID()) + { + *handled = true; + uint32 stack = triggeredByAura->GetStackAmount(); + int32 const mod = (GetMap()->GetSpawnMode() & 1) ? 1500 : 1250; + int32 dmg = 0; + for (uint8 i = 1; i <= stack; ++i) + dmg += mod * i; + caster->CastCustomSpell(70701, SPELLVALUE_BASE_POINT0, dmg); + } + break; + } + // Ball of Flames Proc + case 71756: + case 72782: + case 72783: + case 72784: + RemoveAuraFromStack(dummySpell->Id); + *handled = true; + break; + // Discerning Eye of the Beast + case 59915: + { + CastSpell(this, 59914, true); // 59914 already has correct basepoints in DBC, no need for custom bp + *handled = true; + break; + } + // Swift Hand of Justice + case 59906: + { + int32 bp0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_0]. CalcValue()); + CastCustomSpell(this, 59913, &bp0, nullptr, nullptr, true); + *handled = true; + break; + } + } + + break; + case SPELLFAMILY_MAGE: + { + // Combustion + switch (dummySpell->Id) + { + case 11129: + { + *handled = true; + Unit* caster = triggeredByAura->GetCaster(); + if (!caster || !damage) + return false; + + // last charge and crit + if (triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT)) + return true; // charge counting (will removed) + + CastSpell(this, 28682, true); + + return procEx & PROC_EX_CRITICAL_HIT; + } + // Empowered Fire + case 31656: + case 31657: + case 31658: + { + *handled = true; + + SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(67545); + if (!spInfo) + return false; + + int32 bp0 = int32(CalculatePct(GetMaxPower(POWER_MANA), spInfo->Effects[0].CalcValue())); + CastCustomSpell(this, 67545, &bp0, nullptr, nullptr, true, nullptr, triggeredByAura->GetEffect(EFFECT_0), GetGUID()); + return true; + } + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Blood of the North + // Reaping + // Death Rune Mastery + // xinef: Icon 22 is used for item bonus, skip + if (dummySpell->SpellIconID == 3041 || (dummySpell->SpellIconID == 22 && dummySpell->Id != 62459) || dummySpell->SpellIconID == 2622) + { + *handled = true; + // Convert recently used Blood Rune to Death Rune + if (Player* player = ToPlayer()) + { + if (player->getClass() != CLASS_DEATH_KNIGHT) + return false; + + // xinef: not true + //RuneType rune = ToPlayer()->GetLastUsedRune(); + // can't proc from death rune use + //if (rune == RUNE_DEATH) + // return false; + AuraEffect* aurEff = triggeredByAura->GetEffect(EFFECT_0); + if (!aurEff) + return false; + + // Reset amplitude - set death rune remove timer to 30s + aurEff->ResetPeriodic(true); + uint32 runesLeft; + + if (dummySpell->SpellIconID == 2622) + runesLeft = 2; + else + runesLeft = 1; + + for (uint8 i = 0; i < MAX_RUNES && runesLeft; ++i) + { + if (dummySpell->SpellIconID == 2622) + { + if (player->GetCurrentRune(i) == RUNE_DEATH || + player->GetBaseRune(i) == RUNE_BLOOD) + continue; + } + else + { + if (player->GetCurrentRune(i) == RUNE_DEATH || + player->GetBaseRune(i) != RUNE_BLOOD) + continue; + } + if (player->GetRuneCooldown(i) != player->GetRuneBaseCooldown(i, false)) + continue; + + --runesLeft; + // Mark aura as used + player->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff); + } + return true; + } + return false; + } + break; + } + case SPELLFAMILY_WARRIOR: + { + switch (dummySpell->Id) + { + // Item - Warrior T10 Protection 4P Bonus + case 70844: + { + int32 basepoints0 = CalculatePct(GetMaxHealth(), dummySpell->Effects[EFFECT_1]. CalcValue()); + CastCustomSpell(this, 70845, &basepoints0, nullptr, nullptr, true); + break; + } + default: + break; + } + break; + } + case SPELLFAMILY_SHAMAN: + { + // Flurry + if ((dummySpell->SpellFamilyFlags[1] & 0x00000200) != 0) + { + if (cooldown) + { + if (HasSpellCooldown(dummySpell->Id)) + { + *handled = true; + break; + } + + AddSpellCooldown(dummySpell->Id, 0, cooldown); + } + } + break; + } + } + return false; +} + +bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo) +{ + // Get triggered aura spell info + SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo(); + + // Basepoints of trigger aura + int32 triggerAmount = triggeredByAura->GetAmount(); + + // Set trigger spell id, target, custom basepoints + uint32 trigger_spell_id = auraSpellInfo->Effects[triggeredByAura->GetEffIndex()].TriggerSpell; + + Unit* target = nullptr; + int32 basepoints0 = 0; + + if (triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE) + basepoints0 = triggerAmount; + + Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER + ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; + + // Try handle unknown trigger spells + //if (sSpellMgr->GetSpellInfo(trigger_spell_id) == nullptr) + { + switch (auraSpellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch (auraSpellInfo->Id) + { + case 43820: // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket) + // Pct value stored in dummy + if (!victim) + return false; + basepoints0 = victim->GetCreateHealth() * auraSpellInfo->Effects[1].CalcValue() / 100; + target = victim; + break; + case 57345: // Darkmoon Card: Greatness + { + float stat = 0.0f; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229; stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233; stat = GetStat(STAT_AGILITY); } + // intellect + if (GetStat(STAT_INTELLECT) > stat) { trigger_spell_id = 60234; stat = GetStat(STAT_INTELLECT);} + // spirit + if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235; } + break; + } + case 67702: // Death's Choice, Item - Coliseum 25 Normal Melee Trinket + { + if (!damage) + return false; + float stat = 0.0f; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67708; stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67703; } + break; + } + case 67771: // Death's Choice (heroic), Item - Coliseum 25 Heroic Melee Trinket + { + if (!damage) + return false; + float stat = 0.0f; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67773; stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67772; } + break; + } + // Mana Drain Trigger + case 27522: + case 40336: + { + // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target. + if (IsAlive()) + CastSpell(this, 29471, true, castItem, triggeredByAura); + if (victim && victim->IsAlive()) + CastSpell(victim, 27526, true, castItem, triggeredByAura); + return true; + } + // Forge of Souls, Devourer of Souls, Mirrored Soul + case 69023: + { + int32 dmg = damage * 0.45f; + if (dmg > 0) + if (Aura* a = GetAura(69023)) + if (Unit* c = a->GetCaster()) + CastCustomSpell(c, 69034, &dmg, 0, 0, true); + return true; + } + // Soul-Trader Beacon proc aura + case 50051: + { + if (!victim) + return false; + + if (Creature* cr = ObjectAccessor::GetCreature(*this, m_SummonSlot[SUMMON_SLOT_MINIPET])) + cr->CastSpell(victim, 50101, true); + + return false; + } + } + break; + case SPELLFAMILY_MAGE: + if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed + { + switch (auraSpellInfo->Id) + { + case 31641: // Rank 1 + case 31642: // Rank 2 + trigger_spell_id = 31643; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} miss posibly Blazing Speed", auraSpellInfo->Id); + return false; + } + } + else if (auraSpellInfo->Id == 71761) // Deep Freeze Immunity State (only permanent) + { + Creature* creature = victim->ToCreature(); + if (!creature || !creature->HasMechanicTemplateImmunity(1 << (MECHANIC_STUN - 1))) + return false; + } + break; + case SPELLFAMILY_WARLOCK: + { + // Nether Protection + if (auraSpellInfo->SpellIconID == 1985) + { + if (!procSpell) + return false; + switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: + trigger_spell_id = 54370; + break; + case SPELL_SCHOOL_FIRE: + trigger_spell_id = 54371; + break; + case SPELL_SCHOOL_NATURE: + trigger_spell_id = 54375; + break; + case SPELL_SCHOOL_FROST: + trigger_spell_id = 54372; + break; + case SPELL_SCHOOL_SHADOW: + trigger_spell_id = 54374; + break; + case SPELL_SCHOOL_ARCANE: + trigger_spell_id = 54373; + break; + default: + return false; + } + } + break; + } + case SPELLFAMILY_PRIEST: + { + // Blessed Recovery + if (auraSpellInfo->SpellIconID == 1875) + { + switch (auraSpellInfo->Id) + { + case 27811: + trigger_spell_id = 27813; + break; + case 27815: + trigger_spell_id = 27817; + break; + case 27816: + trigger_spell_id = 27818; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} not handled in BR", auraSpellInfo->Id); + return false; + } + basepoints0 = CalculatePct(int32(damage), triggerAmount) / 3; + target = this; + // Add remaining ticks to healing done + CastDelayedSpellWithPeriodicAmount(this, trigger_spell_id, SPELL_AURA_PERIODIC_HEAL, basepoints0); + return true; + } + break; + } + case SPELLFAMILY_DRUID: + { + switch (auraSpellInfo->Id) + { + // Druid Forms Trinket + case 37336: + { + switch (GetShapeshiftForm()) + { + case FORM_NONE: + trigger_spell_id = 37344; + break; + case FORM_CAT: + trigger_spell_id = 37341; + break; + case FORM_BEAR: + case FORM_DIREBEAR: + trigger_spell_id = 37340; + break; + case FORM_TREE: + trigger_spell_id = 37342; + break; + case FORM_MOONKIN: + trigger_spell_id = 37343; + break; + default: + return false; + } + break; + } + // Druid T9 Feral Relic (Lacerate, Swipe, Mangle, and Shred) + case 67353: + { + switch (GetShapeshiftForm()) + { + case FORM_CAT: + trigger_spell_id = 67355; + break; + case FORM_BEAR: + case FORM_DIREBEAR: + trigger_spell_id = 67354; + break; + default: + return false; + } + break; + } + default: + break; + } + break; + } + case SPELLFAMILY_HUNTER: + { + if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots + { + if (!victim) + return false; + + switch (auraSpellInfo->Id) + { + case 53234: // Rank 1 + case 53237: // Rank 2 + case 53238: // Rank 3 + trigger_spell_id = 63468; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} miss posibly Piercing Shots", auraSpellInfo->Id); + return false; + } + SpellInfo const* TriggerPS = sSpellMgr->GetSpellInfo(trigger_spell_id); + if (!TriggerPS) + return false; + + basepoints0 = CalculatePct(int32(damage), triggerAmount) / (TriggerPS->GetMaxDuration() / TriggerPS->Effects[0].Amplitude); + victim->CastDelayedSpellWithPeriodicAmount(this, trigger_spell_id, SPELL_AURA_PERIODIC_DAMAGE, basepoints0); + return true; + } + // Item - Hunter T9 4P Bonus (Steady Shot) + else if (auraSpellInfo->Id == 67151) + { + if (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetPet()) + return false; + + target = ToPlayer()->GetPet(); + trigger_spell_id = 68130; + break; + } + break; + } + case SPELLFAMILY_PALADIN: + { + switch (auraSpellInfo->Id) + { + // Soul Preserver + case 60510: + { + switch (getClass()) + { + case CLASS_DRUID: + trigger_spell_id = 60512; + break; + case CLASS_PALADIN: + trigger_spell_id = 60513; + break; + case CLASS_PRIEST: + trigger_spell_id = 60514; + break; + case CLASS_SHAMAN: + trigger_spell_id = 60515; + break; + } + + target = this; + break; + } + case 37657: // Lightning Capacitor + case 54841: // Thunder Capacitor + case 67712: // Item - Coliseum 25 Normal Caster Trinket + case 67758: // Item - Coliseum 25 Heroic Caster Trinket + { + if (!victim || !victim->IsAlive() || GetTypeId() != TYPEID_PLAYER) + return false; + + uint32 stack_spell_id = 0; + switch (auraSpellInfo->Id) + { + case 37657: + stack_spell_id = 37658; + trigger_spell_id = 37661; + break; + case 54841: + stack_spell_id = 54842; + trigger_spell_id = 54843; + break; + case 67712: + stack_spell_id = 67713; + trigger_spell_id = 67714; + break; + case 67758: + stack_spell_id = 67759; + trigger_spell_id = 67760; + break; + } + + if (cooldown && GetTypeId() == TYPEID_PLAYER) + { + if (ToPlayer()->HasSpellCooldown(stack_spell_id)) + return false; + + ToPlayer()->AddSpellCooldown(stack_spell_id, 0, cooldown); + } + + CastSpell(this, stack_spell_id, true, nullptr, triggeredByAura); + + Aura* dummy = GetAura(stack_spell_id); + if (!dummy || dummy->GetStackAmount() < triggerAmount) + return false; + + RemoveAurasDueToSpell(stack_spell_id); + CastSpell(victim, trigger_spell_id, true, nullptr, triggeredByAura); + return true; + } + default: + // Illumination + if (auraSpellInfo->SpellIconID == 241) + { + if (!procSpell) + return false; + // procspell is triggered spell but we need mana cost of original casted spell + uint32 originalSpellId = procSpell->Id; + // Holy Shock heal + if (procSpell->SpellFamilyFlags[1] & 0x00010000) + { + switch (procSpell->Id) + { + case 25914: + originalSpellId = 20473; + break; + case 25913: + originalSpellId = 20929; + break; + case 25903: + originalSpellId = 20930; + break; + case 27175: + originalSpellId = 27174; + break; + case 33074: + originalSpellId = 33072; + break; + case 48820: + originalSpellId = 48824; + break; + case 48821: + originalSpellId = 48825; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} not handled in HShock", procSpell->Id); + return false; + } + } + SpellInfo const* originalSpell = sSpellMgr->GetSpellInfo(originalSpellId); + if (!originalSpell) + { + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} unknown but selected as original in Illu", originalSpellId); + return false; + } + // percent stored in effect 1 (class scripts) base points + int32 cost = int32(originalSpell->ManaCost + CalculatePct(GetCreateMana(), originalSpell->ManaCostPercentage)); + basepoints0 = CalculatePct(cost, auraSpellInfo->Effects[1].CalcValue()); + trigger_spell_id = 20272; + target = this; + } + break; + } + break; + } + case SPELLFAMILY_SHAMAN: + { + // Lightning Shield (overwrite non existing triggered spell call in spell.dbc + if (auraSpellInfo->SpellFamilyFlags[0] & 0x400) + { + // Do not proc off from self-casted items + if (Spell const* spell = eventInfo.GetProcSpell()) + { + if (spell->m_castItemGUID && victim->GetGUID() == GetGUID()) + { + return false; + } + } + + trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, auraSpellInfo->GetRank()); + } + // Nature's Guardian + else if (auraSpellInfo->SpellIconID == 2013) + { + // Check health condition - should drop to less 30% (damage deal after this!) + if (!HealthBelowPctDamaged(30, damage)) + return false; + + if (victim && victim->IsAlive()) + victim->GetThreatMgr().ModifyThreatByPercent(this, -10); + + basepoints0 = int32(CountPctFromMaxHealth(triggerAmount)); + trigger_spell_id = 31616; + target = this; + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Acclimation + if (auraSpellInfo->SpellIconID == 1930) + { + if (!procSpell) + return false; + switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: + trigger_spell_id = 50490; + break; + case SPELL_SCHOOL_FIRE: + trigger_spell_id = 50362; + break; + case SPELL_SCHOOL_NATURE: + trigger_spell_id = 50488; + break; + case SPELL_SCHOOL_FROST: + trigger_spell_id = 50485; + break; + case SPELL_SCHOOL_SHADOW: + trigger_spell_id = 50489; + break; + case SPELL_SCHOOL_ARCANE: + trigger_spell_id = 50486; + break; + default: + return false; + } + } + // Blood Presence (Improved) + else if (auraSpellInfo->Id == 63611) + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + trigger_spell_id = 50475; + basepoints0 = CalculatePct(int32(damage), triggerAmount); + } + break; + } + } + } + + // All ok. Check current trigger spell + SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id); + if (!triggerEntry) + { + // Don't cast unknown spell + LOG_ERROR("entities.unit", "Unit::HandleProcTriggerSpell: Spell {} (effIndex: {}) has unknown TriggerSpell {}. Unhandled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex(), trigger_spell_id); + return false; + } + + // not allow proc extra attack spell at extra attack + if (triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + { + uint32 lastExtraAttackSpell = eventInfo.GetActor()->GetLastExtraAttackSpell(); + + // Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves + if (lastExtraAttackSpell == trigger_spell_id) + { + return false; + } + + // Patch 2.2.0 Sword Specialization (Warrior, Rogue) extra attack can no longer proc additional extra attacks + // 3.3.5 Sword Specialization (Warrior), Hack and Slash (Rogue) + if (lastExtraAttackSpell == 16459 || lastExtraAttackSpell == 66923) + { + return false; + } + } + + // Custom requirements (not listed in procEx) Warning! damage dealing after this + // Custom triggered spells + switch (auraSpellInfo->Id) + { + // Deep Wounds + case 12834: + case 12849: + case 12867: + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + if (procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK) + basepoints0 = int32((GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE)) / 2.0f); + else + basepoints0 = int32((GetFloatValue(UNIT_FIELD_MAXDAMAGE) + GetFloatValue(UNIT_FIELD_MINDAMAGE)) / 2.0f); + break; + } + // Persistent Shield (Scarab Brooch trinket) + // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect) + case 26467: + { + basepoints0 = int32(CalculatePct(damage, 15)); + target = victim; + trigger_spell_id = 26470; + break; + } + // Unyielding Knights (item exploit 29108\29109) + case 38164: + { + if (!victim || victim->GetEntry() != 19457) // Proc only if your target is Grillok + return false; + break; + } + // Deflection + case 52420: + { + if (!HealthBelowPct(35)) + return false; + break; + } + + // Cheat Death + case 28845: + { + // When your health drops below 20% + if (HealthBelowPctDamaged(20, damage) || HealthBelowPct(20)) + return false; + break; + } + // Deadly Swiftness (Rank 1) + case 31255: + { + // whenever you deal damage to a target who is below 20% health. + if (!victim || !victim->IsAlive() || victim->HealthAbovePct(20)) + return false; + + target = this; + trigger_spell_id = 22588; + [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. + } + // Bonus Healing (Crystal Spire of Karabor mace) + case 40971: + { + // If your target is below $s1% health + if (!victim || !victim->IsAlive() || victim->HealthAbovePct(triggerAmount)) + return false; + break; + } + // Rapid Recuperation + case 53228: + case 53232: + { + // This effect only from Rapid Fire (ability cast) + if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x20)) + return false; + break; + } + // Decimation + case 63156: + case 63158: + // Can proc only if target has hp below 35% + if (!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this)) + return false; + break; + // Ulduar, Hodir, Toasty Fire + case 62821: + if (this->GetTypeId() != TYPEID_PLAYER) // spell has Attribute, but persistent area auras ignore it + return false; + break; + case 15337: // Improved Spirit Tap (Rank 1) + case 15338: // Improved Spirit Tap (Rank 2) + { + if (!procSpell) + return false; + + if (procSpell->SpellFamilyFlags[0] & 0x800000) + if ((procSpell->Id != 58381) || !roll_chance_i(50)) + return false; + + target = victim; + break; + } + // Professor Putricide - Ooze Spell Tank Protection + case 71770: + if (victim) + victim->CastSpell(victim, trigger_spell_id, true); // EffectImplicitTarget is self + return true; + case 45057: // Evasive Maneuvers (Commendation of Kael`thas trinket) + case 71634: // Item - Icecrown 25 Normal Tank Trinket 1 + case 71640: // Item - Icecrown 25 Heroic Tank Trinket 1 + case 75475: // Item - Chamber of Aspects 25 Normal Tank Trinket + case 75481: // Item - Chamber of Aspects 25 Heroic Tank Trinket + { + // Procs only if damage takes health below $s1% + if (!HealthBelowPctDamaged(triggerAmount, damage)) + return false; + break; + } + default: + break; + } + + if (auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT) + { + // Xinef: keep this order, Aura 70656 has SpellIconID 85! + // Item - Death Knight T10 Melee 4P Bonus + if (auraSpellInfo->Id == 70656) + { + if (GetTypeId() != TYPEID_PLAYER || getClass() != CLASS_DEATH_KNIGHT) + return false; + + for (uint8 i = 0; i < MAX_RUNES; ++i) + if (ToPlayer()->GetRuneCooldown(i) == 0) + return false; + } + // Blade Barrier + else if (auraSpellInfo->SpellIconID == 85) + { + Player* plr = ToPlayer(); + if (!plr || plr->getClass() != CLASS_DEATH_KNIGHT || !procSpell) + return false; + + if (!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) + return false; + } + // Rime + else if (auraSpellInfo->SpellIconID == 56) + { + if (GetTypeId() != TYPEID_PLAYER) + return false; + + // Howling Blast + ToPlayer()->RemoveCategoryCooldown(1248); + } + } + + // Custom basepoints/target for exist spell + // dummy basepoints or other customs + switch (trigger_spell_id) + { + // Auras which should proc on area aura source (caster in this case): + // Turn the Tables + case 52914: + case 52915: + case 52910: + // Honor Among Thieves + case 51699: + { + target = triggeredByAura->GetBase()->GetCaster(); + if (!target) + return false; + + if (Player* pTarget = target->ToPlayer()) + { + if (cooldown) + { + if (pTarget->HasSpellCooldown(trigger_spell_id) ) + return false; + pTarget->AddSpellCooldown(trigger_spell_id, 0, cooldown); + } + + Unit* cptarget = nullptr; + if (trigger_spell_id == 51699) + { + cptarget = pTarget->GetComboTarget(); + if (!cptarget) + { + cptarget = pTarget->GetSelectedUnit(); + } + } + else + cptarget = target; + + if (cptarget) + { + target->CastSpell(cptarget, trigger_spell_id, true); + return true; + } + } + return false; + } + // Cast positive spell on enemy target + case 7099: // Curse of Mending + case 39703: // Curse of Mending + case 29494: // Temptation + case 20233: // Improved Lay on Hands (cast on target) + { + target = victim; + break; + } + // Ruby Drake, Evasive Aura + case 50241: + { + if( GetAura(50240) ) + return false; + + break; + } + // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset) + case 15250: // Rogue Setup + { + // applied only for main target + if (!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit())) + return false; + break; // continue normal case + } + // Finish movies that add combo + case 14189: // Seal Fate (Netherblade set) + case 14157: // Ruthlessness + { + victim = nullptr; + // Need add combopoint AFTER finish movie (or they dropped in finish phase) + break; + } + // Item - Druid T10 Balance 2P Bonus + case 16870: + { + if (HasAura(70718)) + CastSpell(this, 70721, true); + RemoveAurasDueToSpell(trigger_spell_id); + break; + } + // Shamanistic Rage triggered spell + case 30824: + { + basepoints0 = int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount)); + break; + } + // Enlightenment (trigger only from mana cost spells) + case 35095: + { + if (!procSpell || procSpell->PowerType != POWER_MANA || (procSpell->ManaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->ManaCostPerlevel == 0)) + return false; + break; + } + // Demonic Pact + case 48090: + { + // Get talent aura from owner + if (IsPet()) + if (Unit* owner = GetOwner()) + { + if (HasSpellCooldown(trigger_spell_id)) + return false; + AddSpellCooldown(trigger_spell_id, 0, cooldown); + + if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0)) + { + int32 spellPower = owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)); + if (AuraEffect const* demonicAuraEffect = GetAuraEffect(trigger_spell_id, EFFECT_0)) + spellPower -= demonicAuraEffect->GetAmount(); + + basepoints0 = int32((aurEff->GetAmount() * spellPower + 100.0f) / 100.0f); + CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, nullptr, true, castItem, triggeredByAura); + return true; + } + } + break; + } + case 46916: // Slam! (Bloodsurge proc) + case 52437: // Sudden Death + { + // Item - Warrior T10 Melee 4P Bonus + if (AuraEffect const* aurEff = GetAuraEffect(70847, 0)) + { + if (!roll_chance_i(aurEff->GetAmount())) + { + // Xinef: dont allow normal proc to override set one + if (GetAura((trigger_spell_id == 46916) ? 71072 : 71069)) + return false; + // Xinef: just to be sure + RemoveAurasDueToSpell(70849); + break; + } + + // Xinef: fully remove all auras and reapply once more + RemoveAurasDueToSpell(70849); + RemoveAurasDueToSpell(71072); + RemoveAurasDueToSpell(71069); + + CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge! + if (trigger_spell_id == 46916) + CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced + else + CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced + } + break; + } + // Sword and Board + case 50227: + { + // Remove cooldown on Shield Slam + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->RemoveCategoryCooldown(1209); + break; + } + // Maelstrom Weapon + case 53817: + { + // have rank dependent proc chance, ignore too often cases + // PPM = 2.5 * (rank of talent), + uint32 rank = auraSpellInfo->GetRank(); + // 5 rank -> 100% 4 rank -> 80% and etc from full rate + if (!roll_chance_i(20 * rank)) + return false; + + // Item - Shaman T10 Enhancement 4P Bonus + if (AuraEffect const* aurEff = GetAuraEffect(70832, 0)) + if (Aura const* maelstrom = GetAura(53817)) + // xinef: we have 4 charges and all proc conditions are met - aura reaches 5 charges + if ((maelstrom->GetStackAmount() == 4) && roll_chance_i(aurEff->GetAmount())) + CastSpell(this, 70831, true, castItem, triggeredByAura); + + break; + } + // Astral Shift + case 52179: + { + if (!procSpell || !(procEx & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) || this == victim) + return false; + + // Need stun, fear or silence mechanic + if (!(procSpell->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR)))) + return false; + break; + } + // Glyph of Death's Embrace + case 58679: + { + // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags + if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000)) + return false; + break; + } + // Glyph of Death Grip + case 58628: + { + // remove cooldown of Death Grip + if (GetTypeId() == TYPEID_PLAYER) + ToPlayer()->RemoveSpellCooldown(49576, true); + return true; + } + // Savage Defense + case 62606: + { + basepoints0 = CalculatePct(triggerAmount, GetTotalAttackPowerValue(BASE_ATTACK)); + break; + } + // Body and Soul + case 64128: + case 65081: + { + // Proc only from PW:S cast + if (!procSpell || !(procSpell->SpellFamilyFlags[0] & 0x00000001)) + return false; + break; + } + // Culling the Herd + case 70893: + { + if (!procSpell) + { + return false; + } + // check if we're doing a critical hit + if (!(procSpell->SpellFamilyFlags[1] & 0x10000000) && (procEx != PROC_EX_CRITICAL_HIT)) + return false; + // check if we're procced by Claw, Bite or Smack (need to use the spell icon ID to detect it) + if (!(procSpell->SpellIconID == 262 || procSpell->SpellIconID == 1680 || procSpell->SpellIconID == 473)) + return false; + break; + } + // Fingers of Frost, synchronise with Frostbite + case 44544: + { + if (procPhase == PROC_SPELL_PHASE_HIT) + { + // Find Frostbite + if (AuraEffect* aurEff = this->GetAuraEffect(SPELL_AURA_ADD_TARGET_TRIGGER, SPELLFAMILY_MAGE, 119, EFFECT_0)) + { + if (!victim) + return false; + + uint8 fofRank = sSpellMgr->GetSpellRank(triggeredByAura->GetId()); + uint8 fbRank = sSpellMgr->GetSpellRank(aurEff->GetId()); + uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f)); + + if (roll_chance_i(chance)) + CastSpell(victim, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); + } + } + break; + } + } + + // try detect target manually if not set + if (!target) + target = !(procFlags & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry->IsPositive() ? this : victim; + + if (cooldown) + { + if (HasSpellCooldown(triggerEntry->Id)) + return false; + + AddSpellCooldown(triggerEntry->Id, 0, cooldown); + } + + if(basepoints0) + CastCustomSpell(target, triggerEntry->Id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura); + else + CastSpell(target, triggerEntry->Id, true, castItem, triggeredByAura); + + return true; +} + +bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown) +{ + int32 scriptId = triggeredByAura->GetMiscValue(); + + if (!victim || !victim->IsAlive()) + return false; + + Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER + ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : nullptr; + + uint32 triggered_spell_id = 0; + + switch (scriptId) + { + case 836: // Improved Blizzard (Rank 1) + { + if (!procSpell || procSpell->SpellVisual[0] != 9487) + return false; + triggered_spell_id = 12484; + break; + } + case 988: // Improved Blizzard (Rank 2) + { + if (!procSpell || procSpell->SpellVisual[0] != 9487) + return false; + triggered_spell_id = 12485; + break; + } + case 989: // Improved Blizzard (Rank 3) + { + if (!procSpell || procSpell->SpellVisual[0] != 9487) + return false; + triggered_spell_id = 12486; + break; + } + case 4533: // Dreamwalker Raiment 2 pieces bonus + { + // Chance 50% + if (!roll_chance_i(50)) + return false; + + switch (victim->getPowerType()) + { + case POWER_MANA: + triggered_spell_id = 28722; + break; + case POWER_RAGE: + triggered_spell_id = 28723; + break; + case POWER_ENERGY: + triggered_spell_id = 28724; + break; + default: + return false; + } + break; + } + case 4537: // Dreamwalker Raiment 6 pieces bonus + triggered_spell_id = 28750; // Blessing of the Claw + break; + case 5497: // Improved Mana Gems + triggered_spell_id = 37445; // Mana Surge + break; + case 7010: // Revitalize - can proc on full hp target + case 7011: + case 7012: + { + if (!roll_chance_i(triggeredByAura->GetAmount())) + return false; + switch (victim->getPowerType()) + { + case POWER_MANA: + triggered_spell_id = 48542; + break; + case POWER_RAGE: + triggered_spell_id = 48541; + break; + case POWER_ENERGY: + triggered_spell_id = 48540; + break; + case POWER_RUNIC_POWER: + triggered_spell_id = 48543; + break; + default: + break; + } + break; + } + default: + break; + } + + // not processed + if (!triggered_spell_id) + return false; + + // standard non-dummy case + SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); + + if (!triggerEntry) + { + LOG_ERROR("entities.unit", "Unit::HandleOverrideClassScriptAuraProc: Spell {} triggering for class script id {}", triggered_spell_id, scriptId); + return false; + } + + if (cooldown) + { + if (HasSpellCooldown(triggered_spell_id)) + return false; + + AddSpellCooldown(triggered_spell_id, 0, cooldown); + } + + CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura); + + return true; +} + void Unit::setPowerType(Powers new_powertype) { SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype); @@ -6230,7 +9660,7 @@ void Unit::setPowerType(Powers new_powertype) break; } - if (const Player* player = ToPlayer()) + if (Player const* player = ToPlayer()) if (player->NeedSendSpectatorData()) { ArenaSpectator::SendCommand_UInt32Value(FindMap(), GetGUID(), "PWT", new_powertype); @@ -6335,7 +9765,7 @@ ReputationRank Unit::GetReactionTo(Unit const* target, bool checkOriginalFaction { // check contested flags if (targetFactionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS - && selfPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) + && selfPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) return REP_HOSTILE; // if faction has reputation, hostile state depends only from AtWar state @@ -6408,7 +9838,7 @@ ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTem { // check contested flags if (factionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS - && targetPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) + && targetPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP)) return REP_HOSTILE; if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry)) return *repRank; @@ -6750,8 +10180,8 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co if (spellProto) { AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); - for (AuraEffect const* aurEff : stateAuras) - if (aurEff->IsAffectedOnSpell(spellProto)) + for (AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j) + if ((*j)->IsAffectedOnSpell(spellProto)) return true; } // Check per caster aura state @@ -7147,12 +10577,9 @@ void Unit::SetCharm(Unit* charm, bool apply) } } -void Unit::DealHeal(HealInfo& healInfo) +int32 Unit::DealHeal(Unit* healer, Unit* victim, uint32 addhealth) { int32 gain = 0; - Unit* victim = healInfo.GetTarget(); - Unit* healer = healInfo.GetHealer(); - uint32 addhealth = healInfo.GetHeal(); if (healer) { @@ -7175,7 +10602,7 @@ void Unit::DealHeal(HealInfo& healInfo) unit = healer->GetOwner(); if (!unit) - return; + return gain; if (Player* player = unit->ToPlayer()) { @@ -7195,10 +10622,7 @@ void Unit::DealHeal(HealInfo& healInfo) //player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth); // pussywizard: optimization }*/ - if (gain) - { - healInfo.SetEffectiveHeal(gain > 0 ? static_cast(gain) : 0UL); - } + return gain; } bool RedirectSpellEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) @@ -7429,16 +10853,16 @@ void Unit::UnsummonAllTotems(bool onDeath /*= false*/) } } -void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/) +void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical) { // we guess size WorldPacket data(SMSG_SPELLHEALLOG, (8 + 8 + 4 + 4 + 4 + 4 + 1 + 1)); - data << healInfo.GetTarget()->GetPackGUID(); - data << healInfo.GetHealer()->GetPackGUID(); - data << uint32(healInfo.GetSpellInfo()->Id); - data << uint32(healInfo.GetHeal()); - data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal()); - data << uint32(healInfo.GetAbsorb()); // Absorb amount + data << victim->GetPackGUID(); + data << GetPackGUID(); + data << uint32(SpellID); + data << uint32(Damage); + data << uint32(OverHeal); + data << uint32(Absorb); // Absorb amount data << uint8(critical ? 1 : 0); data << uint8(0); // unused SendMessageToSet(&data, true); @@ -7453,9 +10877,9 @@ int32 Unit::HealBySpell(HealInfo& healInfo, bool critical) // calculate heal absorb and reduce healing CalcHealAbsorb(healInfo); - DealHeal(healInfo); - SendHealSpellLog(healInfo, critical); - return healInfo.GetEffectiveHeal(); + int32 gain = Unit::DealHeal(healInfo.GetHealer(), healInfo.GetTarget(), healInfo.GetHeal()); + SendHealSpellLog(healInfo.GetTarget(), healInfo.GetSpellInfo()->Id, healInfo.GetHeal(), uint32(healInfo.GetHeal() - gain), healInfo.GetAbsorb(), critical); + return gain; } void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) @@ -7471,15 +10895,15 @@ void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Pow void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) { - SendEnergizeSpellLog(victim, spellID, damage, powerType); - // needs to be called after sending spell log - victim->ModifyPower(powerType, damage); + victim->ModifyPower(powerType, damage, false); if (powerType != POWER_HAPPINESS) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); victim->getHostileRefMgr().threatAssist(this, float(damage) * 0.5f, spellInfo); } + + SendEnergizeSpellLog(victim, spellID, damage, powerType); } float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) @@ -7941,7 +11365,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, coeff); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); coeff /= 100.0f; } @@ -7951,16 +11375,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin float tmpDamage = (float(pdamage) + DoneTotal) * DoneTotalMod; // apply spellmod to Done damage (flat and pct) if (Player* modOwner = GetSpellModOwner()) - { - if (damagetype == DOT) - { - modOwner->ApplySpellMod(spellProto->Id, tmpDamage); - } - else - { - modOwner->ApplySpellMod(spellProto->Id, tmpDamage); - } - } + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); return uint32(std::max(tmpDamage, 0.0f)); } @@ -8237,7 +11652,7 @@ float Unit::SpellDoneCritChance(Unit const* /*victim*/, SpellInfo const* spellPr // percent done // only players use intelligence for critical chance computations if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, crit_chance); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); // xinef: can be negative! return crit_chance; @@ -8487,7 +11902,7 @@ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spell // adds additional damage to critBonus (from talents) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, crit_bonus); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); crit_bonus += damage; } @@ -8522,7 +11937,7 @@ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spel // adds additional damage to critBonus (from talents) // xinef: used for death knight death coil if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, crit_bonus); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); } if (crit_bonus > 0) @@ -8707,7 +12122,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, coeff); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); coeff /= 100.0f; } DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); @@ -8732,16 +12147,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui // apply spellmod to Done amount if (Player* modOwner = GetSpellModOwner()) - { - if (damagetype == DOT) - { - modOwner->ApplySpellMod(spellProto->Id, heal); - } - else - { - modOwner->ApplySpellMod(spellProto->Id, heal); - } - } + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); return uint32(std::max(heal, 0.0f)); } @@ -8837,7 +12243,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, coeff); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); coeff /= 100.0f; } @@ -9344,7 +12750,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType // apply spellmod to Done damage if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, tmpDamage); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage); // bonus result can be negative return uint32(std::max(tmpDamage, 0.0f)); @@ -9534,7 +12940,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spe // Apply chance modifer aura if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, PPM); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM); return floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } @@ -9961,7 +13367,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // can't attack invisible (ignore stealth for aoe spells) also if the area being looked at is from a spell use the dynamic object created instead of the casting unit. //Ignore stealth if target is player and unit in combat with same player - if (GetEntry() != WORLD_TRIGGER && (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target))))) + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT)) && (obj ? !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()) : !CanSeeOrDetect(target, (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target))))) return false; // can't attack dead @@ -10209,7 +13615,7 @@ int32 Unit::GetHealthGain(int32 dVal) } // returns negative amount on power reduction -int32 Unit::ModifyPower(Powers power, int32 dVal) +int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/) { if (dVal == 0) return 0; @@ -10221,7 +13627,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) int32 val = dVal + curPower; if (val <= 0) { - SetPower(power, 0); + SetPower(power, 0, withPowerUpdate); return -curPower; } @@ -10229,12 +13635,12 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) if (val < maxPower) { - SetPower(power, val); + SetPower(power, val, withPowerUpdate); gain = val - curPower; } else if (curPower != maxPower) { - SetPower(power, maxPower); + SetPower(power, maxPower, withPowerUpdate); gain = maxPower - curPower; } @@ -10860,17 +14266,17 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index { if (Player* modOwner = GetSpellModOwner()) { - modOwner->ApplySpellMod(spellProto->Id, value); + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value); switch (effect_index) { - case EFFECT_0: - modOwner->ApplySpellMod(spellProto->Id, value); + case 0: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value); break; - case EFFECT_1: - modOwner->ApplySpellMod(spellProto->Id, value); + case 1: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value); break; - case EFFECT_2: - modOwner->ApplySpellMod(spellProto->Id, value); + case 2: + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value); break; } } @@ -11011,7 +14417,7 @@ void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime, Spell* // called from caster if (Player* modOwner = GetSpellModOwner()) // TODO:(MadAgos) Eventually check and delete the bool argument - modOwner->ApplySpellMod(spellInfo->Id, castTime, spell); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell, bool(modOwner != this && !IsPet())); switch (spellInfo->DmgClass) { @@ -11593,7 +14999,7 @@ void Unit::SetMaxHealth(uint32 val) SetHealth(val); } -void Unit::SetPower(Powers power, uint32 val) +void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/) { if (GetPower(power) == val) return; @@ -11604,11 +15010,14 @@ void Unit::SetPower(Powers power, uint32 val) SetStatInt32Value(static_cast(UNIT_FIELD_POWER1) + power, val); - WorldPacket data(SMSG_POWER_UPDATE); - data << GetPackGUID(); - data << uint8(power); - data << uint32(val); - SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); + if (withPowerUpdate) + { + WorldPacket data(SMSG_POWER_UPDATE); + data << GetPackGUID(); + data << uint8(power); + data << uint32(val); + SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER); + } // group update if (GetTypeId() == TYPEID_PLAYER) @@ -12099,6 +15508,92 @@ bool Unit::isFrozen() const return HasAuraState(AURA_STATE_FROZEN); } +struct ProcTriggeredData +{ + ProcTriggeredData(Aura* _aura) : aura(_aura) + { + effMask = 0; + spellProcEvent = nullptr; + triggerSpelId.fill(0); + } + + SpellProcEventEntry const* spellProcEvent; + Aura* aura; + uint32 effMask; + std::array triggerSpelId; + + bool operator==(const uint32 spellId) const + { + return aura->GetId() == spellId; + } +}; + +typedef std::list< ProcTriggeredData > ProcTriggeredList; + +// List of auras that CAN be trigger but may not exist in spell_proc_event +// in most case need for drop charges +// in some types of aura need do additional check +// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic +bool InitTriggerAuraData() +{ + for (uint16 i = 0; i < TOTAL_AURAS; ++i) + { + isTriggerAura[i] = false; + isNonTriggerAura[i] = false; + isAlwaysTriggeredAura[i] = false; + } + isTriggerAura[SPELL_AURA_DUMMY] = true; + isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; + isTriggerAura[SPELL_AURA_MOD_THREAT] = true; + isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger + isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; + isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; + isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; + isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; + isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger + isTriggerAura[SPELL_AURA_MOD_ROOT] = true; + isTriggerAura[SPELL_AURA_TRANSFORM] = true; + isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; + isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true; + isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true; + isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested + isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true; + isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true; + isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true; + isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true; + isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true; + isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true; + isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true; + isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true; + isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; + isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true; + isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true; + isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true; + isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true; + isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true; + isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; + isTriggerAura[SPELL_AURA_MOD_DAMAGE_FROM_CASTER] = true; + isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true; + isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true; + + isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN] = true; + isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK] = true; + + isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true; + isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true; + isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true; + isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true; + isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true; + + return true; +} + void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bool positive, uint32& procAttacker, uint32& procVictim) { if (spellInfo) @@ -12173,88 +15668,73 @@ void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bo } } -uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition) +uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition) { - uint32 hitMask = PROC_HIT_NONE; + uint32 procEx = PROC_EX_NONE; // Check victim state if (missCondition != SPELL_MISS_NONE) - { switch (missCondition) { case SPELL_MISS_MISS: - hitMask |= PROC_HIT_MISS; - break; - case SPELL_MISS_DODGE: - hitMask |= PROC_HIT_DODGE; - break; - case SPELL_MISS_PARRY: - hitMask |= PROC_HIT_PARRY; - break; - case SPELL_MISS_BLOCK: - // spells can't be partially blocked (it's damage can though) - hitMask |= PROC_HIT_BLOCK | PROC_HIT_FULL_BLOCK; - break; - case SPELL_MISS_EVADE: - hitMask |= PROC_HIT_EVADE; - break; - case SPELL_MISS_IMMUNE: - case SPELL_MISS_IMMUNE2: - hitMask |= PROC_HIT_IMMUNE; - break; - case SPELL_MISS_DEFLECT: - hitMask |= PROC_HIT_DEFLECT; - break; - case SPELL_MISS_ABSORB: - hitMask |= PROC_HIT_ABSORB; - break; - case SPELL_MISS_REFLECT: - hitMask |= PROC_HIT_REFLECT; + procEx |= PROC_EX_MISS; break; case SPELL_MISS_RESIST: - hitMask |= PROC_HIT_FULL_RESIST; + procEx |= PROC_EX_RESIST; + break; + case SPELL_MISS_DODGE: + procEx |= PROC_EX_DODGE; + break; + case SPELL_MISS_PARRY: + procEx |= PROC_EX_PARRY; + break; + case SPELL_MISS_BLOCK: + procEx |= PROC_EX_BLOCK; + break; + case SPELL_MISS_EVADE: + procEx |= PROC_EX_EVADE; + break; + case SPELL_MISS_IMMUNE: + procEx |= PROC_EX_IMMUNE; + break; + case SPELL_MISS_IMMUNE2: + procEx |= PROC_EX_IMMUNE; + break; + case SPELL_MISS_DEFLECT: + procEx |= PROC_EX_DEFLECT; + break; + case SPELL_MISS_ABSORB: + procEx |= PROC_EX_ABSORB; + break; + case SPELL_MISS_REFLECT: + procEx |= PROC_EX_REFLECT; break; default: break; } - } else { // On block if (damageInfo->blocked) - { - hitMask |= PROC_HIT_BLOCK; - if (damageInfo->fullBlock) - hitMask |= PROC_HIT_FULL_BLOCK; - } + procEx |= PROC_EX_BLOCK; // On absorb if (damageInfo->absorb) - hitMask |= PROC_HIT_ABSORB; - - // Don't set hit/crit hitMask if damage is nullified - bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0; - if (!damageNullified) - { - // On crit - if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - hitMask |= PROC_HIT_CRITICAL; - else - hitMask |= PROC_HIT_NORMAL; - } - else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0) - hitMask |= PROC_HIT_FULL_RESIST; + procEx |= PROC_EX_ABSORB; + // On crit + if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) + procEx |= PROC_EX_CRITICAL_HIT; + else + procEx |= PROC_EX_NORMAL_HIT; } - - return hitMask; + return procEx; } -void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType) +void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo, uint32 procPhase) { // Player is loaded now - do not allow passive spell casts to proc if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading()) return; - // For melee/ranged based attack need update skills and set some Aura states if victim present - if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget) + if (procFlag & MELEE_BASED_TRIGGER_MASK && target && procPhase == PROC_SPELL_PHASE_HIT) { // Xinef: Shaman in ghost wolf form cant proc anything melee based if (!isVictim && GetShapeshiftForm() == FORM_GHOSTWOLF) @@ -12262,30 +15742,27 @@ void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMa // Update skills here for players // only when you are not fighting other players or their pets/totems (pvp) - if (GetTypeId() == TYPEID_PLAYER && - procTarget->GetTypeId() != TYPEID_PLAYER && - !(procTarget->IsTotem() && procTarget->ToTotem()->GetOwner()->IsPlayer()) && - !procTarget->IsPet() - ) + if (IsPlayer() && !target->IsCharmedOwnedByPlayerOrPlayer()) { // On melee based hit/miss/resist/parry/dodge need to update skill (for victim and attacker) - if (hitMask & (PROC_HIT_NORMAL | PROC_HIT_MISS | PROC_HIT_FULL_RESIST)) + if (procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_MISS | PROC_EX_RESIST | PROC_EX_PARRY | PROC_EX_DODGE)) { - if (procTarget->GetTypeId() != TYPEID_PLAYER && !procTarget->IsCritter()) - ToPlayer()->UpdateCombatSkills(procTarget, attType, isVictim); + ToPlayer()->UpdateCombatSkills(target, attType, isVictim, procSpell ? procSpell->m_weaponItem : nullptr); + } + // Update defence if player is victim and we block - TODO: confirm that blocked attacks only have a chance to increase defence skill + else if (isVictim && procExtra & (PROC_EX_BLOCK)) + { + ToPlayer()->UpdateCombatSkills(target, attType, true); } - // Update defence if player is victim and we block - else if (isVictim && (hitMask & (PROC_HIT_DODGE | PROC_HIT_PARRY | PROC_HIT_BLOCK))) - ToPlayer()->UpdateCombatSkills(procTarget, attType, true); } // If exist crit/parry/dodge/block need update aura state (for victim and attacker) - if (hitMask & (PROC_HIT_CRITICAL | PROC_HIT_PARRY | PROC_HIT_DODGE | PROC_HIT_BLOCK)) + if (procExtra & (PROC_EX_CRITICAL_HIT | PROC_EX_PARRY | PROC_EX_DODGE | PROC_EX_BLOCK)) { // for victim if (isVictim) { // if victim and dodge attack - if (hitMask & PROC_HIT_DODGE) + if (procExtra & PROC_EX_DODGE) { // Update AURA_STATE on dodge if (getClass() != CLASS_ROGUE) // skip Rogue Riposte @@ -12295,7 +15772,7 @@ void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMa } } // if victim and parry attack - if (hitMask & PROC_HIT_PARRY) + if (procExtra & PROC_EX_PARRY) { // For Hunters only Counterattack (skip Mongoose bite) if (getClass() == CLASS_HUNTER) @@ -12310,7 +15787,7 @@ void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMa } } // if and victim block attack - if (hitMask & PROC_HIT_BLOCK) + if (procExtra & PROC_EX_BLOCK) { ModifyAuraState(AURA_STATE_DEFENSE, true); StartReactiveTimer(REACTIVE_DEFENSE); @@ -12319,38 +15796,416 @@ void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMa else // For attacker { // Overpower on victim dodge - if (hitMask & PROC_HIT_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) + if (procExtra & PROC_EX_DODGE) { - AddComboPoints(procTarget, 1); - StartReactiveTimer(REACTIVE_OVERPOWER); + if (getClass() == CLASS_WARRIOR) + { + AddComboPoints(target, 1); + StartReactiveTimer(REACTIVE_OVERPOWER); + } } // Wolverine Bite - if ((hitMask & PROC_HIT_CRITICAL) && IsHunterPet()) + if ((procExtra & PROC_HIT_CRITICAL) && IsHunterPet()) { - AddComboPoints(procTarget, 1); + AddComboPoints(target, 1); StartReactiveTimer(REACTIVE_WOLVERINE_BITE); } } } } + + Unit* actor = isVictim ? target : this; + Unit* actionTarget = !isVictim ? target : this; + + ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, procPhase, procExtra, procSpell, damageInfo, healInfo, procAura, procAuraEffectIndex); + + ProcTriggeredList procTriggered; + // Fill procTriggered list + for (AuraApplicationMap::const_iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr) + { + // Do not allow auras to proc from effect triggered by itself + if (procAura && procAura->Id == itr->first) + continue; + + // Xinef: Generic Item Equipment cooldown, -1 is a special marker + if (itr->second->GetBase()->GetCastItemGUID() && HasSpellItemCooldown(itr->first, uint32(-1))) + continue; + + ProcTriggeredData triggerData(itr->second->GetBase()); + // Defensive procs are active on absorbs (so absorption effects are not a hindrance) + bool active = damage || (procExtra & PROC_EX_BLOCK && isVictim); + if (isVictim) + procExtra &= ~PROC_EX_INTERNAL_REQ_FAMILY; + + SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo(); + + // only auras that have trigger spell should proc from fully absorbed damage + if (procExtra & PROC_EX_ABSORB && isVictim) + if (damage || spellProto->Effects[EFFECT_0].TriggerSpell || spellProto->Effects[EFFECT_1].TriggerSpell || spellProto->Effects[EFFECT_2].TriggerSpell) + active = true; + + // xinef: fix spell procing from damaging / healing casts if spell has DoT / HoT effect only + // only player spells are taken into account + if (!active && !isVictim && !(procFlag & PROC_FLAG_DONE_PERIODIC) && procSpellInfo && procSpellInfo->SpellFamilyName && (procSpellInfo->HasAura(SPELL_AURA_PERIODIC_DAMAGE) || procSpellInfo->HasAura(SPELL_AURA_PERIODIC_HEAL))) + active = true; + + // AuraScript Hook + if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo)) + { + continue; + } + + bool isTriggeredAtSpellProcEvent = IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo); + + // AuraScript Hook + triggerData.aura->CallScriptCheckAfterProcHandlers(itr->second, eventInfo); + + if (!isTriggeredAtSpellProcEvent) + { + continue; + } + + // do checks using conditions table + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id); + ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget()); + if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) + { + continue; + } + + // Triggered spells not triggering additional spells + //bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_FROM_PROCS) ? + // (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false; + + bool hasTriggeredProc = false; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (itr->second->HasEffect(i)) + { + AuraEffect* aurEff = itr->second->GetBase()->GetEffect(i); + + // Skip this auras + if (isNonTriggerAura[aurEff->GetAuraType()]) + continue; + + // If not trigger by default and spellProcEvent == nullptr - skip + if (!isTriggerAura[aurEff->GetAuraType()] && !triggerData.spellProcEvent) + continue; + + switch (aurEff->GetAuraType()) + { + case SPELL_AURA_PROC_TRIGGER_SPELL: + case SPELL_AURA_MANA_SHIELD: + case SPELL_AURA_DUMMY: + case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: + if (uint32 triggerSpellId = aurEff->GetSpellInfo()->Effects[i].TriggerSpell) + { + triggerData.triggerSpelId[i] = triggerSpellId; + hasTriggeredProc = true; + } + break; + default: + break; + } + + // Some spells must always trigger + //if (isAlwaysTriggeredAura[aurEff->GetAuraType()]) + triggerData.effMask |= 1 << i; + } + } + + if (triggerData.effMask) + { + // If there is aura that triggers another proc aura, make sure that the triggered one is going to be proccessed on top of it + if (hasTriggeredProc) + { + bool proccessed = false; + for (uint8 i = 0; i < EFFECT_ALL; ++i) + { + if (uint32 triggeredSpellId = triggerData.triggerSpelId[i]) + { + auto iter = std::find(procTriggered.begin(), procTriggered.end(), triggeredSpellId); + if (iter != procTriggered.end()) + { + std::advance(iter, 1); + procTriggered.insert(iter, triggerData); + proccessed = true; + break; + } + } + } + + if (!proccessed) + { + procTriggered.push_front(triggerData); + } + } + else + { + procTriggered.push_front(triggerData); + } + } + } + + // Nothing found + if (procTriggered.empty()) + return; + + // Note: must SetCantProc(false) before return + if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC)) + SetCantProc(true); + + // Handle effects proceed this time + for (ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) + { + // look for aura in auras list, it may be removed while proc event processing + if (i->aura->IsRemoved()) + continue; + + bool useCharges = i->aura->IsUsingCharges(); + // no more charges to use, prevent proc + if (useCharges && !i->aura->GetCharges()) + continue; + + bool takeCharges = false; + SpellInfo const* spellInfo = i->aura->GetSpellInfo(); + + AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID()); + + bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo); + + // For players set spell cooldown if need + uint32 cooldown = 0; + if (prepare && i->spellProcEvent && i->spellProcEvent->cooldown) + cooldown = i->spellProcEvent->cooldown; + + // Xinef: set cooldown for actual proc + eventInfo.SetProcCooldown(cooldown); + + // Note: must SetCantProc(false) before return + if (spellInfo->HasAttribute(SPELL_ATTR3_INSTANT_TARGET_PROCS)) + SetCantProc(true); + + bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo); + + // "handled" is needed as long as proc can be handled in multiple places + if (!handled && HandleAuraProc(target, damage, i->aura, procSpellInfo, procFlag, procExtra, cooldown, &handled)) + { + uint32 Id = i->aura->GetId(); + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered with value by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), Id); + takeCharges = true; + } + + if (!handled) + for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + { + if (!(i->effMask & (1 << effIndex))) + continue; + + AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex); + ASSERT(triggeredByAura); + + bool prevented = i->aura->CallScriptEffectProcHandlers(triggeredByAura, aurApp, eventInfo); + if (prevented) + { + takeCharges = true; + continue; + } + + switch (triggeredByAura->GetAuraType()) + { + case SPELL_AURA_PROC_TRIGGER_SPELL: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + // Don`t drop charge or add cooldown for not started trigger + if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo)) + takeCharges = true; + break; + } + case SPELL_AURA_PROC_TRIGGER_DAMAGE: + { + // target has to be valid + if (!eventInfo.GetProcTarget()) + break; + + triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system + takeCharges = true; + break; + } + case SPELL_AURA_MANA_SHIELD: + case SPELL_AURA_DUMMY: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} dummy aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procSpell)) + takeCharges = true; + break; + } + case SPELL_AURA_OBS_MOD_POWER: + case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: + case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: + case SPELL_AURA_MOD_MELEE_HASTE: + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} aura of spell {})", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId()); + takeCharges = true; + break; + case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell id {} (triggered by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpellInfo, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting mending (triggered by {} dummy aura of spell {})", + (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + if (damage > 0) + { + HandleAuraRaidProcFromChargeWithValue(triggeredByAura); + takeCharges = true; + } + break; + } + case SPELL_AURA_RAID_PROC_FROM_CHARGE: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting mending (triggered by {} dummy aura of spell {})", + (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + HandleAuraRaidProcFromCharge(triggeredByAura); + takeCharges = true; + break; + } + case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: + { + LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered with value by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId()); + + if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo)) + takeCharges = true; + break; + } + case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: + // Skip melee hits or instant cast spells + // xinef: check channeled spells which are affected by haste also + if (procSpellInfo && (procSpellInfo->SpellFamilyName || GetTypeId() != TYPEID_PLAYER) && + (procSpellInfo->CalcCastTime() > 0 /*|| + (procSpell->IsChanneled() && procSpell->GetDuration() > 0 && (HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, procSpell) || procSpell->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)))*/)) + takeCharges = true; + break; + case SPELL_AURA_REFLECT_SPELLS_SCHOOL: + // Skip Melee hits and spells ws wrong school + if (procSpellInfo && (triggeredByAura->GetMiscValue() & procSpellInfo->SchoolMask)) // School check + takeCharges = true; + break; + case SPELL_AURA_SPELL_MAGNET: + // Skip Melee hits and targets with magnet aura + if (procSpellInfo && (triggeredByAura->GetBase()->GetUnitOwner()->ToUnit() == ToUnit())) // Magnet + takeCharges = true; + break; + case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: + case SPELL_AURA_MOD_POWER_COST_SCHOOL: + // Skip melee hits and spells ws wrong school or zero cost + if (procSpellInfo && + (procSpellInfo->ManaCost != 0 || procSpellInfo->ManaCostPercentage != 0 || (procSpellInfo->SpellFamilyFlags[1] & 0x2)) && // Cost check, mutilate include + (triggeredByAura->GetMiscValue() & procSpellInfo->SchoolMask)) // School check + takeCharges = true; + break; + case SPELL_AURA_MECHANIC_IMMUNITY: + case SPELL_AURA_MOD_MECHANIC_RESISTANCE: + // Compare mechanic + if (procSpellInfo && procSpellInfo->Mechanic == uint32(triggeredByAura->GetMiscValue())) + takeCharges = true; + break; + case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: + // Compare casters + if (target && triggeredByAura->GetCasterGUID() == target->GetGUID()) + takeCharges = true; + break; + // CC Auras which use their amount amount to drop + // Are there any more auras which need this? + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + case SPELL_AURA_TRANSFORM: + { + // Spell own direct damage at apply wont break the CC + // Xinef: Or when the aura is at full duration (assume that such auras should be added at the end, skipping all damage procs etc.) + if (procSpellInfo) + if ((!i->aura->IsPermanent() && i->aura->GetDuration() == i->aura->GetMaxDuration()) || procSpellInfo->Id == triggeredByAura->GetId() || + procSpellInfo->HasAttribute(SPELL_ATTR4_REACTIVE_DAMAGE_PROC)) + break; + + // chargeable mods are breaking on hit + if (useCharges) + takeCharges = true; + else if (triggeredByAura->GetAmount()) // aura must have amount + { + int32 damageLeft = triggeredByAura->GetAmount(); + // No damage left + if (damageLeft < int32(damage)) + i->aura->Remove(); + else + triggeredByAura->SetAmount(damageLeft - damage); + } + break; + } + case SPELL_AURA_ABILITY_IGNORE_AURASTATE: + if (procSpellInfo && procSpellInfo->Id == 20647) // hack for warriors execute, both dummy and damage spell are affected by ignore aurastate aura + break; + takeCharges = true; + break; + case SPELL_AURA_ADD_FLAT_MODIFIER: + case SPELL_AURA_ADD_PCT_MODIFIER: + { + if (SpellModifier* mod = triggeredByAura->GetSpellModifier()) + { + if (mod->op == SPELLMOD_CASTING_TIME && mod->value < 0 && procSpell) + { + // Skip instant spells + if (procSpellInfo->CalcCastTime() <= 0 || (procSpell->GetTriggeredCastFlags() & TRIGGERED_CAST_DIRECTLY) != 0) + { + break; + } + } + } + takeCharges = true; + break; + } + default: + takeCharges = true; + break; + } + i->aura->CallScriptAfterEffectProcHandlers(triggeredByAura, aurApp, eventInfo); + } + // Remove charge (aura can be removed by triggers) + // xinef: take into account attribute6 of proc spell + if (prepare && useCharges && takeCharges) + if (!procSpellInfo || isVictim || !procSpellInfo->HasAttribute(SPELL_ATTR6_DO_NOT_CONSUME_RESOURCES)) + i->aura->DropCharge(); + + i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo); + + if (spellInfo->HasAttribute(SPELL_ATTR3_INSTANT_TARGET_PROCS)) + SetCantProc(false); + } + + // Cleanup proc requirements + if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC)) + SetCantProc(false); } -void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo) +void Unit::GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo) { - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - // use provided list of auras which can proc if (procAuras) { - for (AuraApplication* aurApp : *procAuras) + for (std::list::iterator itr = procAuras->begin(); itr != procAuras->end(); ++itr) { - ASSERT(aurApp->GetTarget() == this); - if (!aurApp->GetRemoveMode()) - if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now)) + ASSERT((*itr)->GetTarget() == this); + if (!(*itr)->GetRemoveMode()) + if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo)) { - aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now); - aurasTriggeringProc.emplace_back(procEffectMask, aurApp); + (*itr)->GetBase()->PrepareProcToTrigger(*itr, eventInfo); + aurasTriggeringProc.push_back(*itr); } } } @@ -12359,10 +16214,10 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg { for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr) { - if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now)) + if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo)) { - itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now); - aurasTriggeringProc.emplace_back(procEffectMask, itr->second); + itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo); + aurasTriggeringProc.push_back(itr->second); } } } @@ -12371,80 +16226,35 @@ void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTrigg void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo) { DamageInfo dmgInfo = DamageInfo(damageInfo); - TriggerAurasProcOnEvent(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr); + TriggerAurasProcOnEvent(nullptr, nullptr, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, 0, 0, damageInfo.procEx, nullptr, &dmgInfo, nullptr); } -void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) +void Unit::TriggerAurasProcOnEvent(std::list* myProcAuras, std::list* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { // prepare data for self trigger - ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - if (typeMaskActor) - { - AuraApplicationProcContainer myAurasTriggeringProc; - GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo); - - // needed for example for Cobra Strikes, pet does the attack, but aura is on owner - if (Player* modOwner = GetSpellModOwner()) - { - if (modOwner != this && spell) - { - AuraApplicationList modAuras; - for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr) - { - if (spell->m_appliedMods.count(itr->second->GetBase()) != 0) - modAuras.push_back(itr->second); - } - modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo); - } - } - - TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc); - } + ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + std::list myAurasTriggeringProc; + GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo); // prepare data for target trigger - ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); - if (typeMaskActionTarget && actionTarget) - { - AuraApplicationProcContainer targetAurasTriggeringProc; - actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo); - actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc); - } + ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); + std::list targetAurasTriggeringProc; + if (typeMaskActionTarget) + GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo); + + TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc); + + if (typeMaskActionTarget) + TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc); } -void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc) +void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& aurasTriggeringProc) { - Spell const* triggeringSpell = eventInfo.GetProcSpell(); - bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled(); - if (disableProcs) - SetCantProc(true); - - for (auto const& aurAppProc : aurasTriggeringProc) + for (std::list::iterator itr = aurasTriggeringProc.begin(); itr != aurasTriggeringProc.end(); ++itr) { - AuraApplication* aurApp; - uint8 procEffectMask; - std::tie(procEffectMask, aurApp) = aurAppProc; - - if (aurApp->GetRemoveMode()) - { - continue; - } - - SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo(); - if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC)) - { - SetCantProc(true); - } - - aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo); - - if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC)) - { - SetCantProc(false); - } + if (!(*itr)->GetRemoveMode()) + (*itr)->GetBase()->TriggerProcOnEvent(*itr, eventInfo); } - - if (disableProcs) - SetCantProc(false); } SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const @@ -12677,10 +16487,6 @@ void Unit::AddComboPoints(Unit* target, int8 count) return; } - // remove Premed-like effects - // (NB: this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore) - RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS); - if (target && target != m_comboTarget) { if (m_comboTarget) @@ -13248,7 +17054,280 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return true; } -void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackType /* attackType */, SpellInfo const* /* spellProto */) +bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo) +{ + SpellInfo const* spellProto = aura->GetSpellInfo(); + SpellInfo const* procSpell = eventInfo.GetSpellInfo(); + + // let the aura be handled by new proc system if it has new entry + if (sSpellMgr->GetSpellProcEntry(spellProto->Id)) + return false; + + // Get proc Event Entry + spellProcEvent = sSpellMgr->GetSpellProcEvent(spellProto->Id); + + // Get EventProcFlag + uint32 EventProcFlag; + if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags + EventProcFlag = spellProcEvent->procFlags; + else + EventProcFlag = spellProto->ProcFlags; // else get from spell proto + // Continue if no trigger exist + if (!EventProcFlag) + return false; + + // Additional checks for triggered spells (ignore trap casts) + //if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) + //{ + // if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_TRIGGERED)) + // return false; + //} + + // Xinef: additional check for player auras - only player spells can trigger player proc auras + // Xinef: skip victim auras + // Excluded player shoot spells + if (!isVictim && GetTypeId() == TYPEID_PLAYER) //spellProto->SpellFamilyName != SPELLFAMILY_GENERIC) + if (!(EventProcFlag & (PROC_FLAG_KILL | PROC_FLAG_DEATH)) && procSpell && procSpell->SpellFamilyName == SPELLFAMILY_GENERIC && procSpell->GetCategory() != 76 && + (!eventInfo.GetTriggerAuraSpell() || eventInfo.GetTriggerAuraSpell()->SpellFamilyName == SPELLFAMILY_GENERIC)) + return false; + + // Check spellProcEvent data requirements + if (!sSpellMgr->IsSpellProcEventCanTriggeredBy(spellProto, spellProcEvent, EventProcFlag, eventInfo, active)) + return false; + // In most cases req get honor or XP from kill + if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER) + { + bool allow = false; + + if (victim) + allow = ToPlayer()->isHonorOrXPTarget(victim); + + // Shadow Word: Death - can trigger from every kill + if (aura->GetId() == 32409 || aura->GetId() == 18372 || aura->GetId() == 18213) + allow = true; + if (!allow) + return false; + } + // Aura added by spell can`t trigger from self (prevent drop charges/do triggers) + // But except periodic and kill triggers (can triggered from self) + if (procSpell && procSpell->Id == spellProto->Id + && !(spellProto->ProcFlags & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL))) + return false; + + // Check if current equipment allows aura to proc + if (!isVictim && GetTypeId() == TYPEID_PLAYER && !spellProto->HasAttribute(SPELL_ATTR3_NO_PROC_EQUIP_REQUIREMENT)) + { + Player* player = ToPlayer(); + if (spellProto->EquippedItemClass == ITEM_CLASS_WEAPON) + { + Item* item = nullptr; + if (attType == BASE_ATTACK) + item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + else if (attType == OFF_ATTACK) + item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + else + item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); + + if (player->IsInFeralForm()) + return false; + + if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->SubClass) & spellProto->EquippedItemSubClassMask)) + return false; + } + else if (spellProto->EquippedItemClass == ITEM_CLASS_ARMOR) + { + // Check if player is wearing shield + Item* item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + if (!item || item->IsBroken() || item->GetTemplate()->Class != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->SubClass) & spellProto->EquippedItemSubClassMask)) + return false; + } + } + // Get chance from spell + float chance = float(spellProto->ProcChance); + // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance; + if (spellProcEvent && spellProcEvent->customChance) + chance = spellProcEvent->customChance; + // If PPM exist calculate chance from PPM + if (spellProcEvent && spellProcEvent->ppmRate != 0) + { + if (!isVictim) + { + uint32 WeaponSpeed = GetAttackTime(attType); + chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); + } + else if (victim) + { + uint32 WeaponSpeed = victim->GetAttackTime(attType); + chance = victim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); + } + } + + // Custom chances + switch (spellProto->SpellFamilyName) + { + case SPELLFAMILY_WARRIOR: + { + // Recklessness, allow to proc only once for whirlwind + if (spellProto->Id == 1719 && procSpell && procSpell->Id == 44949) + return false; + } + } + + if (eventInfo.GetProcChance()) + { + chance = *eventInfo.GetProcChance(); + } + + // Apply chance modifer aura + if (Player* modOwner = GetSpellModOwner()) + { + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance); + } + + return roll_chance_f(chance); +} + +bool Unit::HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura) +{ + // aura can be deleted at casts + SpellInfo const* spellProto = triggeredByAura->GetSpellInfo(); + int32 heal = triggeredByAura->GetAmount(); + ObjectGuid caster_guid = triggeredByAura->GetCasterGUID(); + + // Currently only Prayer of Mending + if (!(spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && spellProto->SpellFamilyFlags[1] & 0x20)) + { + LOG_DEBUG("spells.aura", "Unit::HandleAuraRaidProcFromChargeWithValue, received not handled spell: {}", spellProto->Id); + return false; + } + + // jumps + int32 jumps = triggeredByAura->GetBase()->GetCharges() - 1; + + // current aura expire + triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease + + // next target selection + if (jumps > 0) + { + if (Unit* caster = triggeredByAura->GetCaster()) + { + // smart healing + float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); + std::list nearMembers; + + Player* player = nullptr; + if (GetTypeId() == TYPEID_PLAYER) + player = ToPlayer(); + else if (GetOwner()) + player = GetOwner()->ToPlayer(); + + if (player) + { + Group* group = player->GetGroup(); + if (!group) + { + if (player != this) + { + if (IsWithinDistInMap(player, radius)) + nearMembers.push_back(player); + } + else if (Unit* pet = GetGuardianPet()) + { + if (IsWithinDistInMap(pet, radius)) + nearMembers.push_back(pet); + } + } + else + { + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + if (Player* Target = itr->GetSource()) + { + if (Target != this && !IsWithinDistInMap(Target, radius)) + continue; + + // IsHostileTo check duel and controlled by enemy + if (Target != this && Target->IsAlive() && !IsHostileTo(Target)) + nearMembers.push_back(Target); + + // Push player's pet to vector + if (Unit* pet = Target->GetGuardianPet()) + if (pet != this && pet->IsAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet)) + nearMembers.push_back(pet); + } + } + + if (!nearMembers.empty()) + { + nearMembers.sort(Acore::HealthPctOrderPred()); + if (Unit* target = nearMembers.front()) + { + CastSpell(target, 41637 /*Dummy visual effect triggered by main spell cast*/, true); + CastCustomSpell(target, spellProto->Id, &heal, nullptr, nullptr, true, nullptr, triggeredByAura, caster_guid); + if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID())) + aura->SetCharges(jumps); + } + } + } + } + } + + // heal + CastCustomSpell(this, 33110, &heal, nullptr, nullptr, true, nullptr, nullptr, caster_guid); + return true; +} +bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura) +{ + // aura can be deleted at casts + SpellInfo const* spellProto = triggeredByAura->GetSpellInfo(); + + uint32 damageSpellId; + switch (spellProto->Id) + { + case 57949: // shiver + damageSpellId = 57952; + //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637) + break; + case 59978: // shiver + damageSpellId = 59979; + break; + case 43593: // Cold Stare + damageSpellId = 43594; + break; + default: + LOG_ERROR("entities.unit", "Unit::HandleAuraRaidProcFromCharge, received unhandled spell: {}", spellProto->Id); + return false; + } + + ObjectGuid caster_guid = triggeredByAura->GetCasterGUID(); + + // jumps + int32 jumps = triggeredByAura->GetBase()->GetCharges() - 1; + + // current aura expire + triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease + + // next target selection + if (jumps > 0) + { + if (Unit* caster = triggeredByAura->GetCaster()) + { + float radius = triggeredByAura->GetSpellInfo()->Effects[triggeredByAura->GetEffIndex()].CalcRadius(caster); + if (Unit* target = GetNextRandomRaidMemberOrPet(radius)) + { + CastSpell(target, spellProto, true, nullptr, triggeredByAura, caster_guid); + if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID())) + aura->SetCharges(jumps); + } + } + } + + CastSpell(this, damageSpellId, true, nullptr, triggeredByAura, caster_guid); + + return true; +} + +void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackType attackType, SpellInfo const* spellProto, Spell const* spell /*= nullptr*/) { // Prevent killing unit twice (and giving reward from kill twice) if (!victim->GetHealth()) @@ -13363,22 +17442,17 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp // Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim if (killer && (killer->IsPet() || killer->IsTotem())) - { - // proc only once for victim if (Unit* owner = killer->GetOwner()) { - owner->ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); - sScriptMgr->OnCreatureKilledByPet(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature()); + Unit::ProcDamageAndSpell(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); + sScriptMgr->OnCreatureKilledByPet( killer->GetCharmerOrOwnerPlayerOrPlayerItself(), victim->ToCreature()); } - } if (killer != victim && !victim->IsCritter()) - { - killer->ProcSkillsAndAuras(victim, killer ? PROC_FLAG_KILL : PROC_FLAG_NONE, PROC_FLAG_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); - } + Unit::ProcDamageAndSpell(killer, victim, killer ? PROC_FLAG_KILL : 0, PROC_FLAG_KILLED, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); // Proc auras on death - must be before aura/combat remove - victim->ProcSkillsAndAuras(victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); + Unit::ProcDamageAndSpell(victim, nullptr, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, attackType, spellProto, nullptr, -1, spell); // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras @@ -14544,7 +18618,7 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, i if (spellId) { if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellId, hitChance); + modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, hitChance); } missChance += hitChance - 100.0f; @@ -15060,6 +19134,15 @@ void Unit::JumpTo(WorldObject* obj, float speedZ) bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) { + Creature* creature = ToCreature(); + if (creature && creature->IsAIEnabled) + { + if (!creature->AI()->BeforeSpellClick(clicker)) + { + return false; + } + } + bool result = false; uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry(); SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry); @@ -15128,7 +19211,6 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) result = true; } - Creature* creature = ToCreature(); if (creature && creature->IsAIEnabled) creature->AI()->OnSpellClick(clicker, result); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8e66a0a48..383b45247 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -702,13 +702,13 @@ struct DiminishingReturn : DRGroup(group), stack(0), hitTime(t), hitCount(count) {} - DiminishingGroup DRGroup; - uint16 stack; + DiminishingGroup DRGroup: 16; + uint16 stack: 16; uint32 hitTime; uint32 hitCount; }; -enum MeleeHitOutcome : uint8 +enum MeleeHitOutcome { MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY, MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL @@ -761,12 +761,11 @@ private: uint32 m_absorb; uint32 m_resist; uint32 m_block; - uint32 m_hitMask; uint32 m_cleanDamage; public: - DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType, uint32 cleanDamage = 0); + explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0); explicit DamageInfo(CalcDamageInfo& dmgInfo); - DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask); + DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType); void ModifyDamage(int32 amount); void AbsorbDamage(uint32 amount); @@ -785,7 +784,6 @@ public: [[nodiscard]] uint32 GetBlock() const { return m_block; }; [[nodiscard]] uint32 GetUnmitigatedDamage() const; - [[nodiscard]] uint32 GetHitMask() const; }; class HealInfo @@ -794,33 +792,33 @@ private: Unit* const m_healer; Unit* const m_target; uint32 m_heal; - uint32 m_effectiveHeal; uint32 m_absorb; SpellInfo const* const m_spellInfo; SpellSchoolMask const m_schoolMask; - uint32 m_hitMask; public: - explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask); - void AbsorbHeal(uint32 amount); + explicit HealInfo(Unit* _healer, Unit* _target, uint32 _heal, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask) + : m_healer(_healer), m_target(_target), m_heal(_heal), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask) + { + m_absorb = 0; + } + void AbsorbHeal(uint32 amount) + { + amount = std::min(amount, GetHeal()); + m_absorb += amount; + m_heal -= amount; + } void SetHeal(uint32 amount) { m_heal = amount; } - void SetEffectiveHeal(uint32 amount) - { - m_effectiveHeal = amount; - } - [[nodiscard]] Unit* GetHealer() const { return m_healer; } [[nodiscard]] Unit* GetTarget() const { return m_target; } [[nodiscard]] uint32 GetHeal() const { return m_heal; } - [[nodiscard]] uint32 GetEffectiveHeal() const { return m_effectiveHeal; } [[nodiscard]] uint32 GetAbsorb() const { return m_absorb; } [[nodiscard]] SpellInfo const* GetSpellInfo() const { return m_spellInfo; }; [[nodiscard]] SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }; - [[nodiscard]] uint32 GetHitMask() const; }; class ProcEventInfo @@ -891,7 +889,7 @@ struct SpellNonMeleeDamage { SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, uint32 _schoolMask) : target(_target), attacker(_attacker), spellInfo(_spellInfo), damage(0), overkill(0), schoolMask(_schoolMask), - absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false) + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) {} Unit* target; @@ -908,7 +906,6 @@ struct SpellNonMeleeDamage uint32 HitInfo; // Used for help uint32 cleanDamage; - bool fullBlock; }; struct SpellPeriodicAuraLogInfo @@ -926,7 +923,7 @@ struct SpellPeriodicAuraLogInfo }; void createProcFlags(SpellInfo const* spellInfo, WeaponAttackType attackType, bool positive, uint32& procAttacker, uint32& procVictim); -uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition); +uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition); struct RedirectThreatInfo { @@ -1291,7 +1288,6 @@ public: typedef std::list AuraList; typedef std::list AuraApplicationList; typedef std::list Diminishing; - typedef std::vector> AuraApplicationProcContainer; typedef GuidUnorderedSet ComboPointHolderSet; typedef std::map VisibleAuraMap; @@ -1443,10 +1439,10 @@ public: void setPowerType(Powers power); [[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast(UNIT_FIELD_POWER1) + power); } [[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast(UNIT_FIELD_MAXPOWER1) + power); } - void SetPower(Powers power, uint32 val); + void SetPower(Powers power, uint32 val, bool withPowerUpdate = true); void SetMaxPower(Powers power, uint32 val); // returns the change in power - int32 ModifyPower(Powers power, int32 val); + int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true); int32 ModifyPowerPct(Powers power, float pct, bool apply = true); [[nodiscard]] uint32 GetAttackTime(WeaponAttackType att) const @@ -1530,15 +1526,16 @@ public: uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb); static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr); - static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr); - static void DealHeal(HealInfo& healInfo); + static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr); + static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth); - void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); + static void ProcDamageAndSpell(Unit* actor, Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/); + void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr, uint32 procPhase = 2 /*PROC_SPELL_PHASE_HIT*/); - void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo); + void GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo); void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo); - void TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); - void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras); + void TriggerAurasProcOnEvent(std::list* myProcAuras, std::list* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); + void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list& procAuras); void HandleEmoteCommand(uint32 emoteId); void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false); @@ -1546,7 +1543,12 @@ public: void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); - void HandleProcExtraAttackFor(Unit* victim); + void HandleProcExtraAttackFor(Unit* victim, uint32 count); + void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; } + [[nodiscard]] uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; } + void AddExtraAttacks(uint32 count); + void SetLastDamagedTargetGuid(ObjectGuid const& guid) { _lastDamagedTargetGuid = guid; } + [[nodiscard]] ObjectGuid const& GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; } void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false); void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell = nullptr); @@ -1698,7 +1700,7 @@ public: [[nodiscard]] virtual bool IsUnderWater() const; bool isInAccessiblePlaceFor(Creature const* c) const; - void SendHealSpellLog(HealInfo& healInfo, bool critical = false); + void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); int32 HealBySpell(HealInfo& healInfo, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); @@ -2513,6 +2515,14 @@ protected: bool _instantCast; private: + bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo); + bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, Spell const* spellProc = nullptr); + bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled); + bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo); + bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown); + bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura); + bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura); + void UpdateSplineMovement(uint32 t_diff); void UpdateSplinePosition(); @@ -2520,8 +2530,6 @@ private: [[nodiscard]] float GetCombatRatingReduction(CombatRating cr) const; [[nodiscard]] uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const; - void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType); - protected: void SetFeared(bool apply); void SetConfused(bool apply); @@ -2555,6 +2563,10 @@ private: bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed? [[nodiscard]] float processDummyAuras(float TakenTotalMod) const; + + uint32 _lastExtraAttackSpell; + std::unordered_map extraAttacksTargets; + ObjectGuid _lastDamagedTargetGuid; }; namespace Acore diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 9afe62860..70eb6ef98 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1186,7 +1186,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) { int32 i = 0; flag96 _mask = 0; - SpellModContainer const& spellMods = pCurrChar->GetSpellModContainer(opType); + SpellModList const& spellMods = pCurrChar->GetSpellModList(opType); if (spellMods.empty()) continue; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6b195ff72..94a6d72b6 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -103,8 +103,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] = &AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY &AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY &AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY - &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc - &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc + &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell + &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor &AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES &AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES &AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a) @@ -323,7 +323,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] = &AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonus &AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code &AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE - &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast + &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast &AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask &AuraEffect::HandleUnused, //264 unused (3.2.0) &AuraEffect::HandleUnused, //265 unused (3.2.0) @@ -631,7 +631,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) { // Apply periodic time mod if (modOwner) - modOwner->ApplySpellMod(GetId(), m_amplitude); + modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_amplitude); if (caster) { @@ -689,6 +689,7 @@ void AuraEffect::CalculateSpellMod() m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types m_spellmod->spellId = GetId(); m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; + m_spellmod->charges = GetBase()->GetCharges(); } m_spellmod->value = GetAmount(); break; @@ -1071,11 +1072,14 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const { if (!spell) return false; - // Check family name and EffectClassMask - if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask)) + // Check family name + if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName) return false; - return true; + // Check EffectClassMask + if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags) + return true; + return false; } bool AuraEffect::HasSpellClassMask() const @@ -1142,99 +1146,6 @@ void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const } } -bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const -{ - bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo); - if (!result) - return false; - - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - switch (GetAuraType()) - { - case SPELL_AURA_MOD_CONFUSE: - case SPELL_AURA_MOD_FEAR: - case SPELL_AURA_MOD_STUN: - case SPELL_AURA_MOD_ROOT: - case SPELL_AURA_TRANSFORM: - { - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - { - return false; - } - - // Spell own damage at apply won't break CC - if (spellInfo && spellInfo == eventInfo.GetSpellInfo()) - { - Aura* aura = GetBase(); - // called from spellcast, should not have ticked yet - if (aura->GetDuration() == aura->GetMaxDuration()) - { - return false; - } - } - break; - } - break; - case SPELL_AURA_MECHANIC_IMMUNITY: - case SPELL_AURA_MOD_MECHANIC_RESISTANCE: - // Compare mechanic - if (!spellInfo || static_cast(spellInfo->Mechanic) != GetMiscValue()) - { - return false; - } - break; - case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: - // Skip melee hits and instant cast spells - if (!spellInfo || !spellInfo->CalcCastTime()) - { - return false; - } - break; - case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: - // Compare casters - if (GetCasterGUID() != eventInfo.GetActor()->GetGUID()) - { - return false; - } - break; - case SPELL_AURA_MOD_POWER_COST_SCHOOL: - case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: - // Skip melee hits and spells with wrong school or zero cost - if (!spellInfo || (!spellInfo->ManaCost && !spellInfo->ManaCostPercentage) || // Cost Check - !(spellInfo->GetSchoolMask() & GetMiscValue())) // School Check - { - return false; - } - break; - case SPELL_AURA_REFLECT_SPELLS_SCHOOL: - // Skip melee hits and spells with wrong school - if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue())) - { - return false; - } - break; - case SPELL_AURA_PROC_TRIGGER_SPELL: - case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: - { - // Don't proc extra attacks while already processing extra attack spell - uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell; - if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) - { - if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - { - return false; - } - } - break; - } - default: - break; - } - - return result; -} - void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo); @@ -1243,16 +1154,6 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) switch (GetAuraType()) { - // CC Auras which use their amount to drop - // Are there anyu more auras which need this? - case SPELL_AURA_MOD_CONFUSE: - case SPELL_AURA_MOD_FEAR: - case SPELL_AURA_MOD_STUN: - case SPELL_AURA_MOD_ROOT: - case SPELL_AURA_TRANSFORM: - HandleBreakableCCAuraProc(aurApp, eventInfo); - break; - case SPELL_AURA_DUMMY: case SPELL_AURA_PROC_TRIGGER_SPELL: HandleProcTriggerSpellAuraProc(aurApp, eventInfo); break; @@ -2977,6 +2878,7 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo displayId = 0; } } + } target->Mount(displayId, vehicleId, GetMiscValue()); } @@ -5214,6 +5116,12 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use break; + case 71563: + { + if (Aura* newAura = target->AddAura(71564, target)) + newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); + return; + } } } // AT REMOVE @@ -6446,8 +6354,10 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const mitigatedDamage += resilienceReduction; } - DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage); + damage = std::max(0, dmg); + cleanDamage.mitigated_damage = std::max(0, mitigatedDamage); + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); @@ -6461,15 +6371,12 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 hitMask = dmgInfo.GetHitMask(); + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; if (absorb > 0) - hitMask |= PROC_HIT_ABSORB; + procEx |= PROC_EX_ABSORB; if (damage) - { procVictim |= PROC_FLAG_TAKEN_DAMAGE; - hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; - } int32 overkill = damage - target->GetHealth(); if (overkill < 0) @@ -6480,8 +6387,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); - // allow null caster to call this function - caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr); + Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const @@ -6534,8 +6440,10 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c cleanDamageAmount += resilienceReduction; } - DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, cleanDamage.mitigated_damage); + damage = std::max(0, dmg); + cleanDamage.mitigated_damage = std::max(0, cleanDamageAmount); + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); @@ -6545,15 +6453,12 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 hitMask = dmgInfo.GetHitMask(); + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; if (absorb > 0) - hitMask |= PROC_HIT_ABSORB; + procEx |= PROC_EX_ABSORB; if (dmgInfo.GetDamage()) - { procVictim |= PROC_FLAG_TAKEN_DAMAGE; - hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; - } if (target->GetHealth() < dmgInfo.GetDamage()) { @@ -6571,8 +6476,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); - // allow null caster to call this function - caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dmgInfo, nullptr); + Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); if (!caster || !caster->IsAlive()) return; @@ -6585,7 +6489,6 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); int32 gain = caster->HealBySpell(healInfo); caster->getHostileRefMgr().threatAssist(caster, gain * 0.5f, GetSpellInfo()); - caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const @@ -6719,13 +6622,13 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); Unit::CalcHealAbsorb(healInfo); - Unit::DealHeal(healInfo); + int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal()); - SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); + SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); if (caster) - target->getHostileRefMgr().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo()); + target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo()); bool haveCastItem = GetBase()->GetCastItemGUID(); @@ -6735,9 +6638,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST)) { uint32 manaPerSecond = GetSpellInfo()->ManaPerSecond; - if (manaPerSecond > healInfo.GetEffectiveHeal() && healInfo.GetEffectiveHeal() > 0) + if ((int32)manaPerSecond > gain && gain > 0) { - manaPerSecond = healInfo.GetEffectiveHeal(); + manaPerSecond = gain; } uint32 absorb2 = 0; @@ -6749,15 +6652,13 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 hitMask = (crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL); + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; if (healInfo.GetAbsorb() > 0) - { - hitMask |= PROC_HIT_ABSORB; - } + procEx |= PROC_EX_ABSORB; // ignore item heals if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot - caster->ProcSkillsAndAuras(target, caster ? procAttacker : 0, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo); + Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -6938,32 +6839,14 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE); - uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL; + uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT; if (damageInfo.damage) - { procVictim |= PROC_FLAG_TAKEN_DAMAGE; - spellTypeMask |= PROC_SPELL_TYPE_DAMAGE; - } caster->DealSpellDamage(&damageInfo, true); - DamageInfo dmgInfo(damageInfo, DOT, BASE_ATTACK, hitMask); - caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dmgInfo, nullptr); -} - -void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) -{ - int32 const damageLeft = GetAmount() - static_cast(eventInfo.GetDamageInfo()->GetDamage()); - - if (damageLeft <= 0) - { - aurApp->GetTarget()->RemoveAura(aurApp); - } - else - { - SetAmount(damageLeft); - } + DamageInfo dmgInfo(damageInfo, DOT); + Unit::ProcDamageAndSpell(caster, damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo); } void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) @@ -6979,7 +6862,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve } else { - LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); + LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); } } @@ -7000,7 +6883,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp } else { - LOG_ERROR("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); + LOG_DEBUG("spells.aura", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell {} from aura {} proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId()); } } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index b7ff1e15f..b85984341 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -49,6 +49,7 @@ public: Aura* GetBase() const { return m_base; } void GetTargetList(std::list& targetList) const; void GetApplicationList(std::list& applicationList) const; + SpellModifier* GetSpellModifier() const { return m_spellmod; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } uint32 GetId() const; @@ -95,7 +96,6 @@ public: void SendTickImmune(Unit* target, Unit* caster) const; void PeriodicTick(AuraApplication* aurApp, Unit* caster) const; - bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void CleanupTriggeredSpells(Unit* target); @@ -333,7 +333,6 @@ public: void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const; // aura effect proc handlers - void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index db70f3207..8d2add5c3 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -411,7 +411,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* m_castItemGuid(itemGUID ? itemGUID : castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemEntry(castItem ? castItem->GetEntry() : 0), m_applyTime(GameTime::GetGameTime().count()), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), - m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_procCooldown(std::chrono::steady_clock::time_point::min()), m_triggeredByAuraSpellInfo(nullptr) + m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_triggeredByAuraSpellInfo(nullptr) { if ((m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NO_TARGET_PER_SECOND_COST)) m_timeCla = 1 * IN_MILLISECONDS; @@ -875,7 +875,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const // IsPermanent() checks max duration (which we are supposed to calculate here) if (maxDuration != -1 && modOwner) - modOwner->ApplySpellMod(GetId(), maxDuration); + modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, maxDuration); return maxDuration; } @@ -885,7 +885,7 @@ void Aura::SetDuration(int32 duration, bool withMods) { if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), duration); + modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration); } m_duration = duration; SetNeedClientUpdateForTargets(); @@ -976,11 +976,11 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const { uint32 maxProcCharges = m_spellInfo->ProcCharges; if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId())) - maxProcCharges = procEntry->Charges; + maxProcCharges = procEntry->charges; if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), maxProcCharges); + modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, maxProcCharges); return maxProcCharges; } @@ -1062,6 +1062,12 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode, bool periodicRes // reset charges SetCharges(CalcMaxCharges()); + // FIXME: not a best way to synchronize charges, but works + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect* aurEff = GetEffect(i)) + if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER) + if (SpellModifier* mod = aurEff->GetSpellModifier()) + mod->charges = GetCharges(); } SetStackAmount(stackAmount); @@ -1196,7 +1202,7 @@ int32 Aura::CalcDispelChance(Unit* auraTarget, bool offensive) const // Apply dispel mod from aura caster if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), resistChance); + modOwner->ApplySpellMod(GetId(), SPELLMOD_RESIST_DISPEL_CHANCE, resistChance); // Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST // Only affects offensive dispels @@ -1254,7 +1260,7 @@ void Aura::HandleAllEffects(AuraApplication* aurApp, uint8 mode, bool apply) m_effects[i]->HandleEffect(aurApp, mode, apply); } -void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const +void Aura::GetApplicationList(std::list& applicationList) const { for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) { @@ -1433,9 +1439,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b } break; case 44544: // Fingers of Frost - // Refresh or add visual aura - target->CastCustomSpell(74396, SPELLVALUE_AURA_STACK, sSpellMgr->AssertSpellInfo(74396)->StackAmount, (Unit*)nullptr, true); - break; { // See if we already have the indicator aura. If not, create one. if (Aura* aur = target->GetAura(74396)) @@ -1660,6 +1663,10 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b target->CastSpell(target, 32612, true, nullptr, GetEffect(1)); target->CombatStop(); break; + case 74396: // Fingers of Frost + // Remove the IGNORE_AURASTATE aura + target->RemoveAurasDueToSpell(44544); + break; case 44401: // Missile Barrage case 48108: // Hot Streak case 57761: // Fireball! @@ -2185,17 +2192,22 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const return true; } -bool Aura::IsProcOnCooldown(std::chrono::steady_clock::time_point now) const +bool Aura::IsProcOnCooldown() const { - return m_procCooldown > now; + /*if (m_procCooldown) + { + if (m_procCooldown > GameTime::GetGameTime().count()) + return true; + }*/ + return false; } -void Aura::AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd) +void Aura::AddProcCooldown(uint32 /*msec*/) { - m_procCooldown = cooldownEnd; + //m_procCooldown = GameTime::GetGameTime().count() + msec; } -void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) +void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo) { bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo); if (!prepare) @@ -2213,101 +2225,47 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf ASSERT(procEntry); // cooldowns should be added to the whole aura (see 51698 area aura) - AddProcCooldown(now + procEntry->Cooldown); + AddProcCooldown(procEntry->cooldown); } -uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const +bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const { SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()); // only auras with spell proc entry can trigger proc if (!procEntry) - return 0; - - // check spell triggering us - if (Spell const* spell = eventInfo.GetProcSpell()) - { - // Do not allow auras to proc from effect triggered from itself - if (spell->IsTriggeredByAura(m_spellInfo)) - return 0; - - // check if aura can proc when spell is triggered (exception for hunter auto shot & wands) - if (spell->IsTriggered() && !(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK)) - if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED)) - return 0; - } - - // check don't break stealth attr present - if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH)) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) - return 0; - } + return false; // check if we have charges to proc with - if (IsUsingCharges()) - { - if (!GetCharges()) - return 0; - - if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD) - { - if (Spell const* spell = eventInfo.GetProcSpell()) - { - if (!spell->m_appliedMods.count(const_cast(this))) - { - return 0; - } - } - } - } + if (IsUsingCharges() && !GetCharges()) + return false; // check proc cooldown - if (IsProcOnCooldown(now)) - return 0; + if (IsProcOnCooldown()) + return false; + + // TODO: + // something about triggered spells triggering, and add extra attack effect // do checks against db data - if (!SpellMgr::CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) - return 0; + if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo)) + return false; // do checks using conditions table ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId()); ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget()); if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) - return 0; + return false; // AuraScript Hook bool check = const_cast(this)->CallScriptCheckProcHandlers(aurApp, eventInfo); if (!check) - return 0; - - // At least one effect has to pass checks to proc aura - uint8 procEffectMask = aurApp->GetEffectMask(); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (procEffectMask & (1 << i)) - if ((procEntry->AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) || !GetEffect(i)->CheckEffectProc(aurApp, eventInfo)) - procEffectMask &= ~(1 << i); - } - - if (!procEffectMask) - return 0; + return false; // TODO: // do allow additional requirements for procs // this is needed because this is the last moment in which you can prevent aura charge drop on proc // and possibly a way to prevent default checks (if there're going to be any) - // Aura added by spoell can't trigger from self (prevent drop charges/do triggers) - // But except periodic and kill triggers (can triggered from self) - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - { - if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL))) - { - return 0; - } - } - // Check if current equipment meets aura requirements // do that only for passive spells // TODO: this needs to be unified for all kinds of auras @@ -2320,7 +2278,7 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON) { if (target->ToPlayer()->IsInFeralForm()) - return 0; + return false; if (DamageInfo const* damageInfo = eventInfo.GetDamageInfo()) { @@ -2351,50 +2309,39 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, } } - if (roll_chance_f(CalcProcChance(*procEntry, eventInfo))) - return procEffectMask; - - return 0; + return roll_chance_f(CalcProcChance(*procEntry, eventInfo)); } float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const { - float chance = procEntry.Chance; + float chance = procEntry.chance; // calculate chances depending on unit with caster's data // so talents modifying chances and judgements will have properly calculated proc chance if (Unit* caster = GetCaster()) { // calculate ppm chance if present and we're using weapon - if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0) + if (eventInfo.GetDamageInfo() && procEntry.ratePerMinute != 0) { uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType()); - chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo()); + chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ratePerMinute, GetSpellInfo()); } // apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), chance); + modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance); } return chance; } -void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo) +void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) { - bool prevented = CallScriptProcHandlers(aurApp, eventInfo); - - if (!prevented) - { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!(procEffectMask & (1 << i))) - continue; + CallScriptProcHandlers(aurApp, eventInfo); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (aurApp->HasEffect(i)) // OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc() - if (aurApp->HasEffect(i)) - GetEffect(i)->HandleProc(aurApp, eventInfo); - } + GetEffect(i)->HandleProc(aurApp, eventInfo); - CallScriptAfterProcHandlers(aurApp, eventInfo); - } + CallScriptAfterProcHandlers(aurApp, eventInfo); // Remove aura if we've used last charge to proc if (IsUsingCharges() && !GetCharges()) @@ -2690,14 +2637,30 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool result = true; - for (auto & m_loadedScript : m_loadedScripts) + for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { - m_loadedScript->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); - auto hookItrEnd = m_loadedScript->DoCheckProc.end(), hookItr = m_loadedScript->DoCheckProc.begin(); + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); + std::list::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin(); for (; hookItr != hookItrEnd; ++hookItr) - result &= hookItr->Call(m_loadedScript, eventInfo); + result &= hookItr->Call(*scritr, eventInfo); - m_loadedScript->_FinishScriptCall(); + (*scritr)->_FinishScriptCall(); + } + + return result; +} + +bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + bool result = true; + for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp); + std::list::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + result &= hookItr->Call(*scritr, eventInfo); + + (*scritr)->_FinishScriptCall(); } return result; @@ -2752,26 +2715,6 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI } } -bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) -{ - bool result = true; - - for (std::list::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) - { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp); - std::list::iterator hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin(); - for (; hookItr != hookItrEnd; ++hookItr) - { - if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - result &= hookItr->Call(*scritr, aurEff, eventInfo); - } - - (*scritr)->_FinishScriptCall(); - } - - return result; -} - bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) { bool preventDefault = false; diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index c33ac114d..d98f391dc 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -191,14 +191,18 @@ public: bool CanStackWith(Aura const* checkAura, bool remove) const; bool IsAuraStronger(Aura const* newAura) const; - bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const; - void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd); + // Proc system + // this subsystem is not yet in use - the core of it is functional, but still some research has to be done + // and some dependant problems fixed before it can replace old proc system (for example cooldown handling) + // currently proc system functionality is implemented in Unit::ProcDamageAndSpell + bool IsProcOnCooldown() const; + void AddProcCooldown(uint32 msec); bool IsUsingCharges() const { return m_isUsingCharges; } void SetUsingCharges(bool val) { m_isUsingCharges = val; } - void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now); - uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const; + void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo); + bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; - void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo); + void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo); // AuraScript void LoadScripts(); @@ -222,7 +226,7 @@ public: // Spell Proc Hooks bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); - bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); + bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); @@ -265,8 +269,6 @@ protected: bool m_isSingleTarget: 1; // true if it's a single target spell and registered at caster - can change at spell steal for example bool m_isUsingCharges: 1; - std::chrono::steady_clock::time_point m_procCooldown; - private: Unit::AuraApplicationList m_removedApplications; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 20d8ad67c..813ef0dbe 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -640,7 +640,7 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, m_healing = 0; m_procAttacker = 0; m_procVictim = 0; - m_hitMask = 0; + m_procEx = 0; focusObject = nullptr; m_cast_count = 0; m_glyphIndex = 0; @@ -1811,7 +1811,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg { uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, maxTargets, this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); if (maxTargets > 1) { @@ -2273,11 +2273,12 @@ void Spell::SearchChainTargets(std::list& targets, uint32 chainTar } } -void Spell::prepareDataForTriggerSystem() +void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/) { //========================================================================================== // Now fill data for trigger system, need know: - // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask) + // can spell trigger another or not (m_canTrigger) + // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx) //========================================================================================== m_procVictim = m_procAttacker = 0; @@ -2316,6 +2317,7 @@ void Spell::prepareDataForTriggerSystem() // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget // Because spell positivity is dependant on target } + m_procEx = PROC_EX_NONE; // Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && @@ -2324,18 +2326,31 @@ void Spell::prepareDataForTriggerSystem() m_spellInfo->SpellFamilyFlags[2] & 0x00064000)) // Explosive and Immolation Trap { m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION; - - // also fill up other flags (DoAllEffectOnTarget only fills up flag if both are not set) - m_procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; - m_procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG; } + /* Effects which are result of aura proc from triggered spell cannot proc + to prevent chain proc of these spells */ + // Hellfire Effect - trigger as DOT if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040) { m_procAttacker = PROC_FLAG_DONE_PERIODIC; m_procVictim = PROC_FLAG_TAKEN_PERIODIC; } + + // Ranged autorepeat attack is set as triggered spell - ignore it + if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK)) + { + if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS && + (m_spellInfo->HasAttribute(SPELL_ATTR2_ACTIVE_THREAT) || + m_spellInfo->HasAttribute(SPELL_ATTR3_NOT_A_PROC))) + m_procEx |= PROC_EX_INTERNAL_CANT_PROC; + else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) + m_procEx |= PROC_EX_INTERNAL_TRIGGERED; + } + // Totem casts require spellfamilymask defined in spell_proc_event to proc + if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsTotem() && m_caster->IsControlledByPlayer()) + m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; } void Spell::CleanupTargetList() @@ -2347,32 +2362,6 @@ void Spell::CleanupTargetList() m_delayTrajectory = 0; } -class ProcReflectDelayed : public BasicEvent -{ -public: - ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { } - - bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override - { - Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid); - if (!caster) - return true; - - uint32 const typeMaskActor = PROC_FLAG_NONE; - uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG; - uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL; - uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE; - uint32 const hitMask = PROC_HIT_REFLECT; - - caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr); - return true; - } - -private: - Unit* _victim; - ObjectGuid _casterGuid; -}; - void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/) { for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) @@ -2384,8 +2373,11 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; if (checkIfValid) - if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE + { + SpellCastResult res = m_spellInfo->CheckTarget(m_caster, target, implicit); + if (res != SPELL_CAST_OK) return; + } // Check for effect immune skip if immuned for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) @@ -2456,22 +2448,23 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= targetInfo.timeDelay = (uint64) floor(dist / m_spellInfo->Speed * 1000.0f); // Calculate minimum incoming time - if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay) + if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay) m_delayMoment = targetInfo.timeDelay; } else - targetInfo.timeDelay = 0ULL; + targetInfo.timeDelay = 0LL; // If target reflect spell back to caster if (targetInfo.missCondition == SPELL_MISS_REFLECT) { // Calculate reflected spell result on caster - targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice + targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect); - // Proc spell reflect aura when missile hits the original target - target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay)); + if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell + targetInfo.reflectResult = SPELL_MISS_PARRY; // Increase time interval for reflected spells by 1.5 + m_caster->m_Events.AddEvent(new ReflectEvent(m_caster, targetInfo.targetGUID, m_spellInfo), m_caster->m_Events.CalculateTime(targetInfo.timeDelay)); targetInfo.timeDelay += targetInfo.timeDelay >> 1; m_spellFlags |= SPELL_FLAG_REFLECTED; @@ -2552,7 +2545,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) if (dist < 5.0f) dist = 5.0f; target.timeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f)); - if (!m_delayMoment || m_delayMoment > target.timeDelay) + if (m_delayMoment == 0 || m_delayMoment > target.timeDelay) m_delayMoment = target.timeDelay; } else @@ -2667,8 +2660,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(missInfo); - // Spells with this flag cannot trigger if effect is casted on self - bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2); + //Spells with this flag cannot trigger if effect is casted on self + bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2); bool reflectedSpell = missInfo == SPELL_MISS_REFLECT; Unit* spellHitTarget = nullptr; @@ -2706,14 +2699,18 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID) { m_needComboPoints = false; + // Restore spell mods for a miss/dodge/parry Cold Blood + // TODO: check how broad this rule should be + if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS || missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY)) + m_caster->ToPlayer()->RestoreSpellMods(this, 14177); } // Fill base trigger info uint32 procAttacker = m_procAttacker; uint32 procVictim = m_procVictim; - uint32 hitMask = m_hitMask; + uint32 procEx = m_procEx; - // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now + // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now if (canEffectTrigger && !procAttacker && !procVictim) { bool positive = true; @@ -2769,11 +2766,11 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (crit) { - hitMask |= PROC_HIT_CRITICAL; + procEx |= PROC_EX_CRITICAL_HIT; addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr); } else - hitMask |= PROC_HIT_NORMAL; + procEx |= PROC_EX_NORMAL_HIT; HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask()); @@ -2781,20 +2778,27 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (GetSpellValue()->ForcedCritResult) { crit = true; - hitMask |= PROC_HIT_CRITICAL; + procEx |= PROC_EX_CRITICAL_HIT; } int32 gain = caster->HealBySpell(healInfo, crit); unitTarget->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); m_healing = gain; - // Do triggers for unit + // Xinef: if heal acutally healed something, add no overheal flag + if (m_healing) + procEx |= PROC_EX_NO_OVERHEAL; + + // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo); + Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, + m_triggeredByAuraSpell.effectIndex, this, nullptr, &healInfo); } // Do damage and triggers else if (m_damage > 0) { + caster->SetLastDamagedTargetGuid(unitTarget->GetGUID()); + // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); @@ -2854,7 +2858,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (reflectedSpell) effectUnit->SendSpellNonMeleeReflectLog(&damageInfo, effectUnit); - hitMask |= createProcHitMask(&damageInfo, missInfo); + procEx |= createProcExtendMask(&damageInfo, missInfo); procVictim |= PROC_FLAG_TAKEN_DAMAGE; caster->DealSpellDamage(&damageInfo, true, this); @@ -2862,15 +2866,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // do procs after damage, eg healing effects // no need to check if target is alive, done in procdamageandspell - // Do triggers for unit + // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask); - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &dmgInfo, nullptr); + DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE); + Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, + m_triggeredByAuraSpell.effectIndex, this, &dmgInfo); if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) - caster->ToPlayer()->CastItemCombatSpell(dmgInfo); + caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); } m_damage = damageInfo.damage; @@ -2880,16 +2885,19 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); - hitMask |= createProcHitMask(&damageInfo, missInfo); - // Do triggers for unit + procEx |= createProcExtendMask(&damageInfo, missInfo); + // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask); - caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr); + DamageInfo dmgInfo(damageInfo, NODAMAGE); + Unit::ProcDamageAndSpell(caster, unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell.spellInfo, + m_triggeredByAuraSpell.effectIndex, this, &dmgInfo); - if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) && - !m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) - caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo); + // Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also + // Xinef: ofc count only spells that HIT the target, little hack used to fool the system + if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && + m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) + caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim | PROC_FLAG_TAKEN_DAMAGE, procEx); } // Failed Pickpocket, reveal rogue @@ -3113,6 +3121,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, refreshPeriodic); + // xinef: if aura was not refreshed, add proc ex + if (!refresh) + m_procEx |= PROC_EX_NO_AURA_REFRESH; + if (m_spellAura) { // Set aura stack amount to desired value @@ -3241,8 +3253,8 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) // info confirmed with retail sniffs of permafrost and shadow weaving if (!m_hitTriggerSpells.empty()) { - int32 _duration = 0; - for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) + int _duration = 0; + for (HitTriggerSpellList::const_iterator i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i) { if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance)) { @@ -3358,7 +3370,7 @@ bool Spell::UpdateChanneledTargetList() } if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, range, this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); // xinef: add little tolerance level range += std::min(3.0f, range * 0.1f); // 10% but no more than 3yd @@ -3521,7 +3533,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const } // Prepare data for triggers - prepareDataForTriggerSystem(); + prepareDataForTriggerSystem(triggeredByAura); // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) m_casttime = (_triggeredCastFlags & TRIGGERED_CAST_DIRECTLY) ? 0 : m_spellInfo->CalcCastTime(m_caster, this); @@ -3705,6 +3717,10 @@ void Spell::cancel(bool bySelf) if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->NeedSendSpectatorData()) ArenaSpectator::SendCommand_Spell(m_caster->FindMap(), m_caster->GetGUID(), "SPE", m_spellInfo->Id, bySelf ? 99998 : 99999); + // spell is canceled-take mods and clear list + if (Player* player = m_caster->GetSpellModOwner()) + player->RemoveSpellMods(this); + m_appliedMods.clear(); break; default: @@ -3929,14 +3945,26 @@ void Spell::_cast(bool skipCheck) } } - uint32 hitMask = m_hitMask; + uint32 procEx = PROC_EX_NORMAL_HIT; - if (!(hitMask & PROC_HIT_CRITICAL)) + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { - hitMask |= PROC_HIT_NORMAL; + if (ihit->missCondition != SPELL_MISS_NONE) + { + continue; + } + + if (!ihit->crit) + { + continue; + } + + procEx |= PROC_EX_CRITICAL_HIT; + break; } - m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); + Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo, + m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST); } if (modOwner) @@ -3957,6 +3985,11 @@ void Spell::_cast(bool skipCheck) if (m_caster->HasUnitState(UNIT_STATE_CASTING) && !m_caster->IsNonMeleeSpellCast(false, false, true)) m_caster->ClearUnitState(UNIT_STATE_CASTING); + // remove all applied mods at this point + // dont allow user to use them twice in case spell did not reach current target + if (modOwner) + modOwner->RemoveSpellMods(this); + // Xinef: why do we keep focus after spell is sent to air? // Xinef: Because of this, in the middle of some animation after setting targetguid to 0 etc // Xinef: we get focused to it out of nowhere... @@ -4049,7 +4082,7 @@ void Spell::handle_immediate() // First mod_duration then haste - see Missile Barrage // Apply duration mod if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); // Apply haste mods if (m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) @@ -4073,14 +4106,8 @@ void Spell::handle_immediate() // process immediate effects (items, ground, etc.) also initialize some variables _handle_immediate_phase(); - // consider spell hit for some spells without target, so they may proc on finish phase correctly - if (m_UniqueTargetInfo.empty()) - m_hitMask = PROC_HIT_NORMAL; - else - { - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - DoAllEffectOnTarget(&(*ihit)); - } + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + DoAllEffectOnTarget(&(*ihit)); for (std::list::iterator ihit = m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); @@ -4227,8 +4254,10 @@ void Spell::_handle_finish_phase() m_caster->AddComboPoints(m_comboTarget, m_comboPointGain); } - if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - m_caster->HandleProcExtraAttackFor(m_caster->GetVictim()); + if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + { + m_caster->SetLastExtraAttackSpell(m_spellInfo->Id); + } if (!IsAutoRepeat() && !IsNextMeleeSwingSpell()) if (m_caster->GetCharmerOrOwnerPlayerOrPlayerItself()) @@ -4257,13 +4286,25 @@ void Spell::_handle_finish_phase() } } - uint32 hitMask = m_hitMask; - if (!(hitMask & PROC_HIT_CRITICAL)) + uint32 procEx = PROC_EX_NORMAL_HIT; + for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { - hitMask |= PROC_HIT_NORMAL; + if (ihit->missCondition != SPELL_MISS_NONE) + { + continue; + } + + if (!ihit->crit) + { + continue; + } + + procEx |= PROC_EX_CRITICAL_HIT; + break; } - m_originalCaster->ProcSkillsAndAuras(m_originalCaster, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, hitMask, this, nullptr, nullptr); + Unit::ProcDamageAndSpell(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, procEx, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo, + m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_FINISH); } } @@ -4453,6 +4494,11 @@ void Spell::finish(bool ok) if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_triggeredByAuraSpell) m_caster->ToPlayer()->UpdatePotionCooldown(this); + // Take mods after trigger spell (needed for 14177 to affect 48664) + // mods are taken only on succesfull cast and independantly from targets of the spell + if (Player* player = m_caster->GetSpellModOwner()) + player->RemoveSpellMods(this); + // xinef: clear reactive auras states after spell cast if (m_spellInfo->CasterAuraState == AURA_STATE_DEFENSE || m_spellInfo->CasterAuraState == AURA_STATE_HUNTER_PARRY) m_caster->ModifyAuraState(AuraStateType(m_spellInfo->CasterAuraState), false); @@ -5237,7 +5283,7 @@ void Spell::TakePower() hit = false; //lower spell cost on fail (by talent aura) if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, m_powerCost, this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost, this); } break; } @@ -5338,7 +5384,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 RuneCostID) { runeCost[i] = src->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, runeCost[i], this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this); } runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later @@ -5378,7 +5424,7 @@ void Spell::TakeRunePower(bool didHit) { runeCost[i] = runeCostData->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, runeCost[i], this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this); } runeCost[RUNE_DEATH] = 0; // calculated later @@ -5775,11 +5821,7 @@ SpellCastResult Spell::CheckCast(bool strict) // Xinef: do not check explicit target for triggered spell casted on self with targetflag enemy if (!m_triggeredByAuraSpell || m_targets.GetUnitTarget() != m_caster || !(m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY)) { - Unit* caster = m_caster; - if (m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) // Do a simplified check for gameobject casts - caster = m_originalCaster; - - SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget()); + SpellCastResult castResult = m_spellInfo->CheckExplicitTarget((m_originalCaster && m_caster->GetEntry() != WORLD_TRIGGER) ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget()); if (castResult != SPELL_CAST_OK) return castResult; } @@ -5787,7 +5829,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (Unit* target = m_targets.GetUnitTarget()) { - SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetEntry() == WORLD_TRIGGER); // skip stealth checks for GO casts + SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false); if (castResult != SPELL_CAST_OK) return castResult; @@ -6983,7 +7025,7 @@ SpellCastResult Spell::CheckRange(bool strict) range_type = SPELL_RANGE_RANGED; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, max_range, this); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, max_range, this); // xinef: dont check max_range to strictly after cast if (range_type != SPELL_RANGE_MELEE && !strict) @@ -7697,7 +7739,7 @@ void Spell::Delayed() // only called in DealDamage() //check pushback reduce int32 delaytime = 500; // spellcasting delay is normally 500ms int32 delayReduce = 100; // must be initialized to 100 for percent modifiers - m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, delayReduce, this); + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -7735,7 +7777,7 @@ void Spell::DelayedChannel() int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit int32 delayReduce = 100; // must be initialized to 100 for percent modifiers - m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, delayReduce, this); + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this); delayReduce += m_caster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -8115,6 +8157,14 @@ bool SpellEvent::IsDeletable() const return m_Spell->IsDeletable(); } +bool ReflectEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) +{ + Unit* target = ObjectAccessor::GetUnit(*_caster, _targetGUID); + if (target && _caster->IsInMap(target)) + Unit::ProcDamageAndSpell(_caster, target, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, _spellInfo); + return true; +} + bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const { if (target->IsAlive()) @@ -8690,24 +8740,26 @@ void Spell::PrepareTriggersExecutedOnHit() // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster // and to correctly calculate proc chance when combopoints are present Unit::AuraEffectList const& targetTriggers = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER); - for (AuraEffect const* aurEff : targetTriggers) + for (Unit::AuraEffectList::const_iterator i = targetTriggers.begin(); i != targetTriggers.end(); ++i) { - if (!aurEff->IsAffectedOnSpell(m_spellInfo)) + if (!(*i)->IsAffectedOnSpell(m_spellInfo)) continue; - - SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo(); - uint32 auraSpellIdx = aurEff->GetEffIndex(); + SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); + uint32 auraSpellIdx = (*i)->GetEffIndex(); if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell)) { // calculate the chance using spell base amount, because aura amount is not updated on combo-points change // this possibly needs fixing - int32 auraBaseAmount = aurEff->GetBaseAmount(); + int32 auraBaseAmount = (*i)->GetBaseAmount(); // proc chance is stored in effect amount int32 chance = m_caster->CalculateSpellDamage(nullptr, auraSpellInfo, auraSpellIdx, &auraBaseAmount); - chance *= aurEff->GetBase()->GetStackAmount(); - // build trigger and add to the list - m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance); + HitTriggerSpell spellTriggerInfo; + spellTriggerInfo.triggeredSpell = spellInfo; + spellTriggerInfo.triggeredByAura = auraSpellInfo; + spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex(); + spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); + m_hitTriggerSpells.push_back(spellTriggerInfo); } } } @@ -8752,8 +8804,8 @@ void Spell::TriggerGlobalCooldown() if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD) { // gcd modifier auras are applied only to own spells and only players have such mods - if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, gcd, this); + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this); // Apply haste rating if (m_spellInfo->StartRecoveryCategory == 133 && m_spellInfo->StartRecoveryTime == 1500 && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && @@ -8762,7 +8814,10 @@ void Spell::TriggerGlobalCooldown() gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); } - RoundToInterval(gcd, MIN_GCD, MAX_GCD); + if (gcd < MIN_GCD) + gcd = MIN_GCD; + else if (gcd > MAX_GCD) + gcd = MAX_GCD; } // Only players or controlled units have global cooldown diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 642ceda36..f6e3e646f 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -414,7 +414,7 @@ public: void EffectCastButtons(SpellEffIndex effIndex); void EffectRechargeManaGem(SpellEffIndex effIndex); - typedef std::unordered_set UsedSpellMods; + typedef std::set UsedSpellMods; void InitExplicitTargets(SpellCastTargets const& targets); void SelectExplicitTargets(); @@ -553,9 +553,6 @@ public: bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; } bool IsAutoActionResetSpell() const; bool IsIgnoringCooldowns() const; - bool IsProcDisabled() const { return (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS) != 0; } - - bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell.spellInfo); } bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; } void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; } @@ -673,8 +670,8 @@ public: // ****************************************** uint32 m_procAttacker; // Attacker trigger flags uint32 m_procVictim; // Victim trigger flags - uint32 m_hitMask; - void prepareDataForTriggerSystem(); + uint32 m_procEx; + void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura); // ***************************************** // Spell target subsystem @@ -742,9 +739,6 @@ public: struct HitTriggerSpell { - HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) : - triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { } - SpellInfo const* triggeredSpell; SpellInfo const* triggeredByAura; uint8 triggeredByEffIdx; @@ -753,7 +747,7 @@ public: bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura = nullptr) const; void PrepareTriggersExecutedOnHit(); - typedef std::vector HitTriggerSpellList; + typedef std::list HitTriggerSpellList; HitTriggerSpellList m_hitTriggerSpells; // effect helpers @@ -844,4 +838,17 @@ namespace Acore } typedef void(Spell::*pEffect)(SpellEffIndex effIndex); + +class ReflectEvent : public BasicEvent +{ + public: + ReflectEvent(Unit* caster, ObjectGuid targetGUID, SpellInfo const* spellInfo) : _caster(caster), _targetGUID(targetGUID), _spellInfo(spellInfo) { } + bool Execute(uint64 e_time, uint32 p_time) override; + + protected: + Unit* _caster; + ObjectGuid _targetGUID; + SpellInfo const* _spellInfo; +}; + #endif diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index d3bd7d3db..f3e08fc34 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -72,38 +72,38 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE), }; -enum SpellModOp : uint8 +enum SpellModOp { - SPELLMOD_DAMAGE = 0, - SPELLMOD_DURATION = 1, - SPELLMOD_THREAT = 2, - SPELLMOD_EFFECT1 = 3, - SPELLMOD_CHARGES = 4, - SPELLMOD_RANGE = 5, - SPELLMOD_RADIUS = 6, - SPELLMOD_CRITICAL_CHANCE = 7, - SPELLMOD_ALL_EFFECTS = 8, - SPELLMOD_NOT_LOSE_CASTING_TIME = 9, - SPELLMOD_CASTING_TIME = 10, - SPELLMOD_COOLDOWN = 11, - SPELLMOD_EFFECT2 = 12, - SPELLMOD_IGNORE_ARMOR = 13, - SPELLMOD_COST = 14, - SPELLMOD_CRIT_DAMAGE_BONUS = 15, - SPELLMOD_RESIST_MISS_CHANCE = 16, - SPELLMOD_JUMP_TARGETS = 17, - SPELLMOD_CHANCE_OF_SUCCESS = 18, - SPELLMOD_ACTIVATION_TIME = 19, - SPELLMOD_DAMAGE_MULTIPLIER = 20, - SPELLMOD_GLOBAL_COOLDOWN = 21, - SPELLMOD_DOT = 22, - SPELLMOD_EFFECT3 = 23, - SPELLMOD_BONUS_MULTIPLIER = 24, + SPELLMOD_DAMAGE = 0, + SPELLMOD_DURATION = 1, + SPELLMOD_THREAT = 2, + SPELLMOD_EFFECT1 = 3, + SPELLMOD_CHARGES = 4, + SPELLMOD_RANGE = 5, + SPELLMOD_RADIUS = 6, + SPELLMOD_CRITICAL_CHANCE = 7, + SPELLMOD_ALL_EFFECTS = 8, + SPELLMOD_NOT_LOSE_CASTING_TIME = 9, + SPELLMOD_CASTING_TIME = 10, + SPELLMOD_COOLDOWN = 11, + SPELLMOD_EFFECT2 = 12, + SPELLMOD_IGNORE_ARMOR = 13, + SPELLMOD_COST = 14, + SPELLMOD_CRIT_DAMAGE_BONUS = 15, + SPELLMOD_RESIST_MISS_CHANCE = 16, + SPELLMOD_JUMP_TARGETS = 17, + SPELLMOD_CHANCE_OF_SUCCESS = 18, + SPELLMOD_ACTIVATION_TIME = 19, + SPELLMOD_DAMAGE_MULTIPLIER = 20, + SPELLMOD_GLOBAL_COOLDOWN = 21, + SPELLMOD_DOT = 22, + SPELLMOD_EFFECT3 = 23, + SPELLMOD_BONUS_MULTIPLIER = 24, // spellmod 25 - SPELLMOD_PROC_PER_MINUTE = 26, - SPELLMOD_VALUE_MULTIPLIER = 27, - SPELLMOD_RESIST_DISPEL_CHANCE = 28, - SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell + SPELLMOD_PROC_PER_MINUTE = 26, + SPELLMOD_VALUE_MULTIPLIER = 27, + SPELLMOD_RESIST_DISPEL_CHANCE = 28, + SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30 }; @@ -141,10 +141,9 @@ enum TriggerCastFlags TRIGGERED_IGNORE_SET_FACING = 0x00000200, //! Will not adjust facing to target (if any) TRIGGERED_IGNORE_SHAPESHIFT = 0x00000400, //! Will ignore shapeshift checks TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state - TRIGGERED_DISALLOW_PROC_EVENTS = 0x00001000, //! Disallows proc events from triggered spell (default) TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements - // reuse 0x00020000 + TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default) TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions TRIGGERED_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b847c8f13..87dbb64a6 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -310,8 +310,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); else { - DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); - m_caster->CalcAbsorbResist(dmgInfo); + DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE); uint32 absorb = dmgInfo.GetAbsorb(); uint32 resist = dmgInfo.GetResist(); @@ -2343,7 +2342,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); TempSummon* summon = nullptr; @@ -3149,7 +3148,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex) int32 duration = m_spellInfo->GetDuration(); if(Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); Player* owner = m_originalCaster->ToPlayer(); if (!owner && m_originalCaster->ToCreature()->IsTotem()) @@ -3723,7 +3722,6 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) { int32 duration = m_originalCaster->ModSpellDuration(m_spellInfo, unitTarget, m_originalCaster->CalcSpellDuration(m_spellInfo), false, 1 << effIndex); unitTarget->ProhibitSpellSchool(curSpellInfo->GetSchoolMask(), duration/*spellInfo->GetDuration()*/); - m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr); } ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id); unitTarget->InterruptSpell(CurrentSpellTypes(i), false); @@ -4684,17 +4682,18 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + { return; + } - if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->GetVictim()) + if (!unitTarget || !unitTarget->IsAlive()) + { return; + } - if (unitTarget->m_extraAttacks) - return; + unitTarget->AddExtraAttacks(damage); - unitTarget->m_extraAttacks = damage; - - ExecuteLogEffectExtraAttacks(effIndex, unitTarget->GetVictim(), damage); + ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage); } void Spell::EffectParry(SpellEffIndex /*effIndex*/) @@ -5817,8 +5816,19 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) m_runesState = m_caster->ToPlayer()->GetRunesState(); uint32 count = damage; - if (count == 0) - count = 1; + if (count == 0) count = 1; + for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) + { + if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) + { + if (m_spellInfo->Id == 45529) + if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) + continue; + player->SetRuneCooldown(j, 0); + player->SetGracePeriod(j, player->IsInCombat()); // xinef: reset grace period + --count; + } + } // Blood Tap if (m_spellInfo->Id == 45529 && count > 0) @@ -5826,10 +5836,10 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) for (uint32 l = 0; l < MAX_RUNES && count > 0; ++l) { // Check if both runes are on cd as that is the only time when this needs to come into effect - if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RUNE_BLOOD)) + if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l + 1) && player->GetCurrentRune(l + 1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB))) { // Should always update the rune with the lowest cd - if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1)) + if (player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1)) l++; player->SetRuneCooldown(l, 0); player->SetGracePeriod(l, player->IsInCombat()); // xinef: reset grace period @@ -5840,15 +5850,6 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) } } - for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) - { - if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) - { - player->SetRuneCooldown(j, 0); - --count; - } - } - // Empower rune weapon if (m_spellInfo->Id == 47568) { @@ -5858,7 +5859,7 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) for (uint32 i = 0; i < MAX_RUNES; ++i) { - if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST)) + if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH)) { player->SetRuneCooldown(i, 0); player->SetGracePeriod(i, player->IsInCombat()); // xinef: reset grace period @@ -6060,7 +6061,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = m_originalCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, duration); + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); //TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; Map* map = caster->GetMap(); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 8d24dd6df..a9a73f07c 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -524,7 +524,7 @@ float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const { float multiplier = ValueMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, multiplier, spell); + modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell); return multiplier; } @@ -532,7 +532,7 @@ float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const { float multiplier = DamageMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, multiplier, spell); + modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell); return multiplier; } @@ -552,7 +552,7 @@ float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const radius += RadiusEntry->RadiusPerLevel * caster->getLevel(); radius = std::min(radius, RadiusEntry->RadiusMax); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(_spellInfo->Id, radius, spell); + modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell); } return radius; @@ -831,7 +831,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry) SpellVisual = spellEntry->SpellVisual; SpellIconID = spellEntry->SpellIconID; ActiveIconID = spellEntry->ActiveIconID; - Priority = spellEntry->SpellPriority; + SpellPriority = spellEntry->SpellPriority; SpellName = spellEntry->SpellName; Rank = spellEntry->Rank; MaxTargetLevel = spellEntry->MaxTargetLevel; @@ -1268,26 +1268,6 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT; } -bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const -{ - if (!familyName) - { - return true; - } - - if (familyName != SpellFamilyName) - { - return false; - } - - if (familyFlags && !(familyFlags & SpellFamilyFlags)) - { - return false; - } - - return true; -} - bool SpellInfo::IsAffectedBySpellMods() const { return !(AttributesEx3 & SPELL_ATTR3_IGNORE_CASTER_MODIFIERS); @@ -1312,7 +1292,15 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const return true; } - return IsAffected(affectSpell->SpellFamilyName, mod->mask); + // False if affect_spell == nullptr or spellFamily not equal + if (affectSpell->SpellFamilyName != SpellFamilyName) + return false; + + // true + if (mod->mask & SpellFamilyFlags) + return true; + + return false; } bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const @@ -2323,7 +2311,7 @@ float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const range = RangeEntry->RangeMax[0]; if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, range, spell); + modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell); return range; } @@ -2458,7 +2446,7 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S // Apply cost mod by spell if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, powerCost, spell); + modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell); if (!caster->IsControlledByPlayer()) { diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 5b8ad7a9b..dc300600b 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -377,7 +377,7 @@ public: std::array SpellVisual; uint32 SpellIconID; uint32 ActiveIconID; - uint32 Priority; + uint32 SpellPriority; std::array SpellName; std::array Rank; uint32 MaxTargetLevel; @@ -463,8 +463,6 @@ public: bool IsRangedWeaponSpell() const; bool IsAutoRepeatRangedSpell() const; - bool IsAffected(uint32 familyName, flag96 const& familyFlags) const; - bool IsAffectedBySpellMods() const; bool IsAffectedBySpellMod(SpellModifier const* mod) const; diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index c47169b9d..e9f247979 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -171,7 +171,7 @@ void SpellMgr::LoadSpellInfoCorrections() 53232, // Rapid Killing (Rank 2) }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; // Entries were not updated after spell effect change, we have to do that manually + spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS; // Entries were not updated after spell effect change, we have to do that manually }); ApplySpellFix({ @@ -257,7 +257,7 @@ void SpellMgr::LoadSpellInfoCorrections() ApplySpellFix({ 57761 }, [](SpellInfo* spellInfo) { spellInfo->ProcCharges = 1; - spellInfo->Priority = 50; + spellInfo->SpellPriority = 50; }); // Tidal Wave @@ -272,10 +272,10 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE; }); - // Death and Decay - ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo) + // Ascendance (Talisman of Ascendance trinket) + ApplySpellFix({ 28200 }, [](SpellInfo* spellInfo) { - spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_PHASE_SHIFT; + spellInfo->ProcCharges = 6; }); // The Eye of Acherus (no spawn in phase 2 in db) @@ -4458,10 +4458,6 @@ void SpellMgr::LoadSpellInfoCorrections() } } - // disable proc for magnet auras, they're handled differently - if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET)) - spellInfo->ProcFlags = 0; - if (spellInfo->ActiveIconID == 2158) // flight { spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 866a1a7b1..8d9524bf5 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -727,6 +727,166 @@ void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpe availableElixirs.insert(itr->first); // insert spell id } +SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const +{ + SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); + if (itr != mSpellProcEventMap.end()) + return &itr->second; + return nullptr; +} + +bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const +{ + // No extra req need + uint32 procEvent_procEx = PROC_EX_NONE; + uint32 procEvent_procPhase = PROC_SPELL_PHASE_HIT; + + uint32 procFlags = eventInfo.GetTypeMask(); + uint32 procExtra = eventInfo.GetHitMask(); + uint32 procPhase = eventInfo.GetSpellPhaseMask(); + SpellInfo const* procSpellInfo = eventInfo.GetSpellInfo(); + + // check prockFlags for condition + if ((procFlags & EventProcFlag) == 0) + return false; + + // Xinef: Always trigger for this, including TAKEN_DAMAGE + if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH | PROC_FLAG_TAKEN_DAMAGE)) + return true; + + bool hasFamilyMask = false; + + if (procFlags & PROC_FLAG_DONE_PERIODIC) + { + if (procExtra & PROC_EX_INTERNAL_HOT) + { + if (EventProcFlag == PROC_FLAG_DONE_PERIODIC) + { + /// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT. + if (!spellProto->SpellFamilyName) + return false; + } + /// Aura must have positive procflags for a HOT to proc + else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS))) + return false; + } + /// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc + else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC) + if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION))) + return false; + } + + if (procFlags & PROC_FLAG_TAKEN_PERIODIC) + { + if (procExtra & PROC_EX_INTERNAL_HOT) + { + /// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT. + if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC) + return false; + /// Aura must have positive procflags for a HOT to proc + if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS))) + return false; + } + /// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc + else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC) + if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG))) + return false; + } + + // Trap casts are active by default + if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) + active = true; + + if (spellProcEvent) // Exist event data + { + // Store extra req + procEvent_procEx = spellProcEvent->procEx; + procEvent_procPhase = spellProcEvent->procPhase; + + // For melee triggers + if (!procSpellInfo) + { + // Check (if set) for school (melee attack have Normal school) + if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) + return false; + } + else // For spells need check school/spell family/family mask + { + // Check (if set) for school + if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpellInfo->SchoolMask) == 0) + return false; + + // Check (if set) for spellFamilyName + if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpellInfo->SpellFamilyName)) + return false; + + // spellFamilyName is Ok need check for spellFamilyMask if present + if (spellProcEvent->spellFamilyMask) + { + if (!(spellProcEvent->spellFamilyMask & procSpellInfo->SpellFamilyFlags)) + return false; + hasFamilyMask = true; + // Some spells are not considered as active even with have spellfamilyflags + if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)) + active = true; + } + + // Check tick numbers + if (procEvent_procEx & PROC_EX_ONLY_FIRST_TICK) + { + if (Spell const* procSpell = eventInfo.GetProcSpell()) + { + if (procSpell->GetTriggeredByAuraTickNumber() > 1) + { + return false; + } + } + } + } + } + + if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY)) + { + if (!hasFamilyMask) + return false; + } + + if (!(procEvent_procPhase & procPhase)) + { + return false; + } + + // Check for extra req (if none) and hit/crit + if (procEvent_procEx == PROC_EX_NONE) + { + // No extra req, so can trigger only for hit/crit - spell has to be active + if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active) + return true; + } + else // Passive spells hits here only if resist/reflect/immune/evade + { + if (procExtra & AURA_SPELL_PROC_EX_MASK) + { + // if spell marked as procing only from not active spells + if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL) + return false; + // if spell marked as procing only from active spells + if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL) + return false; + // Exist req for PROC_EX_EX_TRIGGER_ALWAYS + if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS) + return true; + // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before + if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0)) + return true; + } + // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other) + if (procEvent_procEx & procExtra) + return true; + } + return false; +} + SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const { SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId); @@ -735,78 +895,54 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const return nullptr; } -bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) +bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const { // proc type doesn't match - if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags)) + if (!(eventInfo.GetTypeMask() & procEntry.typeMask)) return false; // check XP or honor target requirement - if (procEntry.AttributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) + if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) if (Player* actor = eventInfo.GetActor()->ToPlayer()) if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget())) return false; - // check mana requirement - if (procEntry.AttributesMask & PROC_ATTR_REQ_MANA_COST) - if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo()) - if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage) - return false; - // always trigger for these types if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH)) return true; - // do triggered cast checks - // Do not consider autoattacks as triggered spells - if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC) && !(eventInfo.GetTypeMask() & AUTO_ATTACK_PROC_FLAG_MASK)) - { - if (Spell const* spell = eventInfo.GetProcSpell()) - { - if (spell->IsTriggered()) - { - SpellInfo const* spellInfo = spell->GetSpellInfo(); - if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) && - !spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC)) - return false; - } - } - } - // check school mask (if set) for other trigger types - if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask)) + if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask)) return false; // check spell family name/flags (if set) for spells - if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK)) + if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION)) { - if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo()) - { - if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask)) - { - return false; - } - } + if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName)) + return false; + + if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags)) + return false; } // check spell type mask (if set) if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)) { - if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask)) + if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask)) return false; } // check spell phase mask if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK) { - if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask)) + if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask)) return false; } // check hit mask (on taken hit or on done hit, but not on spell cast phase) if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST))) { - uint32 hitMask = procEntry.HitMask; + uint32 hitMask = procEntry.hitMask; // get default values if hit mask not set if (!hitMask) { @@ -1597,17 +1733,111 @@ void SpellMgr::LoadSpellGroupStackRules() LOG_INFO("server.loading", " "); } +void SpellMgr::LoadSpellProcEvents() +{ + uint32 oldMSTime = getMSTime(); + + mSpellProcEventMap.clear(); // need for reload case + + // 0 1 2 3 4 5 6 7 8 9 10 11 + QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, procPhase, ppmRate, CustomChance, Cooldown FROM spell_proc_event"); + if (!result) + { + LOG_WARN("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + + int32 spellId = fields[0].Get(); + + bool allRanks = false; + if (spellId < 0) + { + allRanks = true; + spellId = -spellId; + } + + SpellInfo const* spellInfo = GetSpellInfo(spellId); + if (!spellInfo) + { + LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` does not exist", spellId); + continue; + } + + if (allRanks) + { + if (!spellInfo->IsRanked()) + LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId); + + if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) + { + LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` is not first rank of spell.", spellId); + continue; + } + } + + SpellProcEventEntry spellProcEvent; + + spellProcEvent.schoolMask = fields[1].Get(); + spellProcEvent.spellFamilyName = fields[2].Get(); + spellProcEvent.spellFamilyMask[0] = fields[3].Get(); + spellProcEvent.spellFamilyMask[1] = fields[4].Get(); + spellProcEvent.spellFamilyMask[2] = fields[5].Get(); + spellProcEvent.procFlags = fields[6].Get(); + spellProcEvent.procEx = fields[7].Get(); + spellProcEvent.procPhase = fields[8].Get(); + spellProcEvent.ppmRate = fields[9].Get(); + spellProcEvent.customChance = fields[10].Get(); + spellProcEvent.cooldown = fields[11].Get(); + + // PROC_SPELL_PHASE_NONE is by default PROC_SPELL_PHASE_HIT + if (spellProcEvent.procPhase == PROC_SPELL_PHASE_NONE) + { + spellProcEvent.procPhase = PROC_SPELL_PHASE_HIT; + } + + while (spellInfo) + { + if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end()) + { + LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id); + break; + } + + if (!spellInfo->ProcFlags && !spellProcEvent.procFlags) + LOG_ERROR("sql.sql", "Spell {} listed in `spell_proc_event` probally not triggered spell", spellInfo->Id); + + mSpellProcEventMap[spellInfo->Id] = spellProcEvent; + + if (allRanks) + spellInfo = spellInfo->GetNextRankSpell(); + else + break; + } + + ++count; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} + void SpellMgr::LoadSpellProcs() { uint32 oldMSTime = getMSTime(); mSpellProcMap.clear(); // need for reload case - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc"); if (!result) { - LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty."); + LOG_WARN("server.loading", ">> Loaded 0 Spell Proc Conditions And Data. DB table `spell_proc` Is Empty."); LOG_INFO("server.loading", " "); return; } @@ -1644,20 +1874,21 @@ void SpellMgr::LoadSpellProcs() SpellProcEntry baseProcEntry; - baseProcEntry.SchoolMask = fields[1].Get(); - baseProcEntry.SpellFamilyName = fields[2].Get(); - baseProcEntry.SpellFamilyMask[0] = fields[3].Get(); - baseProcEntry.SpellFamilyMask[1] = fields[4].Get(); - baseProcEntry.SpellFamilyMask[2] = fields[5].Get(); - baseProcEntry.ProcFlags = fields[6].Get(); - baseProcEntry.SpellTypeMask = fields[7].Get(); - baseProcEntry.SpellPhaseMask = fields[8].Get(); - baseProcEntry.HitMask = fields[9].Get(); - baseProcEntry.AttributesMask = fields[10].Get(); - baseProcEntry.ProcsPerMinute = fields[11].Get(); - baseProcEntry.Chance = fields[12].Get(); - baseProcEntry.Cooldown = Milliseconds(fields[13].Get()); - baseProcEntry.Charges = fields[14].Get(); + baseProcEntry.schoolMask = fields[1].Get(); + baseProcEntry.spellFamilyName = fields[2].Get(); + baseProcEntry.spellFamilyMask[0] = fields[3].Get(); + baseProcEntry.spellFamilyMask[1] = fields[4].Get(); + baseProcEntry.spellFamilyMask[2] = fields[5].Get(); + baseProcEntry.typeMask = fields[6].Get(); + baseProcEntry.spellTypeMask = fields[7].Get(); + baseProcEntry.spellPhaseMask = fields[8].Get(); + baseProcEntry.hitMask = fields[9].Get(); + baseProcEntry.attributesMask = fields[10].Get(); + baseProcEntry.ratePerMinute = fields[11].Get(); + baseProcEntry.chance = fields[12].Get(); + float cooldown = fields[13].Get(); + baseProcEntry.cooldown = uint32(cooldown); + baseProcEntry.charges = fields[14].Get(); while (spellInfo) { @@ -1669,54 +1900,56 @@ void SpellMgr::LoadSpellProcs() SpellProcEntry procEntry = SpellProcEntry(baseProcEntry); // take defaults from dbcs - if (!procEntry.ProcFlags) - procEntry.ProcFlags = spellInfo->ProcFlags; - if (!procEntry.Charges) - procEntry.Charges = spellInfo->ProcCharges; - if (!procEntry.Chance && !procEntry.ProcsPerMinute) - procEntry.Chance = float(spellInfo->ProcChance); + if (!procEntry.typeMask) + procEntry.typeMask = spellInfo->ProcFlags; + if (!procEntry.charges) + procEntry.charges = spellInfo->ProcCharges; + if (!procEntry.chance && !procEntry.ratePerMinute) + procEntry.chance = float(spellInfo->ProcChance); // validate data - if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SchoolMask` set: {}", spellId, procEntry.SchoolMask); - if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16)) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellFamilyName` set: {}", spellId, procEntry.SpellFamilyName); - if (procEntry.Chance < 0) + if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `schoolMask` set: {}", spellId, procEntry.schoolMask); + if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16)) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellFamilyName` set: {}", spellId, procEntry.spellFamilyName); + if (procEntry.chance < 0) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `Chance` field", spellId); - procEntry.Chance = 0; + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `chance` field", spellId); + procEntry.chance = 0; } - if (procEntry.ProcsPerMinute < 0) + if (procEntry.ratePerMinute < 0) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has negative value in `ProcsPerMinute` field", spellId); - procEntry.ProcsPerMinute = 0; + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `ratePerMinute` field", spellId); + procEntry.ratePerMinute = 0; } - if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellId); - if (procEntry.Charges > 99) + if (cooldown < 0) { - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has too big value in `Charges` field", spellId); - procEntry.Charges = 99; + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in `cooldown` field", spellId); + procEntry.cooldown = 0; } - if (!procEntry.ProcFlags) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `ProcFlags` value defined, proc will not be triggered", spellId); - if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellTypeMask` set: {}", spellId, procEntry.SpellTypeMask); - if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellId); - if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellId); - if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `SpellPhaseMask` set: {}", spellId, procEntry.SpellPhaseMask); - if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellId); - if (procEntry.HitMask & ~PROC_HIT_MASK_ALL) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has wrong `HitMask` set: {}", spellId, procEntry.HitMask); - if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) - LOG_ERROR("sql.sql", "`spell_proc` table entry for SpellId {} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellId); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if ((procEntry.AttributesMask & (PROC_ATTR_DISABLE_EFF_0 << i)) && !spellInfo->Effects[i].IsAura()) - LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has Attribute PROC_ATTR_DISABLE_EFF_{}, but effect {} is not an aura effect", spellInfo->Id, static_cast(i), static_cast(i)); + if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId); + if (procEntry.charges > 99) + { + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has too big value in `charges` field", spellId); + procEntry.charges = 99; + } + if (!procEntry.typeMask) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `typeMask` value defined, proc will not be triggered", spellId); + if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellTypeMask` set: {}", spellId, procEntry.spellTypeMask); + if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId); + if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId); + if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `spellPhaseMask` set: {}", spellId, procEntry.spellPhaseMask); + if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId); + if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `hitMask` set: {}", spellId, procEntry.hitMask); + if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) + LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId); mSpellProcMap[spellInfo->Id] = procEntry; @@ -1728,175 +1961,8 @@ void SpellMgr::LoadSpellProcs() ++count; } while (result->NextRow()); - LOG_INFO("server.loading", ">> Loaded {} Extra Spell Proc Event Conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); - - // Define can trigger auras - bool isTriggerAura[TOTAL_AURAS]; - // Triggered always, even from triggered spells - bool isAlwaysTriggeredAura[TOTAL_AURAS]; - // SpellTypeMask to add to the proc - uint32 spellTypeMask[TOTAL_AURAS]; - - // List of auras that CAN trigger but may not exist in spell_proc - // in most cases needed to drop charges - - // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check) - // see AuraEffect::CheckEffectProc - for (uint16 i = 0; i < TOTAL_AURAS; ++i) - { - isTriggerAura[i] = false; - isAlwaysTriggeredAura[i] = false; - spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL; - } - - isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311) - isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets" - isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus - isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger - isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; - isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; - isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; - isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; - isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger - isTriggerAura[SPELL_AURA_MOD_ROOT] = true; - isTriggerAura[SPELL_AURA_TRANSFORM] = true; - isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; - isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true; - isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true; - isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true; - isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true; - isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true; - isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true; - isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true; - isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true; - isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; - isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true; - isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true; - isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true; - isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true; - isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; - isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true; - isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true; - isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true; - isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true; - - isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true; - isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true; - isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true; - - spellTypeMask[SPELL_AURA_MOD_STEALTH] = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL; - spellTypeMask[SPELL_AURA_MOD_CONFUSE] = PROC_SPELL_TYPE_DAMAGE; - spellTypeMask[SPELL_AURA_MOD_FEAR] = PROC_SPELL_TYPE_DAMAGE; - spellTypeMask[SPELL_AURA_MOD_ROOT] = PROC_SPELL_TYPE_DAMAGE; - spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE; - spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE; - - // This generates default procs to retain compatibility with previous proc system - LOG_INFO("server.loading", "Generating spell proc data from SpellMap..."); - count = 0; - oldMSTime = getMSTime(); - - for (SpellInfo const* spellInfo : mSpellInfoMap) - { - if (!spellInfo) - continue; - - // Data already present in DB, overwrites default proc - if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end()) - continue; - - // Nothing to do if no flags set - if (!spellInfo->ProcFlags) - continue; - - bool addTriggerFlag = false; - uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!spellInfo->Effects[i].IsEffect()) - continue; - - uint32 auraName = spellInfo->Effects[i].ApplyAuraName; - if (!auraName) - continue; - - if (!isTriggerAura[auraName]) - continue; - - procSpellTypeMask |= spellTypeMask[auraName]; - - if (isAlwaysTriggeredAura[auraName]) - addTriggerFlag = true; - - // many proc auras with taken procFlag mask don't have attribute "can proc with triggered" - // they should proc nevertheless (example mage armor spells with judgement) - if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0) - { - switch (auraName) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - case SPELL_AURA_PROC_TRIGGER_DAMAGE: - addTriggerFlag = true; - break; - default: - break; - } - } - - break; - } - - if (!procSpellTypeMask) - continue; - - SpellProcEntry procEntry; - procEntry.SchoolMask = 0; - procEntry.ProcFlags = spellInfo->ProcFlags; - procEntry.SpellFamilyName = 0; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (spellInfo->Effects[i].IsEffect() && isTriggerAura[spellInfo->Effects[i].ApplyAuraName]) - procEntry.SpellFamilyMask |= spellInfo->Effects[i].SpellClassMask; - - if (procEntry.SpellFamilyMask) - procEntry.SpellFamilyName = spellInfo->SpellFamilyName; - - procEntry.SpellTypeMask = procSpellTypeMask; - procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT; - procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent - - // Reflect auras should only proc off reflects - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS) || spellInfo->Effects[i].IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL)) - { - procEntry.HitMask = PROC_HIT_REFLECT; - break; - } - } - - procEntry.AttributesMask = 0; - if (spellInfo->ProcFlags & PROC_FLAG_KILL) - procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR; - if (addTriggerFlag) - procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC; - - procEntry.ProcsPerMinute = 0; - procEntry.Chance = spellInfo->ProcChance; - procEntry.Cooldown = Milliseconds::zero(); - procEntry.Charges = spellInfo->ProcCharges; - - mSpellProcMap[spellInfo->Id] = procEntry; - ++count; - } - - LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SpellMgr::LoadSpellBonuses() diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index c1bfb1d5f..d02342f11 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -154,15 +154,13 @@ enum ProcFlags | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS, SPELL_PROC_FLAG_MASK = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS - | PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS - | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG - | PROC_FLAG_DONE_TRAP_ACTIVATION, + | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, - SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION, + SPELL_CAST_PROC_FLAG_MASK = SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION | RANGED_PROC_FLAG_MASK, PERIODIC_PROC_FLAG_MASK = PROC_FLAG_DONE_PERIODIC | PROC_FLAG_TAKEN_PERIODIC, @@ -170,8 +168,7 @@ enum ProcFlags | PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG - | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_TRAP_ACTIVATION - | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK, + | PROC_FLAG_DONE_PERIODIC | PROC_FLAG_DONE_MAINHAND_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK, TAKEN_HIT_PROC_FLAG_MASK = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS @@ -191,6 +188,46 @@ enum ProcFlags PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS) +enum ProcFlagsExLegacy +{ + PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag) + PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells) + PROC_EX_CRITICAL_HIT = 0x0000002, + PROC_EX_MISS = 0x0000004, + PROC_EX_RESIST = 0x0000008, + PROC_EX_DODGE = 0x0000010, + PROC_EX_PARRY = 0x0000020, + PROC_EX_BLOCK = 0x0000040, + PROC_EX_EVADE = 0x0000080, + PROC_EX_IMMUNE = 0x0000100, + PROC_EX_DEFLECT = 0x0000200, + PROC_EX_ABSORB = 0x0000400, + PROC_EX_REFLECT = 0x0000800, + PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) + PROC_EX_FULL_BLOCK = 0x0002000, // block all attack damage + PROC_EX_RESERVED2 = 0x0004000, + PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc + PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result + PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet) + PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc + PROC_EX_NO_OVERHEAL = 0x0080000, // Proc if heal did some work + PROC_EX_NO_AURA_REFRESH = 0x0100000, // Proc if aura was not refreshed + PROC_EX_ONLY_FIRST_TICK = 0x0200000, // Proc only on first tick (in case of periodic spells) + + // Flags for internal use - do not use these in db! + PROC_EX_INTERNAL_CANT_PROC = 0x0800000, + PROC_EX_INTERNAL_DOT = 0x1000000, + PROC_EX_INTERNAL_HOT = 0x2000000, + PROC_EX_INTERNAL_TRIGGERED = 0x4000000, + PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 +}; + +#define AURA_SPELL_PROC_EX_MASK \ + (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \ + PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \ + PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \ + PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT) + enum ProcFlagsSpellType { PROC_SPELL_TYPE_NONE = 0x0000000, @@ -224,37 +261,45 @@ enum ProcFlagsHit PROC_HIT_DEFLECT = 0x0000200, PROC_HIT_ABSORB = 0x0000400, // partial or full absorb PROC_HIT_REFLECT = 0x0000800, - PROC_HIT_INTERRUPT = 0x0001000, + PROC_HIT_INTERRUPT = 0x0001000, // (not used atm) PROC_HIT_FULL_BLOCK = 0x0002000, - PROC_HIT_MASK_ALL = 0x0002FFF, + PROC_HIT_MASK_ALL = 0x2FFF, }; enum ProcAttributes { - PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc - PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells - PROC_ATTR_REQ_MANA_COST = 0x0000004, // requires triggering spell to have a mana cost for aura proc - PROC_ATTR_REQ_SPELLMOD = 0x0000008, // requires triggering spell to be affected by proccing aura to drop charges - - PROC_ATTR_DISABLE_EFF_0 = 0x0000010, // explicitly disables aura proc from effects, USE ONLY IF 100% SURE AURA SHOULDN'T PROC - PROC_ATTR_DISABLE_EFF_1 = 0x0000020, // used to avoid a console error if the spell has invalid trigger spell and handled elsewhere - PROC_ATTR_DISABLE_EFF_2 = 0x0000040 // or handling not needed + PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010, }; +struct SpellProcEventEntry +{ + uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2 + uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value + flag96 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do) + uint32 procFlags; // bitmask for matching proc event + uint32 procEx; // proc Extend info (see ProcFlagsEx) + uint32 procPhase; // proc phase (see ProcFlagsSpellPhase) + float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc + float customChance; // Owerride chance (in most cases for debug only) + uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_ +}; + +typedef std::unordered_map SpellProcEventMap; + struct SpellProcEntry { - uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school - uint32 SpellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName - flag96 SpellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags - uint32 ProcFlags; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags - uint32 SpellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType - uint32 SpellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase - uint32 HitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit - uint32 AttributesMask; // bitmask, see ProcAttributes - float ProcsPerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 - float Chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set - Milliseconds Cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura - uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite + uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school + uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName + flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags + uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags + uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType + uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase + uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit + uint32 attributesMask; // bitmask, see ProcAttributes + float ratePerMinute; // if nonzero - chance to proc is equal to value * aura caster's weapon speed / 60 + float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set + uint32 cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura + uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite }; typedef std::unordered_map SpellProcMap; @@ -624,9 +669,13 @@ public: SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const; void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set& availableElixirs) const; + // Spell proc event table + [[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const; + bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, ProcEventInfo const& eventInfo, bool active) const; + // Spell proc table [[nodiscard]] SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; - static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo); + bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; // Spell bonus data table [[nodiscard]] SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; @@ -701,6 +750,7 @@ public: void LoadSpellTargetPositions(); void LoadSpellGroups(); void LoadSpellGroupStackRules(); + void LoadSpellProcEvents(); void LoadSpellProcs(); void LoadSpellBonuses(); void LoadSpellThreats(); @@ -729,6 +779,7 @@ private: SpellTargetPositionMap mSpellTargetPositions; SpellGroupMap mSpellGroupMap; SpellGroupStackMap mSpellGroupStackMap; + SpellProcEventMap mSpellProcEventMap; SpellProcMap mSpellProcMap; SpellBonusMap mSpellBonusMap; SpellThreatMap mSpellThreatMap; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index c44c5460a..4842cede7 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -733,9 +733,6 @@ bool AuraScript::_Validate(SpellInfo const* entry) if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); - for (std::list::iterator itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr) - if (!itr->GetAffectedEffectsMask(entry)) - LOG_ERROR("spells.scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString(), m_scriptName->c_str()); for (std::list::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr) if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); @@ -909,17 +906,6 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e return (auraScript->*_HandlerScript)(eventInfo); } -AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) - : AuraScript::EffectBase(effIndex, effName) -{ - _HandlerScript = handlerScript; -} - -bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) -{ - return (auraScript->*_HandlerScript)(aurEff, eventInfo); -} - AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript) { _HandlerScript = handlerScript; @@ -1181,7 +1167,6 @@ Unit* AuraScript::GetTarget() const case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD: case AURA_SCRIPT_HOOK_EFFECT_SPLIT: case AURA_SCRIPT_HOOK_CHECK_PROC: - case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC: case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC: case AURA_SCRIPT_HOOK_PREPARE_PROC: case AURA_SCRIPT_HOOK_PROC: diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 54b8d009b..b52d2215b 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -499,7 +499,6 @@ enum AuraScriptHookType AURA_SCRIPT_HOOK_AFTER_DISPEL, // Spell Proc Hooks AURA_SCRIPT_HOOK_CHECK_PROC, - AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, AURA_SCRIPT_HOOK_PREPARE_PROC, AURA_SCRIPT_HOOK_PROC, @@ -530,8 +529,7 @@ public: typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const*, SpellModifier* &); \ typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \ typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \ - typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \ - typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \ + typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \ typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \ typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \ @@ -641,14 +639,6 @@ public: private: AuraCheckProcFnType _HandlerScript; }; - class CheckEffectProcHandler : public EffectBase - { - public: - CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName); - bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo); - private: - AuraCheckEffectProcFnType _HandlerScript; - }; class AuraProcHandler { public: @@ -678,9 +668,8 @@ public: class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) {} }; \ - class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \ - class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \ - class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \ + class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \ + class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \ class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) {} }; \ #define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) @@ -822,12 +811,6 @@ public: HookList DoCheckAfterProc; #define AuraCheckProcFn(F) CheckProcHandlerFunction(&F) - // executed when aura effect checks if it can proc the aura - // example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); - // where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo); - HookList DoCheckEffectProc; -#define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N) - // executed before aura procs (possibility to prevent charge drop/cooldown) // example: DoPrepareProc += AuraProcFn(class::function); // where function is: void function (ProcEventInfo& eventInfo); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index abfc1078f..a178af405 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1663,7 +1663,10 @@ void World::SetInitialWorldSettings() LOG_INFO("server.loading", "Loading Spell Learn Skills..."); sSpellMgr->LoadSpellLearnSkills(); // must be after LoadSpellRanks - LOG_INFO("server.loading", "Loading Spell Proc conditions and data..."); + LOG_INFO("server.loading", "Loading Spell Proc Event Conditions..."); + sSpellMgr->LoadSpellProcEvents(); + + LOG_INFO("server.loading", "Loading Spell Proc Conditions and Data..."); sSpellMgr->LoadSpellProcs(); LOG_INFO("server.loading", "Loading Spell Bonus Data..."); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 948e18956..2fee7b3b6 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -154,6 +154,7 @@ public: { "spell_loot_template", HandleReloadLootTemplatesSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_linked_spell", HandleReloadSpellLinkedSpellCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_pet_auras", HandleReloadSpellPetAurasCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "spell_proc_event", HandleReloadSpellProcEventCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_proc", HandleReloadSpellProcsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_scripts", HandleReloadSpellScriptsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "spell_target_position", HandleReloadSpellTargetPositionCommand, SEC_ADMINISTRATOR, Console::Yes }, @@ -295,6 +296,7 @@ public: HandleReloadSpellAreaCommand(handler); HandleReloadSpellGroupsCommand(handler); HandleReloadSpellLinkedSpellCommand(handler); + HandleReloadSpellProcEventCommand(handler); HandleReloadSpellProcsCommand(handler); HandleReloadSpellBonusesCommand(handler); HandleReloadSpellTargetPositionCommand(handler); @@ -851,6 +853,14 @@ public: return true; } + static bool HandleReloadSpellProcEventCommand(ChatHandler* handler) + { + LOG_INFO("server.loading", "Re-Loading Spell Proc Event conditions..."); + sSpellMgr->LoadSpellProcEvents(); + handler->SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded."); + return true; + } + static bool HandleReloadSpellProcsCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Re-Loading Spell Proc conditions and data..."); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp index 55088fa48..a87452598 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp @@ -17,19 +17,17 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "SpellScript.h" #include "hyjal.h" #include "hyjal_trash.h" enum Spells { - SPELL_CARRION_SWARM = 31306, - SPELL_SLEEP = 31298, - SPELL_VAMPIRIC_AURA = 38196, - SPELL_VAMPIRIC_AURA_HEAL = 31285, - SPELL_INFERNO = 31299, - SPELL_IMMOLATION = 31303, - SPELL_INFERNO_EFFECT = 31302 + SPELL_CARRION_SWARM = 31306, + SPELL_SLEEP = 31298, + SPELL_VAMPIRIC_AURA = 38196, + SPELL_INFERNO = 31299, + SPELL_IMMOLATION = 31303, + SPELL_INFERNO_EFFECT = 31302, }; enum Texts @@ -267,48 +265,8 @@ public: }; }; -class spell_anetheron_vampiric_aura : public SpellScriptLoader -{ -public: - spell_anetheron_vampiric_aura() : SpellScriptLoader("spell_anetheron_vampiric_aura") { } - - class spell_anetheron_vampiric_aura_AuraScript : public AuraScript - { - PrepareAuraScript(spell_anetheron_vampiric_aura_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_VAMPIRIC_AURA_HEAL)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 bp = damageInfo->GetDamage() * 3; - eventInfo.GetActor()->CastCustomSpell(SPELL_VAMPIRIC_AURA_HEAL, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetActor(), true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_anetheron_vampiric_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_anetheron_vampiric_aura_AuraScript(); - } -}; - void AddSC_boss_anetheron() { new boss_anetheron(); new npc_towering_infernal(); - new spell_anetheron_vampiric_aura(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index 0aaf508bd..ec53af7ec 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -857,7 +857,7 @@ public: resilienceReduction = damage - resilienceReduction; damage -= resilienceReduction; uint32 mitigated_damage = resilienceReduction; - DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK, mitigated_damage); + DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, mitigated_damage); Unit::CalcAbsorbResist(dmgInfo); Unit::DealDamageMods(plr, damage, &absorb); int32 overkill = damage - plr->GetHealth(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index d7f428db7..508653c07 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -1589,26 +1589,6 @@ public: { return new spell_taldaram_ball_of_inferno_flame_SpellScript(); } - - class spell_taldaram_ball_of_inferno_flame_AuraScript : public AuraScript - { - PrepareAuraScript(spell_taldaram_ball_of_inferno_flame_AuraScript); - - void HandleStackDrop(ProcEventInfo& /*eventInfo*/) - { - ModStackAmount(-1); - } - - void Register() override - { - OnProc += AuraProcFn(spell_taldaram_ball_of_inferno_flame_AuraScript::HandleStackDrop); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_taldaram_ball_of_inferno_flame_AuraScript(); - } }; class spell_valanar_kinetic_bomb : public SpellScriptLoader diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 24bb93381..86bc01d41 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1061,7 +1061,7 @@ public: { DamageInfo* damageInfo = eventInfo.GetDamageInfo(); SpellInfo const* procSpell = eventInfo.GetSpellInfo(); - return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion + return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && procSpell && procSpell->SpellIconID != 2731; // Xinef: Mark of the Fallen Champion } void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) @@ -1115,7 +1115,7 @@ public: { DamageInfo* damageInfo = eventInfo.GetDamageInfo(); SpellInfo const* procSpell = eventInfo.GetSpellInfo(); - return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_HIT_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion + return eventInfo.GetActor() && eventInfo.GetActionTarget() && ((damageInfo && damageInfo->GetDamage()) || eventInfo.GetHitMask() & PROC_EX_ABSORB) && (!procSpell || procSpell->SpellIconID != 2731); // Xinef: Mark of the Fallen Champion } void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) @@ -1404,41 +1404,6 @@ public: } }; -// 72176 - Blood Beast's Blood Link -class spell_deathbringer_blood_beast_blood_link : public SpellScriptLoader -{ -public: - spell_deathbringer_blood_beast_blood_link() : SpellScriptLoader("spell_deathbringer_blood_beast_blood_link") { } - - class spell_deathbringer_blood_beast_blood_link_AuraScript : public AuraScript - { - PrepareAuraScript(spell_deathbringer_blood_beast_blood_link_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_BLOOD_LINK_DUMMY)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetProcTarget()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 3, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_deathbringer_blood_beast_blood_link_AuraScript(); - } -}; - void AddSC_boss_deathbringer_saurfang() { new boss_deathbringer_saurfang(); @@ -1453,5 +1418,4 @@ void AddSC_boss_deathbringer_saurfang() new spell_deathbringer_boiling_blood(); new achievement_ive_gone_and_made_a_mess(); new npc_icc_blood_beast(); - new spell_deathbringer_blood_beast_blood_link(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 6f8165d53..7e31e8550 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1076,23 +1076,9 @@ public: caster->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, caster, false);*/ } - void HandleProc(ProcEventInfo& eventInfo) - { - uint32 stack = GetStackAmount(); - Unit* caster = eventInfo.GetActor(); - - int32 const mod = caster->GetMap()->Is25ManRaid() ? 1500 : 1250; - int32 dmg = 0; - for (uint8 i = 1; i <= stack; ++i) - dmg += mod * i; - - caster->CastCustomSpell(SPELL_EXPUNGED_GAS, SPELLVALUE_BASE_POINT0, dmg); - } - void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_gaseous_bloat_AuraScript::HandleExtraEffect, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); - OnProc += AuraProcFn(spell_putricide_gaseous_bloat_AuraScript::HandleProc); } }; @@ -1721,45 +1707,6 @@ public: } }; -// 71770 - Ooze Spell Tank Protection -class spell_putricide_ooze_tank_protection : public SpellScriptLoader -{ -public: - spell_putricide_ooze_tank_protection() : SpellScriptLoader("spell_putricide_ooze_tank_protection") { } - - class spell_putricide_ooze_tank_protection_AuraScript : public AuraScript - { - PrepareAuraScript(spell_putricide_ooze_tank_protection_AuraScript); - - bool Validate(SpellInfo const* spellInfo) override - { - if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell) || - !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].TriggerSpell)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* actionTarget = eventInfo.GetActionTarget(); - actionTarget->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - OnEffectProc += AuraEffectProcFn(spell_putricide_ooze_tank_protection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_putricide_ooze_tank_protection_AuraScript(); - } -}; - void AddSC_boss_professor_putricide() { new boss_professor_putricide(); @@ -1784,5 +1731,4 @@ void AddSC_boss_professor_putricide() new spell_putricide_mutated_transformation_dmg(); new spell_putricide_eat_ooze(); new spell_putricide_regurgitated_ooze(); - new spell_putricide_ooze_tank_protection(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 625a96eea..b581decfc 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -952,7 +952,7 @@ public: } else { - me->ModifyHealth(me->CountPctFromMaxHealth(5)); + Unit::DealHeal(me, me, me->CountPctFromMaxHealth(3)); _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); } break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp index d2c74139b..21d21e3d7 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -2987,8 +2987,6 @@ public: void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); if (!damageInfo || !damageInfo->GetDamage()) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp index 3f17f3048..0664944a8 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp @@ -89,57 +89,6 @@ public: }; }; -enum SecondWind -{ - SPELL_SECOND_WIND_TRIGGER = 42771 -}; - -// 42770 - Second Wind -class spell_uk_second_wind : public SpellScriptLoader -{ -public: - spell_uk_second_wind() : SpellScriptLoader("spell_uk_second_wind") { } - - class spell_uk_second_wind_AuraScript : public AuraScript - { - PrepareAuraScript(spell_uk_second_wind_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_SECOND_WIND_TRIGGER)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActionTarget(); - caster->CastSpell(caster, SPELL_SECOND_WIND_TRIGGER, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_uk_second_wind_AuraScript::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_uk_second_wind_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_uk_second_wind_AuraScript(); - } -}; - enum EnslavedProtoDrake { TYPE_PROTODRAKE_AT = 28, @@ -298,5 +247,4 @@ void AddSC_utgarde_keep() new npc_enslaved_proto_drake(); new spell_ticking_time_bomb(); - new spell_uk_second_wind(); } diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp deleted file mode 100644 index 32fbe4d55..000000000 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ScriptMgr.h" -#include "SpellMgr.h" -#include "SpellScript.h" -#include "SpellAuraEffects.h" -#include "Unit.h" - -enum Spells -{ - SPELL_MARK_OF_MALICE_TRIGGERED = 33494 -}; - -// 33493 - Mark of Malice -class spell_mark_of_malice : public AuraScript -{ - PrepareAuraScript(spell_mark_of_malice); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MARK_OF_MALICE_TRIGGERED }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - // just drop charges - if (aurEff->GetBase()->GetCharges() > 1) - return; - - GetTarget()->CastSpell(GetTarget(), SPELL_MARK_OF_MALICE_TRIGGERED, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mark_of_malice::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -void AddSC_shadow_labyrinth() -{ - RegisterSpellScript(spell_mark_of_malice); -} diff --git a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp index 0046dc91d..24145c39b 100644 --- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp +++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp @@ -33,17 +33,16 @@ enum Texts enum Spells { - SPELL_SHADOW_VOLLEY = 32963, - SPELL_CLEAVE = 31779, - SPELL_THUNDERCLAP = 36706, - SPELL_VOID_BOLT = 39329, - SPELL_MARK_OF_KAZZAK = 32960, - SPELL_MARK_OF_KAZZAK_DAMAGE = 32961, - SPELL_ENRAGE = 32964, - SPELL_CAPTURE_SOUL = 32966, - SPELL_TWISTED_REFLECTION = 21063, - SPELL_TWISTED_REFLECTION_HEAL = 21064, - SPELL_BERSERK = 32965, + SPELL_SHADOW_VOLLEY = 32963, + SPELL_CLEAVE = 31779, + SPELL_THUNDERCLAP = 36706, + SPELL_VOID_BOLT = 39329, + SPELL_MARK_OF_KAZZAK = 32960, + SPELL_MARK_OF_KAZZAK_DAMAGE = 32961, + SPELL_ENRAGE = 32964, + SPELL_CAPTURE_SOUL = 32966, + SPELL_TWISTED_REFLECTION = 21063, + SPELL_BERSERK = 32965, }; enum Events @@ -220,47 +219,8 @@ public: } }; -class spell_twisted_reflection : public SpellScriptLoader -{ -public: - spell_twisted_reflection() : SpellScriptLoader("spell_twisted_reflection") { } - - class spell_twisted_reflection_AuraScript : public AuraScript - { - PrepareAuraScript(spell_twisted_reflection_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_TWISTED_REFLECTION_HEAL)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), SPELL_TWISTED_REFLECTION_HEAL, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_twisted_reflection_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_twisted_reflection_AuraScript(); - } -}; - void AddSC_boss_doomlordkazzak() { new boss_doomlord_kazzak(); new spell_mark_of_kazzak(); - new spell_twisted_reflection(); } diff --git a/src/server/scripts/Outland/outland_script_loader.cpp b/src/server/scripts/Outland/outland_script_loader.cpp index 255252585..df02e86d3 100644 --- a/src/server/scripts/Outland/outland_script_loader.cpp +++ b/src/server/scripts/Outland/outland_script_loader.cpp @@ -29,7 +29,6 @@ void AddSC_boss_ambassador_hellmaw(); void AddSC_boss_blackheart_the_inciter(); void AddSC_boss_grandmaster_vorpil(); void AddSC_boss_murmur(); -void AddSC_shadow_labyrinth(); void AddSC_boss_illidan(); //Black Temple void AddSC_boss_shade_of_akama(); void AddSC_boss_supremus(); @@ -123,7 +122,6 @@ void AddOutlandScripts() AddSC_boss_blackheart_the_inciter(); AddSC_boss_grandmaster_vorpil(); AddSC_boss_murmur(); - AddSC_shadow_labyrinth(); AddSC_boss_illidan(); //Black Temple AddSC_boss_shade_of_akama(); AddSC_boss_supremus(); diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index bd380476e..2533462a5 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -21,11 +21,7 @@ */ #include "ScriptMgr.h" -#include "CreatureAIImpl.h" #include "ScriptedCreature.h" -#include "SpellScript.h" -#include "SpellAuraEffects.h" -#include "TemporarySummon.h" enum HunterSpells { @@ -36,26 +32,6 @@ enum HunterSpells SPELL_HUNTER_PET_SCALING = 62915 }; -enum HunterCreatures -{ - NPC_HUNTER_VIPER = 19921 -}; - -enum PetSpellsMisc -{ - SPELL_PET_GUARD_DOG_HAPPINESS = 54445, - SPELL_PET_SILVERBACK_RANK_1 = 62800, - SPELL_PET_SILVERBACK_RANK_2 = 62801, - - SPELL_PET_SWOOP = 52825, - SPELL_PET_CHARGE = 61685, - - PET_ICON_ID_GROWL = 201, - PET_ICON_ID_CLAW = 262, - PET_ICON_ID_BITE = 1680, - PET_ICON_ID_SMACK = 473 -}; - struct npc_pet_hunter_snake_trap : public ScriptedAI { npc_pet_hunter_snake_trap(Creature* creature) : ScriptedAI(creature) { _init = false; } @@ -162,156 +138,7 @@ private: uint32 _spellTimer; }; -// 57627 - Charge -class spell_pet_charge : public AuraScript -{ - PrepareAuraScript(spell_pet_charge); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PET_SWOOP, - SPELL_PET_CHARGE - }); - } - - void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - // Remove +% AP aura - Unit* pet = eventInfo.GetActor(); - Aura* aura = pet->GetAura(SPELL_PET_SWOOP, pet->GetGUID()); - if (!aura) - aura = pet->GetAura(SPELL_PET_CHARGE, pet->GetGUID()); - - if (!aura) - return; - - aura->DropCharge(AURA_REMOVE_BY_EXPIRE); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pet_charge::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -53178 - Guard Dog -class spell_pet_guard_dog : public AuraScript -{ - PrepareAuraScript(spell_pet_guard_dog); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - // Growl shares family flags with other spells - // filter by spellIcon instead - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, true, nullptr, aurEff); - - float addThreat = CalculatePct(eventInfo.GetSpellInfo()->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); - eventInfo.GetProcTarget()->AddThreat(caster, addThreat); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pet_guard_dog::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pet_guard_dog::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -62764 - Silverback -class spell_pet_silverback : public AuraScript -{ - PrepareAuraScript(spell_pet_silverback); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PET_GUARD_DOG_HAPPINESS }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - // Growl shares family flags with other spells - // filter by spellIcon instead - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->SpellIconID != PET_ICON_ID_GROWL) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static uint32 const triggerSpell[2] = { SPELL_PET_SILVERBACK_RANK_1, SPELL_PET_SILVERBACK_RANK_2 }; - - PreventDefaultAction(); - - uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pet_silverback::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pet_silverback::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -61680 - Culling the Herd -class spell_pet_culling_the_herd : public AuraScript -{ - PrepareAuraScript(spell_pet_culling_the_herd); - - bool CheckProc(ProcEventInfo& eventInfo) - { - // Claw, Bite and Smack share FamilyFlags with other spells - // filter by spellIcon instead - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - switch (spellInfo->SpellIconID) - { - case PET_ICON_ID_CLAW: - case PET_ICON_ID_BITE: - case PET_ICON_ID_SMACK: - break; - default: - return false; - } - - return true; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pet_culling_the_herd::CheckProc); - } -}; - void AddSC_hunter_pet_scripts() { RegisterCreatureAI(npc_pet_hunter_snake_trap); - RegisterSpellScript(spell_pet_charge); - RegisterSpellScript(spell_pet_guard_dog); - RegisterSpellScript(spell_pet_silverback); - RegisterSpellScript(spell_pet_culling_the_herd); } diff --git a/src/server/scripts/Pet/pet_priest.cpp b/src/server/scripts/Pet/pet_priest.cpp index 732943444..1f6b2f964 100644 --- a/src/server/scripts/Pet/pet_priest.cpp +++ b/src/server/scripts/Pet/pet_priest.cpp @@ -29,7 +29,7 @@ enum PriestSpells { SPELL_PRIEST_GLYPH_OF_SHADOWFIEND = 58228, - SPELL_PRIEST_SHADOWFIEND_DEATH = 57989, + SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227, SPELL_PRIEST_SHADOWFIEND_DODGE = 8273, SPELL_PRIEST_LIGHTWELL_CHARGES = 59907 }; @@ -67,10 +67,12 @@ struct npc_pet_pri_shadowfiend : public PetAI AttackStart(target); } - void IsSummonedBy(Unit* summoner) override + void JustDied(Unit* /*killer*/) override { - if (summoner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) - DoCastAOE(SPELL_PRIEST_SHADOWFIEND_DEATH); + if (me->IsSummon()) + if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) + if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) + owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true); } }; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 07aee4a41..88ed7bec2 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -33,13 +33,6 @@ enum DeathKnightSpells { - SPELL_DK_ACCLIMATION_HOLY = 50490, - SPELL_DK_ACCLIMATION_FIRE = 50362, - SPELL_DK_ACCLIMATION_FROST = 50485, - SPELL_DK_ACCLIMATION_ARCANE = 50486, - SPELL_DK_ACCLIMATION_SHADOW = 50489, - SPELL_DK_ACCLIMATION_NATURE = 50488, - SPELL_DK_ADVANTAGE_T10_4P_MELEE = 70657, SPELL_DK_DEATH_AND_DECAY_TRIGGER = 52212, SPELL_DK_GLYPH_OF_SCOURGE_STRIKE = 58642, SPELL_DK_WANDERING_PLAGUE_TRIGGER = 50526, @@ -66,7 +59,6 @@ enum DeathKnightSpells SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365, SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_R1 = 50391, - SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL = 50475, SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED = 63611, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622, SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962, @@ -80,23 +72,7 @@ enum DeathKnightSpells SPELL_DK_UNHOLY_PRESENCE = 48265, SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772, SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, - SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, - SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT = 69961, - SPELL_DK_BUTCHERY_RUNIC_POWER = 50163, - SPELL_DK_MARK_OF_BLOOD_HEAL = 61607, - SPELL_DK_UNHOLY_BLIGHT_DAMAGE = 50536, - SPELL_DK_GLYPH_OF_UNHOLY_BLIGHT = 63332, - SPELL_DK_VENDETTA_HEAL = 50181, - SPELL_DK_NECROSIS_DAMAGE = 51460, - SPELL_DK_OBLITERATE_OFF_HAND_R1 = 66198, - SPELL_DK_FROST_STRIKE_OFF_HAND_R1 = 66196, - SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1 = 66216, - SPELL_DK_DEATH_STRIKE_OFF_HAND_R1 = 66188, - SPELL_DK_RUNE_STRIKE_OFF_HAND_R1 = 66217, - SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 = 66215, - SPELL_DK_RUNIC_RETURN = 61258, - SPELL_DK_WANDERING_PLAGUE_DAMAGE = 50526, - SPELL_DK_DEATH_COIL_R1 = 47541, + SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284 }; enum DeathKnightSpellIcons @@ -106,130 +82,7 @@ enum DeathKnightSpellIcons enum Misc { - NPC_DK_GHOUL = 26125, - NPC_DK_DANCING_RUNE_WEAPON = 27893, - SPELL_CATEGORY_HOWLING_BLAST = 1248 -}; - -// -49200 - Acclimation -class spell_dk_acclimation : public AuraScript -{ - PrepareAuraScript(spell_dk_acclimation); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_HOLY) || - !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FIRE) || - !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_FROST) || - !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_NATURE) || - !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_SHADOW) || - !sSpellMgr->GetSpellInfo(SPELL_DK_ACCLIMATION_ARCANE)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetDamageInfo()) - { - switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) - { - case SPELL_SCHOOL_HOLY: - case SPELL_SCHOOL_FIRE: - case SPELL_SCHOOL_NATURE: - case SPELL_SCHOOL_FROST: - case SPELL_SCHOOL_SHADOW: - case SPELL_SCHOOL_ARCANE: - return true; - default: - break; - } - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - uint32 triggerspell = 0; - - switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) - { - case SPELL_SCHOOL_HOLY: - triggerspell = SPELL_DK_ACCLIMATION_HOLY; - break; - case SPELL_SCHOOL_FIRE: - triggerspell = SPELL_DK_ACCLIMATION_FIRE; - break; - case SPELL_SCHOOL_NATURE: - triggerspell = SPELL_DK_ACCLIMATION_NATURE; - break; - case SPELL_SCHOOL_FROST: - triggerspell = SPELL_DK_ACCLIMATION_FROST; - break; - case SPELL_SCHOOL_SHADOW: - triggerspell = SPELL_DK_ACCLIMATION_SHADOW; - break; - case SPELL_SCHOOL_ARCANE: - triggerspell = SPELL_DK_ACCLIMATION_ARCANE; - break; - default: - return; - } - - if (Unit* target = eventInfo.GetActionTarget()) - { - target->CastSpell(target, triggerspell, true, nullptr, aurEff); - } - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dk_acclimation::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dk_acclimation::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 70656 - Advantage (T10 4P Melee Bonus) -class spell_dk_advantage_t10_4p : public AuraScript -{ - PrepareAuraScript(spell_dk_advantage_t10_4p); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_ADVANTAGE_T10_4P_MELEE)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (Unit* caster = eventInfo.GetActor()) - { - if (caster->GetTypeId() != TYPEID_PLAYER || caster->getClass() != CLASS_DEATH_KNIGHT) - { - return false; - } - - for (uint8 i = 0; i < MAX_RUNES; ++i) - { - if (caster->ToPlayer()->GetRuneCooldown(i) == 0) - { - return false; - } - } - - return true; - } - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dk_advantage_t10_4p::CheckProc); - } + NPC_DK_GHOUL = 26125 }; // 50526 - Wandering Plague @@ -585,38 +438,19 @@ class spell_dk_summon_gargoyle : public SpellScript } }; -// 63611 - Improved Blood Presence Triggered +// 63611 - Improved Blood Presence class spell_dk_improved_blood_presence_proc : public AuraScript { PrepareAuraScript(spell_dk_improved_blood_presence_proc); - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL)) - return false; - return true; - } - bool CheckProc(ProcEventInfo& eventInfo) { - if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER) - return true; - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo()) - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_IMPROVED_BLOOD_PRESENCE_HEAL, SPELLVALUE_BASE_POINT0, CalculatePct(int32(dmgInfo->GetDamage()), aurEff->GetAmount()), - eventInfo.GetActor(), true, nullptr, aurEff); + return eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage(); } void Register() override { DoCheckProc += AuraCheckProcFn(spell_dk_improved_blood_presence_proc::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dk_improved_blood_presence_proc::HandleProc, EFFECT_1, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -643,7 +477,7 @@ class spell_dk_wandering_plague_aura : public AuraScript PreventDefaultAction(); eventInfo.GetActor()->AddSpellCooldown(SPELL_DK_WANDERING_PLAGUE_TRIGGER, 0, 1000); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_TRIGGER, SPELLVALUE_BASE_POINT0, CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), eventInfo.GetActionTarget(), TRIGGERED_FULL_MASK, nullptr, aurEff); + eventInfo.GetActor()->CastCustomSpell(SPELL_DK_WANDERING_PLAGUE_TRIGGER, SPELLVALUE_BASE_POINT0, CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), eventInfo.GetActionTarget(), TRIGGERED_FULL_MASK); } void Register() override @@ -859,7 +693,7 @@ class spell_dk_scent_of_blood_trigger : public AuraScript bool CheckProc(ProcEventInfo& eventInfo) { - return (eventInfo.GetHitMask() & (PROC_HIT_DODGE | PROC_HIT_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage()); + return (eventInfo.GetHitMask() & (PROC_EX_DODGE | PROC_EX_PARRY)) || (eventInfo.GetDamageInfo() && eventInfo.GetDamageInfo()->GetDamage()); } void Register() override @@ -2301,287 +2135,8 @@ class spell_dk_will_of_the_necropolis : public AuraScript } }; -// -49182 - Blade Barrier -class spell_dk_blade_barrier : public AuraScript -{ - PrepareAuraScript(spell_dk_blade_barrier); - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetSpellInfo() != nullptr) - if (Player* player = eventInfo.GetActor()->ToPlayer()) - if (player->getClass() == CLASS_DEATH_KNIGHT && player->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD)) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dk_blade_barrier::CheckProc); - } -}; - -// -48979 - Butchery -class spell_dk_butchery : public AuraScript -{ - PrepareAuraScript(spell_dk_butchery); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_BUTCHERY_RUNIC_POWER }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_BUTCHERY_RUNIC_POWER, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_butchery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 58642 - Glyph of Scourge Strike -class spell_dk_glyph_of_scourge_strike : public AuraScript -{ - PrepareAuraScript(spell_dk_glyph_of_scourge_strike); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_GLYPH_OF_SCOURGE_STRIKE_SCRIPT, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_glyph_of_scourge_strike::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 61257 - Runic Power Back on Snare/Root -class spell_dk_pvp_4p_bonus : public AuraScript -{ - PrepareAuraScript(spell_dk_pvp_4p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_RUNIC_RETURN }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_SNARE))) != 0; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActionTarget()->CastSpell((Unit*)nullptr, SPELL_DK_RUNIC_RETURN, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dk_pvp_4p_bonus::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dk_pvp_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 49005 - Mark of Blood -class spell_dk_mark_of_blood : public AuraScript -{ - PrepareAuraScript(spell_dk_mark_of_blood); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_MARK_OF_BLOOD_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DK_MARK_OF_BLOOD_HEAL, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_mark_of_blood::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -51459 - Necrosis -class spell_dk_necrosis : public AuraScript -{ - PrepareAuraScript(spell_dk_necrosis); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_NECROSIS_DAMAGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DK_NECROSIS_DAMAGE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_necrosis::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -49018 - Sudden Doom -class spell_dk_sudden_doom : public AuraScript -{ - PrepareAuraScript(spell_dk_sudden_doom); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_DEATH_COIL_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DK_DEATH_COIL_R1); - uint32 spellId = 0; - - while (spellInfo) - { - if (!caster->HasSpell(spellInfo->Id)) - break; - - spellId = spellInfo->Id; - spellInfo = spellInfo->GetNextRankSpell(); - } - - if (!spellId) - return; - - caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_sudden_doom::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -65661 Threat of Thassarian -class spell_dk_threat_of_thassarian : public AuraScript -{ - PrepareAuraScript(spell_dk_threat_of_thassarian); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DK_OBLITERATE_OFF_HAND_R1, - SPELL_DK_FROST_STRIKE_OFF_HAND_R1, - SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1, - SPELL_DK_DEATH_STRIKE_OFF_HAND_R1, - SPELL_DK_RUNE_STRIKE_OFF_HAND_R1, - SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1 - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - if (!roll_chance_i(aurEff->GetAmount())) - return; - - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - // Must dual wield - Unit* caster = eventInfo.GetActor(); - if (!caster->haveOffhandWeapon()) - return; - - uint32 spellId = 0; - // Plague Strike - if (spellInfo->SpellFamilyFlags[0] & 0x00000001) - spellId = SPELL_DK_PLAGUE_STRIKE_OFF_HAND_R1; - // Death Strike - else if (spellInfo->SpellFamilyFlags[0] & 0x00000010) - spellId = SPELL_DK_DEATH_STRIKE_OFF_HAND_R1; - // Blood Strike - else if (spellInfo->SpellFamilyFlags[0] & 0x00400000) - spellId = SPELL_DK_BLOOD_STRIKE_OFF_HAND_R1; - // Frost Strike - else if (spellInfo->SpellFamilyFlags[1] & 0x00000004) - spellId = SPELL_DK_FROST_STRIKE_OFF_HAND_R1; - // Obliterate - else if (spellInfo->SpellFamilyFlags[1] & 0x00020000) - spellId = SPELL_DK_OBLITERATE_OFF_HAND_R1; - // Rune Strike - else if (spellInfo->SpellFamilyFlags[1] & 0x20000000) - spellId = SPELL_DK_RUNE_STRIKE_OFF_HAND_R1; - - if (!spellId) - return; - - spellId = sSpellMgr->GetSpellWithRank(spellId, spellInfo->GetRank()); - caster->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_threat_of_thassarian::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -49015 - Vendetta -class spell_dk_vendetta : public AuraScript -{ - PrepareAuraScript(spell_dk_vendetta); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DK_VENDETTA_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DK_VENDETTA_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dk_vendetta::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - void AddSC_deathknight_spell_scripts() { - RegisterSpellScript(spell_dk_acclimation); - RegisterSpellScript(spell_dk_advantage_t10_4p); RegisterSpellScript(spell_dk_wandering_plague); RegisterSpellScript(spell_dk_raise_ally); RegisterSpellScript(spell_dk_raise_ally_trigger); @@ -2626,13 +2181,4 @@ void AddSC_deathknight_spell_scripts() RegisterSpellScript(spell_dk_spell_deflection); RegisterSpellScript(spell_dk_vampiric_blood); RegisterSpellScript(spell_dk_will_of_the_necropolis); - RegisterSpellScript(spell_dk_blade_barrier); - RegisterSpellScript(spell_dk_butchery); - RegisterSpellScript(spell_dk_glyph_of_scourge_strike); - RegisterSpellScript(spell_dk_pvp_4p_bonus); - RegisterSpellScript(spell_dk_mark_of_blood); - RegisterSpellScript(spell_dk_necrosis); - RegisterSpellScript(spell_dk_sudden_doom); - RegisterSpellScript(spell_dk_threat_of_thassarian); - RegisterSpellScript(spell_dk_vendetta); } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 0811fa9e5..d7f697a33 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -55,45 +55,12 @@ enum DruidSpells SPELL_DRUID_SURVIVAL_INSTINCTS = 50322, SPELL_DRUID_SAVAGE_ROAR = 62071, SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178, - SPELL_DRUID_T9_FERAL_RELIC_BEAR = 67354, - SPELL_DRUID_T9_FERAL_RELIC_CAT = 67355, SPELL_DRUID_ITEM_T8_BALANCE_RELIC = 64950, SPELL_DRUID_BEAR_FORM_PASSIVE = 1178, SPELL_DRUID_DIRE_BEAR_FORM_PASSIVE = 9635, - SPELL_DRUID_FORMS_TRINKET_BEAR = 37340, - SPELL_DRUID_FORMS_TRINKET_CAT = 37341, - SPELL_DRUID_FORMS_TRINKET_MOONKIN = 37343, - SPELL_DRUID_FORMS_TRINKET_NONE = 37344, - SPELL_DRUID_FORMS_TRINKET_TREE = 37342, SPELL_DRUID_ENRAGE = 5229, SPELL_DRUID_ENRAGED_DEFENSE = 70725, SPELL_DRUID_ITEM_T10_FERAL_4P_BONUS = 70726, - SPELL_DRUID_T3_PROC_ENERGIZE_MANA = 28722, - SPELL_DRUID_T3_PROC_ENERGIZE_RAGE = 28723, - SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY = 28724, - SPELL_DRUID_BLESSING_OF_THE_CLAW = 28750, - SPELL_DRUID_REVITALIZE_ENERGIZE_MANA = 48542, - SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE = 48541, - SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY = 48540, - SPELL_DRUID_REVITALIZE_ENERGIZE_RP = 48543, - SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN = 54833, - SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT = 54846, - SPELL_DRUID_GLYPH_OF_RIP = 54818, - SPELL_DRUID_RIP_DURATION_LACERATE_DMG = 60141, - SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED = 54820, - SPELL_DRUID_IMP_LEADER_OF_THE_PACK_R1 = 34297, - SPELL_DRUID_IMP_LEADER_OF_THE_PACK_HEAL = 34299, - SPELL_DRUID_IMP_LEADER_OF_THE_PACK_MANA = 68285, - SPELL_DRUID_EXHILARATE = 28742, - SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL = 54755, - SPELL_DRUID_INFUSION = 37238, - SPELL_DRUID_BLESSING_OF_REMULOS = 40445, - SPELL_DRUID_BLESSING_OF_ELUNE = 40446, - SPELL_DRUID_BLESSING_OF_CENARIUS = 40452, - SPELL_DRUID_LANGUISH = 71023, - SPELL_DRUID_REJUVENATION_T10_PROC = 70691, - SPELL_DRUID_BALANCE_T10_BONUS = 70718, - SPELL_DRUID_BALANCE_T10_BONUS_PROC = 70721 }; // 1178 - Bear Form (Passive) @@ -272,7 +239,7 @@ class spell_dru_brambles_treant : public AuraScript { int32 amount = 0; if (player->HasAura(SPELL_DRUID_BARKSKIN, player->GetGUID())) - player->ApplySpellMod(SPELL_DRUID_BARKSKIN, amount); + player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount); return roll_chance_i(amount); } @@ -287,7 +254,7 @@ class spell_dru_brambles_treant : public AuraScript if (GetUnitOwner()->IsSummon()) if (Unit* owner = GetUnitOwner()->ToTempSummon()->GetSummonerUnit()) if (Player* player = owner->GetSpellModOwner()) - player->ApplySpellMod(SPELL_DRUID_BARKSKIN, amount); + player->ApplySpellMod(SPELL_DRUID_BARKSKIN, SPELLMOD_CHANCE_OF_SUCCESS, amount); } void Register() override @@ -478,80 +445,6 @@ class spell_dru_enrage : public AuraScript } }; -// 37336 - Druid Forms Trinket -class spell_dru_forms_trinket : public AuraScript -{ - PrepareAuraScript(spell_dru_forms_trinket); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_BEAR) || - !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_CAT) || - !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_MOONKIN) || - !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_NONE) || - !sSpellMgr->GetSpellInfo(SPELL_DRUID_FORMS_TRINKET_TREE)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - Unit* target = eventInfo.GetActor(); - - switch (target->GetShapeshiftForm()) - { - case FORM_BEAR: - case FORM_DIREBEAR: - case FORM_CAT: - case FORM_MOONKIN: - case FORM_NONE: - case FORM_TREE: - return true; - default: - break; - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* target = eventInfo.GetActor(); - uint32 triggerspell = 0; - - switch (target->GetShapeshiftForm()) - { - case FORM_BEAR: - case FORM_DIREBEAR: - triggerspell = SPELL_DRUID_FORMS_TRINKET_BEAR; - break; - case FORM_CAT: - triggerspell = SPELL_DRUID_FORMS_TRINKET_CAT; - break; - case FORM_MOONKIN: - triggerspell = SPELL_DRUID_FORMS_TRINKET_MOONKIN; - break; - case FORM_NONE: - triggerspell = SPELL_DRUID_FORMS_TRINKET_NONE; - break; - case FORM_TREE: - triggerspell = SPELL_DRUID_FORMS_TRINKET_TREE; - break; - default: - return; - } - - target->CastSpell(target, triggerspell, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_forms_trinket::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_forms_trinket::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 54846 - Glyph of Starfire class spell_dru_glyph_of_starfire : public SpellScript { @@ -904,27 +797,35 @@ class spell_dru_rip : public AuraScript } }; -// 62600 - Savage Defense +// 62606 - Savage Defense class spell_dru_savage_defense : public AuraScript { PrepareAuraScript(spell_dru_savage_defense); - bool Validate(SpellInfo const* spellInfo) override + uint32 absorbPct; + + bool Load() override { - return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); + absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); + return true; } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - int32 amount = static_cast(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), aurEff->GetAmount())); - caster->CastCustomSpell(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect* aurEff, DamageInfo& /*dmgInfo*/, uint32& absorbAmount) + { + absorbAmount = uint32(CalculatePct(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct)); + aurEff->SetAmount(0); } void Register() override { - OnEffectProc += AuraEffectProcFn(spell_dru_savage_defense::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_savage_defense::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dru_savage_defense::Absorb, EFFECT_0); } }; @@ -1059,7 +960,7 @@ class spell_dru_survival_instincts_aura : public AuraScript { Unit* target = GetTarget(); int32 bp0 = target->CountPctFromMaxHealth(aurEff->GetAmount()); - target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true, nullptr, aurEff); + target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, nullptr, nullptr, true); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -1132,66 +1033,6 @@ class spell_dru_typhoon : public SpellScript } }; -// 67353 - T9 Feral Relic (Idol of Mutilation) -class spell_dru_t9_feral_relic : public AuraScript -{ - PrepareAuraScript(spell_dru_t9_feral_relic); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_BEAR) || - !sSpellMgr->GetSpellInfo(SPELL_DRUID_T9_FERAL_RELIC_CAT)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - Unit* target = eventInfo.GetActor(); - - switch (target->GetShapeshiftForm()) - { - case FORM_BEAR: - case FORM_DIREBEAR: - case FORM_CAT: - return true; - default: - break; - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - uint32 triggerspell = 0; - - Unit* target = eventInfo.GetActor(); - - switch (target->GetShapeshiftForm()) - { - case FORM_BEAR: - case FORM_DIREBEAR: - triggerspell = SPELL_DRUID_T9_FERAL_RELIC_BEAR; - break; - case FORM_CAT: - triggerspell = SPELL_DRUID_T9_FERAL_RELIC_CAT; - break; - default: - return; - } - - target->CastSpell(target, triggerspell, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_t9_feral_relic::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_t9_feral_relic::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 70691 - Rejuvenation class spell_dru_t10_restoration_4p_bonus : public SpellScript { @@ -1309,441 +1150,6 @@ class spell_dru_berserk : public SpellScript } }; -// 54832 - Glyph of Innervate -class spell_dru_glyph_of_innervate : public AuraScript -{ - PrepareAuraScript(spell_dru_glyph_of_innervate); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN); - int32 amount = CalculatePct(static_cast(caster->GetCreatePowers(POWER_MANA)), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(); - - caster->CastCustomSpell(SPELL_DRUID_GLYPH_OF_INNERVATE_REGEN, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_innervate::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 54821 - Glyph of Rake -class spell_dru_glyph_of_rake : public AuraScript -{ - PrepareAuraScript(spell_dru_glyph_of_rake); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetProcTarget()->GetTypeId() == TYPEID_UNIT; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_RAKE_TRIGGERED, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rake::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rake::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 54754 - Glyph of Rejuvenation -class spell_dru_glyph_of_rejuvenation : public AuraScript -{ - PrepareAuraScript(spell_dru_glyph_of_rejuvenation); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetProcTarget()->HealthBelowPct(50); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_GLYPH_OF_REJUVENATION_HEAL, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_glyph_of_rejuvenation::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_rejuvenation::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 54815 - Glyph of Shred -class spell_dru_glyph_of_shred : public AuraScript -{ - PrepareAuraScript(spell_dru_glyph_of_shred); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DRUID_GLYPH_OF_RIP, - SPELL_DRUID_RIP_DURATION_LACERATE_DMG - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - // try to find spell Rip on the target - if (AuraEffect const* rip = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, caster->GetGUID())) - { - // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip - uint32 countMin = rip->GetBase()->GetMaxDuration(); - - // just Rip's max duration without other spells - uint32 countMax = rip->GetSpellInfo()->GetMaxDuration(); - - // add possible auras' and Glyph of Shred's max duration - countMax += 3 * aurEff->GetAmount() * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds - countMax += caster->HasAura(SPELL_DRUID_GLYPH_OF_RIP) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds - countMax += caster->HasAura(SPELL_DRUID_RIP_DURATION_LACERATE_DMG) ? 4 * IN_MILLISECONDS : 0; // T7 set bonus -> +4 seconds - - // if min < max -> that means caster didn't cast 3 shred yet - // so set Rip's duration and max duration - if (countMin < countMax) - { - rip->GetBase()->SetDuration(rip->GetBase()->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS); - rip->GetBase()->SetMaxDuration(countMin + aurEff->GetAmount() * IN_MILLISECONDS); - } - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_shred::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 54845 - Glyph of Starfire -class spell_dru_glyph_of_starfire_dummy : public AuraScript -{ - PrepareAuraScript(spell_dru_glyph_of_starfire_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_GLYPH_OF_STARFIRE_SCRIPT, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_glyph_of_starfire_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -48539 - Revitalize -class spell_dru_revitalize : public AuraScript -{ - PrepareAuraScript(spell_dru_revitalize); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DRUID_REVITALIZE_ENERGIZE_MANA, - SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE, - SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY, - SPELL_DRUID_REVITALIZE_ENERGIZE_RP - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (!roll_chance_i(aurEff->GetAmount())) - return; - - Unit* target = eventInfo.GetProcTarget(); - uint32 spellId; - - switch (target->getPowerType()) - { - case POWER_MANA: - spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_MANA; - break; - case POWER_RAGE: - spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RAGE; - break; - case POWER_ENERGY: - spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_ENERGY; - break; - case POWER_RUNIC_POWER: - spellId = SPELL_DRUID_REVITALIZE_ENERGIZE_RP; - break; - default: - return; - } - - eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_revitalize::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - } -}; - -// 28716 - Rejuvenation -class spell_dru_t3_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_dru_t3_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DRUID_T3_PROC_ENERGIZE_MANA, - SPELL_DRUID_T3_PROC_ENERGIZE_RAGE, - SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY - }); - } - - bool CheckProc(ProcEventInfo& /*eventInfo*/) - { - if (!roll_chance_i(50)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* target = eventInfo.GetProcTarget(); - uint32 spellId; - - switch (target->getPowerType()) - { - case POWER_MANA: - spellId = SPELL_DRUID_T3_PROC_ENERGIZE_MANA; - break; - case POWER_RAGE: - spellId = SPELL_DRUID_T3_PROC_ENERGIZE_RAGE; - break; - case POWER_ENERGY: - spellId = SPELL_DRUID_T3_PROC_ENERGIZE_ENERGY; - break; - default: - return; - } - - eventInfo.GetActor()->CastSpell(target, spellId, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_t3_2p_bonus::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_t3_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - } -}; - -// 28744 - Regrowth -class spell_dru_t3_6p_bonus : public AuraScript -{ - PrepareAuraScript(spell_dru_t3_6p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_BLESSING_OF_THE_CLAW }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_DRUID_BLESSING_OF_THE_CLAW, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - } -}; - -// 28719 - Healing Touch -class spell_dru_t3_8p_bonus : public AuraScript -{ - PrepareAuraScript(spell_dru_t3_8p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_EXHILARATE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - Unit* caster = eventInfo.GetActor(); - int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_DRUID_EXHILARATE, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_t3_8p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 37288 - Mana Restore -// 37295 - Mana Restore -class spell_dru_t4_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_dru_t4_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_INFUSION }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DRUID_INFUSION, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 40442 - Druid Tier 6 Trinket -class spell_dru_item_t6_trinket : public AuraScript -{ - PrepareAuraScript(spell_dru_item_t6_trinket); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DRUID_BLESSING_OF_REMULOS, - SPELL_DRUID_BLESSING_OF_ELUNE, - SPELL_DRUID_BLESSING_OF_CENARIUS - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - uint32 spellId; - int32 chance; - - // Starfire - if (spellInfo->SpellFamilyFlags[0] & 0x00000004) - { - spellId = SPELL_DRUID_BLESSING_OF_REMULOS; - chance = 25; - } - // Rejuvenation - else if (spellInfo->SpellFamilyFlags[0] & 0x00000010) - { - spellId = SPELL_DRUID_BLESSING_OF_ELUNE; - chance = 25; - } - // Mangle (Bear) and Mangle (Cat) - else if (spellInfo->SpellFamilyFlags[1] & 0x00000440) - { - spellId = SPELL_DRUID_BLESSING_OF_CENARIUS; - chance = 40; - } else - return; - - if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_dru_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 70664 - Druid T10 Restoration 4P Bonus (Rejuvenation) -class spell_dru_t10_restoration_4p_bonus_dummy : public AuraScript -{ - PrepareAuraScript(spell_dru_t10_restoration_4p_bonus_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DRUID_REJUVENATION_T10_PROC }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->Id == SPELL_DRUID_REJUVENATION_T10_PROC) - return false; - - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return false; - - Player* caster = eventInfo.GetActor()->ToPlayer(); - if (!caster) - return false; - - return caster->GetGroup() || caster != eventInfo.GetProcTarget(); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - int32 amount = static_cast(eventInfo.GetHealInfo()->GetHeal()); - eventInfo.GetActor()->CastCustomSpell(SPELL_DRUID_REJUVENATION_T10_PROC, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_dru_t10_restoration_4p_bonus_dummy::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_dru_t10_restoration_4p_bonus_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 24905 - Moonkin Form (Passive) class spell_dru_moonkin_form_passive_proc : public AuraScript { @@ -1778,7 +1184,6 @@ void AddSC_druid_spell_scripts() RegisterSpellScript(spell_dru_berserk); RegisterSpellScript(spell_dru_dash); RegisterSpellScript(spell_dru_enrage); - RegisterSpellScript(spell_dru_forms_trinket); RegisterSpellScript(spell_dru_glyph_of_starfire); RegisterSpellScript(spell_dru_idol_lifebloom); RegisterSpellScript(spell_dru_innervate); @@ -1799,20 +1204,7 @@ void AddSC_druid_spell_scripts() RegisterSpellScript(spell_dru_swift_flight_passive); RegisterSpellScript(spell_dru_tiger_s_fury); RegisterSpellScript(spell_dru_typhoon); - RegisterSpellScript(spell_dru_t9_feral_relic); RegisterSpellScript(spell_dru_t10_restoration_4p_bonus); RegisterSpellScript(spell_dru_wild_growth); - RegisterSpellScript(spell_dru_glyph_of_innervate); - RegisterSpellScript(spell_dru_glyph_of_rake); - RegisterSpellScript(spell_dru_glyph_of_rejuvenation); - RegisterSpellScript(spell_dru_glyph_of_shred); - RegisterSpellScript(spell_dru_glyph_of_starfire_dummy); - RegisterSpellScript(spell_dru_revitalize); - RegisterSpellScript(spell_dru_t3_2p_bonus); - RegisterSpellScript(spell_dru_t3_6p_bonus); - RegisterSpellScript(spell_dru_t3_8p_bonus); - RegisterSpellScript(spell_dru_t4_2p_bonus); - RegisterSpellScript(spell_dru_item_t6_trinket); - RegisterSpellScript(spell_dru_t10_restoration_4p_bonus_dummy); RegisterSpellScript(spell_dru_moonkin_form_passive_proc); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 019ecf37b..7e16ae4f6 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -848,7 +848,8 @@ class spell_gen_fixate_aura : public AuraScript } }; -// 64440 - Blade Warding +/* 64440 - Blade Warding + 64568 - Blood Reserve */ class spell_gen_proc_above_75 : public AuraScript { PrepareAuraScript(spell_gen_proc_above_75); @@ -3633,53 +3634,6 @@ class spell_gen_bandage : public SpellScript } }; -// Blood Reserve - 64568 -enum BloodReserve -{ - SPELL_GEN_BLOOD_RESERVE_AURA = 64568, - SPELL_GEN_BLOOD_RESERVE_HEAL = 64569 -}; - -class spell_gen_blood_reserve : public AuraScript -{ - PrepareAuraScript(spell_gen_blood_reserve); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_GEN_BLOOD_RESERVE_HEAL)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (Unit* caster = eventInfo.GetActionTarget()) - { - if (caster->HealthBelowPct(35)) - { - return true; - } - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActionTarget(); - caster->CastCustomSpell(SPELL_GEN_BLOOD_RESERVE_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), caster, TRIGGERED_FULL_MASK, nullptr, aurEff); - caster->RemoveAura(SPELL_GEN_BLOOD_RESERVE_AURA); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_gen_blood_reserve::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_gen_blood_reserve::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - enum ParalyticPoison { SPELL_PARALYSIS = 35202 @@ -4540,7 +4494,7 @@ public: return ValidateSpellInfo({ _spellId1, _spellId2 }); } - void HandleProc(AuraEffect* aurEff) + void HandleProc(AuraEffect* /*aurEff*/) { if (Unit* caster = GetCaster()) { @@ -4550,7 +4504,7 @@ public: return; } - caster->CastSpell(GetUnitOwner(), _spellId1, true, nullptr, aurEff); + caster->CastSpell(GetUnitOwner(), _spellId1, true); } } diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index ec0279f8c..bead12996 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -61,25 +61,15 @@ enum HunterSpells SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711, SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED = 54045, - SPELL_HUNTER_PIERCING_SHOTS = 63468, SPELL_HUNTER_READINESS = 23989, SPELL_HUNTER_SNIPER_TRAINING_R1 = 53302, SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 = 64418, - SPELL_HUNTER_T9_4P_GREATNESS = 68130, SPELL_HUNTER_VICIOUS_VIPER = 61609, SPELL_HUNTER_VIPER_ATTACK_SPEED = 60144, SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543, SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389, SPELL_LOCK_AND_LOAD_TRIGGER = 56453, - SPELL_LOCK_AND_LOAD_MARKER = 67544, - SPELL_HUNTER_LOCK_AND_LOAD_TRIGGER = 56453, - SPELL_HUNTER_LOCK_AND_LOAD_MARKER = 67544, - SPELL_HUNTER_KILL_COMMAND_HUNTER = 34027, - SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA = 34720, - SPELL_REPLENISHMENT = 57669, - SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1 = 56654, - SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 = 58882, - SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS = 57894 + SPELL_LOCK_AND_LOAD_MARKER = 67544 }; class spell_hun_check_pet_los : public SpellScript @@ -426,7 +416,7 @@ class spell_hun_ascpect_of_the_viper : public AuraScript } }; -// 53209 - Chimera Shot +// 53209 Chimera Shot class spell_hun_chimera_shot : public SpellScript { PrepareSpellScript(spell_hun_chimera_shot); @@ -443,8 +433,8 @@ class spell_hun_chimera_shot : public SpellScript { uint32 spellId = 0; int32 basePoint = 0; - Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) + Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) { Aura* aura = i->second->GetBase(); if (aura->GetCasterGUID() != caster->GetGUID()) @@ -454,47 +444,53 @@ class spell_hun_chimera_shot : public SpellScript flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags; if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) continue; - if (AuraEffect const* aurEff = aura->GetEffect(EFFECT_0)) + if (AuraEffect* aurEff = aura->GetEffect(0)) { // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. if (familyFlag[0] & 0x4000) { + int32 TickCount = aurEff->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; - - // calculate damage of basic tick (bonuses are already factored in AuraEffect) - basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks(); - ApplyPct(basePoint, 40); + basePoint = aurEff->GetAmount(); + ApplyPct(basePoint, TickCount * 40); + basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); } - // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. + // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. else if (familyFlag[1] & 0x00000080) { + int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER; - // % of mana drained in max duration - basePoint = aurEff->GetAmount() * aurEff->GetTotalTicks(); - - // max value - int32 maxManaReturn = CalculatePct(static_cast(caster->GetMaxPower(POWER_MANA)), basePoint * 2); - ApplyPct(basePoint, unitTarget->GetMaxPower(POWER_MANA)); - if (basePoint > maxManaReturn) - basePoint = maxManaReturn; - - ApplyPct(basePoint, 60); + // Amount of one aura tick + basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount())); + int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; // TODO: Caster uses unitTarget? + if (basePoint > casterBasePoint) + basePoint = casterBasePoint; + ApplyPct(basePoint, TickCount * 60); } - // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. + // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. else if (familyFlag[0] & 0x00008000) + { + if (caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown + { + if (caster->ToPlayer()->HasSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID)) + break; + + caster->ToPlayer()->AddSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID, 0, 60000); + } + spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID; + } // Refresh aura duration aura->RefreshDuration(); + aurEff->ChangeAmount(aurEff->CalculateAmount(caster), false); } break; } if (spellId) - { caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); - } } } @@ -812,49 +808,6 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScript } }; -// -53234 - Piercing Shots -class spell_hun_piercing_shots : public AuraScript -{ - PrepareAuraScript(spell_hun_piercing_shots); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PIERCING_SHOTS)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetActionTarget()) - return true; - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetActionTarget(); - - if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo()) - { - SpellInfo const* piercingShots = sSpellMgr->AssertSpellInfo(SPELL_HUNTER_PIERCING_SHOTS); - uint32 dmg = dmgInfo->GetDamage(); - - uint32 bp = CalculatePct(int32(dmg), aurEff->GetAmount()) / static_cast(piercingShots->GetMaxTicks()); - - caster->CastCustomSpell(SPELL_HUNTER_PIERCING_SHOTS, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); - } - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_hun_piercing_shots::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_hun_piercing_shots::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 54044 - Pet Carrion Feeder class spell_hun_pet_carrion_feeder : public SpellScript { @@ -1055,43 +1008,6 @@ class spell_hun_tame_beast : public SpellScript } }; -// 67151 - T9 4P Bonus -class spell_hun_t9_4p_bonus : public AuraScript -{ - PrepareAuraScript(spell_hun_t9_4p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_T9_4P_GREATNESS)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER && eventInfo.GetActor()->ToPlayer()->GetPet()) - { - return true; - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - - caster->CastSpell(caster->ToPlayer()->GetPet(), SPELL_HUNTER_T9_4P_GREATNESS, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_hun_t9_4p_bonus::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_hun_t9_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 60144 - Viper Attack Speed class spell_hun_viper_attack_speed : public AuraScript { @@ -1165,7 +1081,7 @@ class spell_hun_glyph_of_arcane_shot : public AuraScript int32 mana = procSpell->CalcPowerCost(GetTarget(), procSpell->GetSchoolMask()); ApplyPct(mana, aurEff->GetAmount()); - GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), TRIGGERED_NONE, nullptr, aurEff); + GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget()); } void Register() override @@ -1314,7 +1230,7 @@ class spell_hun_lock_and_load : public AuraScript } Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true, nullptr, aurEff); + caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true); } void ApplyMarker(ProcEventInfo& eventInfo) @@ -1392,172 +1308,6 @@ class spell_hun_bestial_wrath : public SpellScript } }; -// 57870 - Glyph of Mend Pet -class spell_hun_glyph_of_mend_pet : public AuraScript -{ - PrepareAuraScript(spell_hun_glyph_of_mend_pet); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_HUNTER_GLYPH_OF_MEND_PET_HAPPINESS, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_mend_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -53290 - Hunting Party -class spell_hun_hunting_party : public AuraScript -{ - PrepareAuraScript(spell_hun_hunting_party); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_REPLENISHMENT }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_hun_hunting_party::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 58914 - Kill Command -class spell_hun_kill_command_pet : public AuraScript -{ - PrepareAuraScript(spell_hun_kill_command_pet); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_HUNTER_KILL_COMMAND_HUNTER }); - } - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - // prevent charge drop (aura has both proc charge and stacks) - PreventDefaultAction(); - - if (Unit* owner = eventInfo.GetActor()->GetOwner()) - owner->RemoveAuraFromStack(SPELL_HUNTER_KILL_COMMAND_HUNTER); - - ModStackAmount(-1); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_hun_kill_command_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -53228 - Rapid Recuperation (talent aura) -class spell_hun_rapid_recuperation_trigger : public AuraScript -{ - PrepareAuraScript(spell_hun_rapid_recuperation_trigger); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, - SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 - }); - } - - void HandleRapidFireProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - // Proc only from Rapid Fire - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000020)) - { - PreventDefaultAction(); - return; - } - } - - void HandleRapidKillingProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static uint32 const triggerSpells[2] = { SPELL_HUNTER_RAPID_RECUPERATION_MANA_R1, SPELL_HUNTER_RAPID_RECUPERATION_MANA_R2 }; - - PreventDefaultAction(); - - // Proc only from Rapid Killing - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || !(spellInfo->SpellFamilyFlags[1] & 0x01000000)) - return; - - uint8 rank = GetSpellInfo()->GetRank(); - uint32 spellId = triggerSpells[rank - 1]; - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidFireProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - OnEffectProc += AuraEffectProcFn(spell_hun_rapid_recuperation_trigger::HandleRapidKillingProc, EFFECT_1, SPELL_AURA_DUMMY); - } -}; - -// -34497 - Thrill of the Hunt -class spell_hun_thrill_of_the_hunt : public AuraScript -{ - PrepareAuraScript(spell_hun_thrill_of_the_hunt); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - Unit* caster = eventInfo.GetActor(); - int32 amount = 0; - - // Explosive Shot - if (spellInfo->SpellFamilyFlags[2] & 0x200) - { - if (AuraEffect const* explosiveShot = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x00000000, 0x80000000, 0x00000000, caster->GetGUID())) - { - // due to Lock and Load SpellInfo::CalcPowerCost might return 0, so just calculate it manually - amount = CalculatePct(static_cast(CalculatePct(caster->GetCreateMana(), explosiveShot->GetSpellInfo()->ManaCostPercentage)), aurEff->GetAmount()); - - ASSERT(explosiveShot->GetSpellInfo()->GetMaxTicks() > 0); - amount /= explosiveShot->GetSpellInfo()->GetMaxTicks(); - } - } - else - amount = CalculatePct(static_cast(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask())), aurEff->GetAmount()); - - if (!amount) - return; - - caster->CastCustomSpell(SPELL_HUNTER_THRILL_OF_THE_HUNT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_hun_thrill_of_the_hunt::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - void AddSC_hunter_spell_scripts() { RegisterSpellScript(spell_hun_check_pet_los); @@ -1579,20 +1329,13 @@ void AddSC_hunter_spell_scripts() RegisterSpellScript(spell_hun_misdirection_proc); RegisterSpellScript(spell_hun_pet_carrion_feeder); RegisterSpellScript(spell_hun_pet_heart_of_the_phoenix); - RegisterSpellScript(spell_hun_piercing_shots); RegisterSpellScript(spell_hun_readiness); RegisterSpellScript(spell_hun_scatter_shot); RegisterSpellScript(spell_hun_sniper_training); RegisterSpellScript(spell_hun_tame_beast); - RegisterSpellScript(spell_hun_t9_4p_bonus); RegisterSpellScript(spell_hun_viper_attack_speed); RegisterSpellScript(spell_hun_volley_trigger); RegisterSpellScript(spell_hun_lock_and_load); RegisterSpellScript(spell_hun_intimidation); RegisterSpellScript(spell_hun_bestial_wrath); - RegisterSpellScript(spell_hun_glyph_of_mend_pet); - RegisterSpellScript(spell_hun_hunting_party); - RegisterSpellScript(spell_hun_kill_command_pet); - RegisterSpellScript(spell_hun_rapid_recuperation_trigger); - RegisterSpellScript(spell_hun_thrill_of_the_hunt); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 769d96e77..3476fb1e3 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -403,12 +403,12 @@ class spell_item_lil_phylactery : public AuraScript return eventInfo.GetActionTarget() && (eventInfo.GetActionTarget()->GetTypeId() != TYPEID_UNIT || eventInfo.GetActionTarget()->ToCreature()->isWorldBoss()); } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); if (Unit* critter = ObjectAccessor::GetUnit(*GetUnitOwner(), GetUnitOwner()->GetCritterGUID())) - GetUnitOwner()->CastSpell(critter, 69731 /*SPELL_LICH_PET_AURA_ON_KILL*/, true, nullptr, aurEff); + GetUnitOwner()->CastSpell(critter, 69731 /*SPELL_LICH_PET_AURA_ON_KILL*/, true); } void Register() override @@ -536,13 +536,13 @@ class spell_item_essence_of_life : public AuraScript }; const uint32 crazyAlchemistTable[5] = - { - 53909, // Wild Magic - 53908, // Potion of Speed - 53762, // Indestructible Potion - 43185, // Runic Healing Potion - 43186 // Runic Mana Potion - }; +{ + 53909, // Wild Magic + 53908, // Potion of Speed + 53762, // Indestructible Potion + 43185, // Runic Healing Potion + 43186 // Runic Mana Potion +}; class spell_item_crazy_alchemists_potion : public SpellScript { @@ -883,7 +883,7 @@ class spell_item_fetch_ball : public SpellScript if (Creature* creature = (*itr)->ToCreature()) { if (creature->GetOwnerGUID() == GetCaster()->GetOwnerGUID() && !creature->IsNonMeleeSpellCast(false) && - creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) { target = creature; break; @@ -923,11 +923,11 @@ class spell_item_oracle_ablutions : public SpellScript caster->CastSpell(caster, SPELL_ABLUTION_RUNIC, true); break; case POWER_MANA: - { - int32 mana = CalculatePct(caster->GetMaxPower(POWER_MANA), 5.0f); - caster->CastCustomSpell(SPELL_ABLUTION_MANA, SPELLVALUE_BASE_POINT0, mana, caster, true); - break; - } + { + int32 mana = CalculatePct(caster->GetMaxPower(POWER_MANA), 5.0f); + caster->CastCustomSpell(SPELL_ABLUTION_MANA, SPELLVALUE_BASE_POINT0, mana, caster, true); + break; + } case POWER_RAGE: caster->CastSpell(caster, SPELL_ABLUTION_RAGE, true); break; @@ -954,10 +954,10 @@ class spell_item_trauma : public AuraScript return eventInfo.GetActionTarget(); } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { PreventDefaultAction(); - GetUnitOwner()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff); + GetUnitOwner()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); } void Register() override @@ -971,7 +971,7 @@ class spell_item_blade_ward_enchant : public AuraScript { PrepareAuraScript(spell_item_blade_ward_enchant); - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { PreventDefaultAction(); if (!eventInfo.GetActionTarget()) @@ -982,7 +982,7 @@ class spell_item_blade_ward_enchant : public AuraScript if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64442 /*SPELL_BLADE_WARDING*/)) { int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActor(), true, nullptr, aurEff); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActor(), true); } } @@ -992,6 +992,37 @@ class spell_item_blade_ward_enchant : public AuraScript } }; +class spell_item_blood_draining_enchant : public AuraScript +{ + PrepareAuraScript(spell_item_blood_draining_enchant); + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (!eventInfo.GetActionTarget() || !eventInfo.GetDamageInfo() || (eventInfo.GetActionTarget()->GetHealth() - eventInfo.GetDamageInfo()->GetDamage()) >= eventInfo.GetActionTarget()->CountPctFromMaxHealth(35)) + { + return; + } + + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/)) + { + int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); + eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/); + int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); + eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); + eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_item_blood_draining_enchant::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + class spell_item_dragon_kite_summon_lightning_bunny : public SpellScript { PrepareSpellScript(spell_item_dragon_kite_summon_lightning_bunny); @@ -1160,12 +1191,12 @@ class spell_item_eye_of_gruul_healing_discount : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_DRUID_ITEM_HEALING_TRANCE, - SPELL_PALADIN_ITEM_HEALING_TRANCE, - SPELL_PRIEST_ITEM_HEALING_TRANCE, - SPELL_SHAMAN_ITEM_HEALING_TRANCE - }); + { + SPELL_DRUID_ITEM_HEALING_TRANCE, + SPELL_PALADIN_ITEM_HEALING_TRANCE, + SPELL_PRIEST_ITEM_HEALING_TRANCE, + SPELL_SHAMAN_ITEM_HEALING_TRANCE + }); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) @@ -1628,9 +1659,9 @@ class spell_item_fate_rune_of_unsurpassed_vigor : public AuraScript return ValidateSpellInfo({ SPELL_UNSURPASSED_VIGOR }); } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) { - GetTarget()->CastSpell(GetTarget(), SPELL_UNSURPASSED_VIGOR, true, nullptr, aurEff); + GetTarget()->CastSpell(GetTarget(), SPELL_UNSURPASSED_VIGOR, true); } void Register() override @@ -1752,13 +1783,13 @@ class spell_item_make_a_wish : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_MR_PINCHYS_BLESSING, - SPELL_SUMMON_MIGHTY_MR_PINCHY, - SPELL_SUMMON_FURIOUS_MR_PINCHY, - SPELL_TINY_MAGICAL_CRAWDAD, - SPELL_MR_PINCHYS_GIFT - }); + { + SPELL_MR_PINCHYS_BLESSING, + SPELL_SUMMON_MIGHTY_MR_PINCHY, + SPELL_SUMMON_FURIOUS_MR_PINCHY, + SPELL_TINY_MAGICAL_CRAWDAD, + SPELL_MR_PINCHYS_GIFT + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -1814,12 +1845,12 @@ enum MingoFortune }; std::array const CreateFortuneSpells = - { - SPELL_CREATE_FORTUNE_1, SPELL_CREATE_FORTUNE_2, SPELL_CREATE_FORTUNE_3, SPELL_CREATE_FORTUNE_4, SPELL_CREATE_FORTUNE_5, - SPELL_CREATE_FORTUNE_6, SPELL_CREATE_FORTUNE_7, SPELL_CREATE_FORTUNE_8, SPELL_CREATE_FORTUNE_9, SPELL_CREATE_FORTUNE_10, - SPELL_CREATE_FORTUNE_11, SPELL_CREATE_FORTUNE_12, SPELL_CREATE_FORTUNE_13, SPELL_CREATE_FORTUNE_14, SPELL_CREATE_FORTUNE_15, - SPELL_CREATE_FORTUNE_16, SPELL_CREATE_FORTUNE_17, SPELL_CREATE_FORTUNE_18, SPELL_CREATE_FORTUNE_19, SPELL_CREATE_FORTUNE_20 - }; +{ + SPELL_CREATE_FORTUNE_1, SPELL_CREATE_FORTUNE_2, SPELL_CREATE_FORTUNE_3, SPELL_CREATE_FORTUNE_4, SPELL_CREATE_FORTUNE_5, + SPELL_CREATE_FORTUNE_6, SPELL_CREATE_FORTUNE_7, SPELL_CREATE_FORTUNE_8, SPELL_CREATE_FORTUNE_9, SPELL_CREATE_FORTUNE_10, + SPELL_CREATE_FORTUNE_11, SPELL_CREATE_FORTUNE_12, SPELL_CREATE_FORTUNE_13, SPELL_CREATE_FORTUNE_14, SPELL_CREATE_FORTUNE_15, + SPELL_CREATE_FORTUNE_16, SPELL_CREATE_FORTUNE_17, SPELL_CREATE_FORTUNE_18, SPELL_CREATE_FORTUNE_19, SPELL_CREATE_FORTUNE_20 +}; // 26465 - Mercurial Shield enum MercurialShield @@ -1922,11 +1953,11 @@ class spell_item_net_o_matic : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_NET_O_MATIC_TRIGGERED1, - SPELL_NET_O_MATIC_TRIGGERED2, - SPELL_NET_O_MATIC_TRIGGERED3 - }); + { + SPELL_NET_O_MATIC_TRIGGERED1, + SPELL_NET_O_MATIC_TRIGGERED2, + SPELL_NET_O_MATIC_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -1971,11 +2002,11 @@ class spell_item_noggenfogger_elixir : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED1, - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2, - SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED3 - }); + { + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED1, + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED2, + SPELL_NOGGENFOGGER_ELIXIR_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2056,7 +2087,7 @@ class spell_item_savory_deviate_delight : public SpellScript case 1: spellId = (caster->getGender() == GENDER_MALE ? SPELL_FLIP_OUT_MALE : SPELL_FLIP_OUT_FEMALE); break; - // Yaaarrrr - pirate + // Yaaarrrr - pirate case 2: spellId = (caster->getGender() == GENDER_MALE ? SPELL_YAAARRRR_MALE : SPELL_YAAARRRR_FEMALE); break; @@ -2247,7 +2278,7 @@ class spell_item_unsated_craving : public AuraScript void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, TRIGGERED_FULL_MASK, nullptr, aurEff); + eventInfo.GetActor()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, TRIGGERED_FULL_MASK); } void Register() override @@ -2261,7 +2292,7 @@ class spell_item_shadows_fate : public AuraScript { PrepareAuraScript(spell_item_shadows_fate); - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -2270,7 +2301,7 @@ class spell_item_shadows_fate : public AuraScript if (!caster || !target) return; - caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK, nullptr, aurEff); + caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK); } void Register() override @@ -2297,11 +2328,11 @@ class spell_item_shadowmourne : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, - SPELL_SHADOWMOURNE_SOUL_FRAGMENT, - SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF - }); + { + SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, + SPELL_SHADOWMOURNE_SOUL_FRAGMENT, + SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF + }); } bool CheckProc(ProcEventInfo& eventInfo) @@ -2423,14 +2454,14 @@ class spell_item_six_demon_bag : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_FROSTBOLT, - SPELL_POLYMORPH, - SPELL_SUMMON_FELHOUND_MINION, - SPELL_FIREBALL, - SPELL_CHAIN_LIGHTNING, - SPELL_ENVELOPING_WINDS - }); + { + SPELL_FROSTBOLT, + SPELL_POLYMORPH, + SPELL_SUMMON_FELHOUND_MINION, + SPELL_FIREBALL, + SPELL_CHAIN_LIGHTNING, + SPELL_ENVELOPING_WINDS + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2509,11 +2540,11 @@ class spell_item_underbelly_elixir : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_UNDERBELLY_ELIXIR_TRIGGERED1, - SPELL_UNDERBELLY_ELIXIR_TRIGGERED2, - SPELL_UNDERBELLY_ELIXIR_TRIGGERED3 - }); + { + SPELL_UNDERBELLY_ELIXIR_TRIGGERED1, + SPELL_UNDERBELLY_ELIXIR_TRIGGERED2, + SPELL_UNDERBELLY_ELIXIR_TRIGGERED3 + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2598,8 +2629,8 @@ class spell_item_map_of_the_geyser_fields : public SpellScript { Unit* caster = GetCaster(); if (caster->FindNearestCreature(NPC_SOUTH_SINKHOLE, 30.0f, true) || - caster->FindNearestCreature(NPC_NORTHEAST_SINKHOLE, 30.0f, true) || - caster->FindNearestCreature(NPC_NORTHWEST_SINKHOLE, 30.0f, true)) + caster->FindNearestCreature(NPC_NORTHEAST_SINKHOLE, 30.0f, true) || + caster->FindNearestCreature(NPC_NORTHWEST_SINKHOLE, 30.0f, true)) return SPELL_CAST_OK; SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_BE_CLOSE_TO_SINKHOLE); @@ -2626,11 +2657,11 @@ class spell_item_vanquished_clutches : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( - { - SPELL_CRUSHER, - SPELL_CONSTRICTOR, - SPELL_CORRUPTOR - }); + { + SPELL_CRUSHER, + SPELL_CONSTRICTOR, + SPELL_CORRUPTOR + }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -2835,13 +2866,13 @@ class spell_item_reindeer_transformation : public SpellScript bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( - { - SPELL_FLYING_REINDEER_310, - SPELL_FLYING_REINDEER_280, - SPELL_FLYING_REINDEER_60, - SPELL_REINDEER_100, - SPELL_REINDEER_60 - }); + { + SPELL_FLYING_REINDEER_310, + SPELL_FLYING_REINDEER_280, + SPELL_FLYING_REINDEER_60, + SPELL_REINDEER_100, + SPELL_REINDEER_60 + }); } void HandleDummy(SpellEffIndex /* effIndex */) @@ -3111,12 +3142,12 @@ class spell_item_brewfest_mount_transformation : public SpellScript bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( - { - SPELL_MOUNT_RAM_100, - SPELL_MOUNT_RAM_60, - SPELL_MOUNT_KODO_100, - SPELL_MOUNT_KODO_60 - }); + { + SPELL_MOUNT_RAM_100, + SPELL_MOUNT_RAM_60, + SPELL_MOUNT_KODO_100, + SPELL_MOUNT_KODO_60 + }); } void HandleDummy(SpellEffIndex /* effIndex */) @@ -3135,20 +3166,20 @@ class spell_item_brewfest_mount_transformation : public SpellScript switch (GetSpellInfo()->Id) { - case SPELL_BREWFEST_MOUNT_TRANSFORM: - if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; - else - spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; - break; - case SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE: - if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) - spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; - else - spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; - break; - default: - return; + case SPELL_BREWFEST_MOUNT_TRANSFORM: + if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; + else + spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; + break; + case SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE: + if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f) + spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100; + else + spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60; + break; + default: + return; } caster->CastSpell(caster, spell_id, true); } @@ -3658,1323 +3689,6 @@ class spell_item_mirrens_drinking_hat : public SpellScript } }; -enum SoulPreserver -{ - SPELL_SOUL_PRESERVER_DRUID = 60512, - SPELL_SOUL_PRESERVER_PALADIN = 60513, - SPELL_SOUL_PRESERVER_PRIEST = 60514, - SPELL_SOUL_PRESERVER_SHAMAN = 60515, -}; - -class spell_item_soul_preserver : public AuraScript -{ - PrepareAuraScript(spell_item_soul_preserver); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SOUL_PRESERVER_DRUID, SPELL_SOUL_PRESERVER_PALADIN, SPELL_SOUL_PRESERVER_PRIEST, SPELL_SOUL_PRESERVER_SHAMAN }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - - switch (caster->getClass()) - { - case CLASS_DRUID: - caster->CastSpell(caster, SPELL_SOUL_PRESERVER_DRUID, true, nullptr, aurEff); - break; - case CLASS_PALADIN: - caster->CastSpell(caster, SPELL_SOUL_PRESERVER_PALADIN, true, nullptr, aurEff); - break; - case CLASS_PRIEST: - caster->CastSpell(caster, SPELL_SOUL_PRESERVER_PRIEST, true, nullptr, aurEff); - break; - case CLASS_SHAMAN: - caster->CastSpell(caster, SPELL_SOUL_PRESERVER_SHAMAN, true, nullptr, aurEff); - break; - default: - break; - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_soul_preserver::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -enum DeathChoiceSpells -{ - SPELL_DEATH_CHOICE_NORMAL_AURA = 67702, - SPELL_DEATH_CHOICE_NORMAL_AGILITY = 67703, - SPELL_DEATH_CHOICE_NORMAL_STRENGTH = 67708, - SPELL_DEATH_CHOICE_HEROIC_AURA = 67771, - SPELL_DEATH_CHOICE_HEROIC_AGILITY = 67772, - SPELL_DEATH_CHOICE_HEROIC_STRENGTH = 67773 -}; - -class spell_item_death_choice : public AuraScript -{ - PrepareAuraScript(spell_item_death_choice); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DEATH_CHOICE_NORMAL_STRENGTH, SPELL_DEATH_CHOICE_NORMAL_AGILITY, SPELL_DEATH_CHOICE_HEROIC_STRENGTH, SPELL_DEATH_CHOICE_HEROIC_AGILITY }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - float str = caster->GetStat(STAT_STRENGTH); - float agi = caster->GetStat(STAT_AGILITY); - - switch (aurEff->GetId()) - { - case SPELL_DEATH_CHOICE_NORMAL_AURA: - { - if (str > agi) - { - caster->CastSpell(caster, SPELL_DEATH_CHOICE_NORMAL_STRENGTH, true, nullptr, aurEff); - } - else - { - caster->CastSpell(caster, SPELL_DEATH_CHOICE_NORMAL_AGILITY, true, nullptr, aurEff); - } - break; - } - case SPELL_DEATH_CHOICE_HEROIC_AURA: - { - if (str > agi) - { - caster->CastSpell(caster, SPELL_DEATH_CHOICE_HEROIC_STRENGTH, true, nullptr, aurEff); - } - else - { - caster->CastSpell(caster, SPELL_DEATH_CHOICE_HEROIC_AGILITY, true, nullptr, aurEff); - } - break; - } - default: - break; - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_death_choice::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -enum TrinketStackSpells -{ - SPELL_LIGHTNING_CAPACITOR_AURA = 37657, // Lightning Capacitor - SPELL_LIGHTNING_CAPACITOR_STACK = 37658, - SPELL_LIGHTNING_CAPACITOR_TRIGGER = 37661, - SPELL_THUNDER_CAPACITOR_AURA = 54841, // Thunder Capacitor - SPELL_THUNDER_CAPACITOR_STACK = 54842, - SPELL_THUNDER_CAPACITOR_TRIGGER = 54843, - SPELL_TOC25_CASTER_TRINKET_NORMAL_AURA = 67712, // Item - Coliseum 25 Normal Caster Trinket - SPELL_TOC25_CASTER_TRINKET_NORMAL_STACK = 67713, - SPELL_TOC25_CASTER_TRINKET_NORMAL_TRIGGER = 67714, - SPELL_TOC25_CASTER_TRINKET_HEROIC_AURA = 67758, // Item - Coliseum 25 Heroic Caster Trinket - SPELL_TOC25_CASTER_TRINKET_HEROIC_STACK = 67759, - SPELL_TOC25_CASTER_TRINKET_HEROIC_TRIGGER = 67760, -}; - -class spell_item_trinket_stack : public SpellScriptLoader -{ -public: - spell_item_trinket_stack(char const* scriptName, uint32 stackSpell, uint32 triggerSpell) : SpellScriptLoader(scriptName), - _stackSpell(stackSpell), _triggerSpell(triggerSpell) - { - } - - class spell_item_trinket_stack_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_trinket_stack_AuraScript); - - public: - spell_item_trinket_stack_AuraScript(uint32 stackSpell, uint32 triggerSpell) : _stackSpell(stackSpell), _triggerSpell(triggerSpell) - { - } - - private: - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ _stackSpell, _triggerSpell }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - - caster->CastSpell(caster, _stackSpell, true, nullptr, aurEff); // cast the stack - - Aura* dummy = caster->GetAura(_stackSpell); // retrieve aura - - //dont do anything if it's not the right amount of stacks; - if (!dummy || dummy->GetStackAmount() < aurEff->GetAmount()) - return; - - // if right amount, remove the aura and cast real trigger - caster->RemoveAurasDueToSpell(_stackSpell); - if (Unit* target = eventInfo.GetActionTarget()) - { - caster->CastSpell(target, _triggerSpell, true, nullptr, aurEff); - } - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAurasDueToSpell(_stackSpell); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_trinket_stack_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - AfterEffectRemove += AuraEffectRemoveFn(spell_item_trinket_stack_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - - private: - uint32 _stackSpell; - uint32 _triggerSpell; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_trinket_stack_AuraScript(_stackSpell, _triggerSpell); - } - -private: - uint32 _stackSpell; - uint32 _triggerSpell; -}; - -// 57345 - Darkmoon Card: Greatness -enum DarkmoonCardSpells -{ - SPELL_DARKMOON_CARD_STRENGHT = 60229, - SPELL_DARKMOON_CARD_AGILITY = 60233, - SPELL_DARKMOON_CARD_INTELLECT = 60234, - SPELL_DARKMOON_CARD_SPIRIT = 60235, -}; - -class spell_item_darkmoon_card_greatness : public AuraScript -{ - PrepareAuraScript(spell_item_darkmoon_card_greatness); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DARKMOON_CARD_AGILITY, SPELL_DARKMOON_CARD_STRENGHT, SPELL_DARKMOON_CARD_INTELLECT, SPELL_DARKMOON_CARD_SPIRIT }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - float str = caster->GetStat(STAT_STRENGTH); - float agi = caster->GetStat(STAT_AGILITY); - float intl = caster->GetStat(STAT_INTELLECT); - float spi = caster->GetStat(STAT_SPIRIT); - float stat = 0.0f; - - uint32 spellTrigger = SPELL_DARKMOON_CARD_STRENGHT; - - if (str > stat) - { - spellTrigger = SPELL_DARKMOON_CARD_STRENGHT; - stat = str; - } - - if (agi > stat) - { - spellTrigger = SPELL_DARKMOON_CARD_AGILITY; - stat = agi; - } - - if (intl > stat) - { - spellTrigger = SPELL_DARKMOON_CARD_INTELLECT; - stat = intl; - } - - if (spi > stat) - { - spellTrigger = SPELL_DARKMOON_CARD_SPIRIT; - stat = spi; - } - - caster->CastSpell(caster, spellTrigger, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_darkmoon_card_greatness::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 43820 - Amani Charm of the Witch Doctor -enum CharmWitchDoctor -{ - SPELL_CHARM_WITCH_DOCTOR_PROC = 43821 -}; - -class spell_item_charm_witch_doctor : public AuraScript -{ - PrepareAuraScript(spell_item_charm_witch_doctor); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_CHARM_WITCH_DOCTOR_PROC }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetActionTarget(); - - if (target) - { - int32 bp = CalculatePct(target->GetCreateHealth(), aurEff->GetSpellInfo()->Effects[1].CalcValue()); - caster->CastCustomSpell(target, SPELL_CHARM_WITCH_DOCTOR_PROC, &bp, nullptr, nullptr, true, nullptr, aurEff); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_charm_witch_doctor::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -enum ManaDrainSpells -{ - SPELL_MANA_DRAIN_ENERGIZE = 29471, - SPELL_MANA_DRAIN_LEECH = 27526 -}; - -// 27522, 40336 - Mana Drain -class spell_item_mana_drain : public AuraScript -{ - PrepareAuraScript(spell_item_mana_drain); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MANA_DRAIN_ENERGIZE, SPELL_MANA_DRAIN_LEECH }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetActionTarget(); - - if (caster->IsAlive()) - { - caster->CastSpell(caster, SPELL_MANA_DRAIN_ENERGIZE, true, nullptr, aurEff); - } - - if (target && target->IsAlive()) - { - caster->CastSpell(target, SPELL_MANA_DRAIN_LEECH, true, nullptr, aurEff); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_mana_drain::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// Item - 12846: Argent Dawn Commission -// Item - 13209: Seal of the Dawn -// Item - 19812: Rune of the Dawn - -enum AlchemistStone -{ - SPELL_ALCHEMISTS_STONE_EXTRA_HEAL = 21399, - SPELL_ALCHEMISTS_STONE_EXTRA_MANA = 21400 -}; - -// Item - 13503: Alchemist's Stone -// Item - 35748: Guardian's Alchemist Stone -// Item - 35749: Sorcerer's Alchemist Stone -// Item - 35750: Redeemer's Alchemist Stone -// Item - 35751: Assassin's Alchemist Stone -// Item - 44322: Mercurial Alchemist Stone -// Item - 44323: Indestructible Alchemist's Stone -// Item - 44324: Mighty Alchemist's Stone - -// 17619 - Alchemist's Stone -class spell_item_alchemists_stone : public AuraScript -{ - PrepareAuraScript(spell_item_alchemists_stone); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_ALCHEMISTS_STONE_EXTRA_HEAL, - SPELL_ALCHEMISTS_STONE_EXTRA_MANA - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - Unit* caster = eventInfo.GetActionTarget(); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - uint32 spellId; - switch (spellInfo->Effects[i].Effect) - { - case SPELL_EFFECT_HEAL: - spellId = SPELL_ALCHEMISTS_STONE_EXTRA_HEAL; - break; - case SPELL_EFFECT_ENERGIZE: - spellId = SPELL_ALCHEMISTS_STONE_EXTRA_MANA; - break; - default: - continue; - } - - int32 amount = CalculatePct(spellInfo->Effects[i].CalcValue(caster), 40); - caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_alchemists_stone::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum AngerCapacitor -{ - SPELL_MOTE_OF_ANGER = 71432, - SPELL_MANIFEST_ANGER_MAIN_HAND = 71433, - SPELL_MANIFEST_ANGER_OFF_HAND = 71434 -}; - -// Item - 50351: Tiny Abomination in a Jar -// 71406 - Anger Capacitor - -// Item - 50706: Tiny Abomination in a Jar (Heroic) -// 71545 - Anger Capacitor -template -class spell_item_anger_capacitor : public SpellScriptLoader -{ -public: - spell_item_anger_capacitor(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_item_anger_capacitor_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_anger_capacitor_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_MOTE_OF_ANGER, - SPELL_MANIFEST_ANGER_MAIN_HAND, - SPELL_MANIFEST_ANGER_OFF_HAND - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - caster->CastSpell((Unit*)nullptr, SPELL_MOTE_OF_ANGER, true); - Aura const* motes = caster->GetAura(SPELL_MOTE_OF_ANGER); - if (!motes || motes->GetStackAmount() < Stacks) - return; - - caster->RemoveAurasDueToSpell(SPELL_MOTE_OF_ANGER); - uint32 spellId = SPELL_MANIFEST_ANGER_MAIN_HAND; - if (Player* player = caster->ToPlayer()) - if (player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1)) - spellId = SPELL_MANIFEST_ANGER_OFF_HAND; - - caster->CastSpell(target, spellId, true, nullptr, aurEff); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAurasDueToSpell(SPELL_MOTE_OF_ANGER); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_anger_capacitor_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - AfterEffectRemove += AuraEffectRemoveFn(spell_item_anger_capacitor_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_anger_capacitor_AuraScript(); - } -}; - -enum AuraOfMadness -{ - SPELL_SOCIOPATH = 39511, // Sociopath: +35 strength(Paladin, Rogue, Druid, Warrior) - SPELL_DELUSIONAL = 40997, // Delusional: +70 attack power(Rogue, Hunter, Paladin, Warrior, Druid) - SPELL_KLEPTOMANIA = 40998, // Kleptomania: +35 agility(Warrior, Rogue, Paladin, Hunter, Druid) - SPELL_MEGALOMANIA = 40999, // Megalomania: +41 damage / healing(Druid, Shaman, Priest, Warlock, Mage, Paladin) - SPELL_PARANOIA = 41002, // Paranoia: +35 spell / melee / ranged crit strike rating(All classes) - SPELL_MANIC = 41005, // Manic: +35 haste(spell, melee and ranged) (All classes) - SPELL_NARCISSISM = 41009, // Narcissism: +35 intellect(Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter) - SPELL_MARTYR_COMPLEX = 41011, // Martyr Complex: +35 stamina(All classes) - SPELL_DEMENTIA = 41404, // Dementia: Every 5 seconds either gives you +5/-5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin) - - SPELL_DEMENTIA_POS = 41406, - SPELL_DEMENTIA_NEG = 41409, - - SAY_MADNESS = 21954 -}; - -// Item - 31859: Darkmoon Card: Madness -// 39446 - Aura of Madness -class spell_item_aura_of_madness : public AuraScript -{ - PrepareAuraScript(spell_item_aura_of_madness); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SOCIOPATH, - SPELL_DELUSIONAL, - SPELL_KLEPTOMANIA, - SPELL_MEGALOMANIA, - SPELL_PARANOIA, - SPELL_MANIC, - SPELL_NARCISSISM, - SPELL_MARTYR_COMPLEX, - SPELL_DEMENTIA - }) && sObjectMgr->GetBroadcastText(SAY_MADNESS); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static std::vector const triggeredSpells[MAX_CLASSES] = - { - //CLASS_NONE - { }, - //CLASS_WARRIOR - { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, - //CLASS_PALADIN - { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_HUNTER - { SPELL_DELUSIONAL, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_ROGUE - { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, - //CLASS_PRIEST - { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_DEATH_KNIGHT - { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_MARTYR_COMPLEX }, - //CLASS_SHAMAN - { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_MAGE - { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_WARLOCK - { SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA }, - //CLASS_UNK - { }, - //CLASS_DRUID - { SPELL_SOCIOPATH, SPELL_DELUSIONAL, SPELL_KLEPTOMANIA, SPELL_MEGALOMANIA, SPELL_PARANOIA, SPELL_MANIC, SPELL_NARCISSISM, SPELL_MARTYR_COMPLEX, SPELL_DEMENTIA } - }; - - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - uint32 spellId = Acore::Containers::SelectRandomContainerElement(triggeredSpells[caster->getClass()]); - caster->CastSpell(caster, spellId, true, nullptr, aurEff); - - if (roll_chance_i(10)) - caster->Unit::Say(SAY_MADNESS); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_aura_of_madness::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 41404 - Dementia -class spell_item_dementia : public AuraScript -{ - PrepareAuraScript(spell_item_dementia); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_DEMENTIA_POS, - SPELL_DEMENTIA_NEG - }); - } - - void HandlePeriodicDummy(AuraEffect const* aurEff) - { - PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), RAND(SPELL_DEMENTIA_POS, SPELL_DEMENTIA_NEG), aurEff); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_item_dementia::HandlePeriodicDummy, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } -}; - -enum DeadlyPrecision -{ - SPELL_DEADLY_PRECISION = 71564 -}; - -// 71564 - Deadly Precision -class spell_item_deadly_precision : public AuraScript -{ - PrepareAuraScript(spell_item_deadly_precision); - - void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - GetTarget()->RemoveAuraFromStack(GetId(), GetTarget()->GetGUID()); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_deadly_precision::HandleStackDrop, EFFECT_0, SPELL_AURA_MOD_RATING); - } -}; - -// 71563 - Deadly Precision Dummy -class spell_item_deadly_precision_dummy : public SpellScript -{ - PrepareSpellScript(spell_item_deadly_precision_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DEADLY_PRECISION }); - } - - void HandleDummy(SpellEffIndex /*effIndex*/) - { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DEADLY_PRECISION); - GetCaster()->CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_STACK, spellInfo->StackAmount, GetCaster(), true); - } - - void Register() override - { - OnEffectHit += SpellEffectFn(spell_item_deadly_precision_dummy::HandleDummy, EFFECT_0, SPELL_EFFECT_APPLY_AURA); - } -}; - -enum DeathbringersWill -{ - SPELL_STRENGTH_OF_THE_TAUNKA = 71484, // +600 Strength - SPELL_AGILITY_OF_THE_VRYKUL = 71485, // +600 Agility - SPELL_POWER_OF_THE_TAUNKA = 71486, // +1200 Attack Power - SPELL_AIM_OF_THE_IRON_DWARVES = 71491, // +600 Critical - SPELL_SPEED_OF_THE_VRYKUL = 71492, // +600 Haste - - SPELL_AGILITY_OF_THE_VRYKUL_HERO = 71556, // +700 Agility - SPELL_POWER_OF_THE_TAUNKA_HERO = 71558, // +1400 Attack Power - SPELL_AIM_OF_THE_IRON_DWARVES_HERO = 71559, // +700 Critical - SPELL_SPEED_OF_THE_VRYKUL_HERO = 71560, // +700 Haste - SPELL_STRENGTH_OF_THE_TAUNKA_HERO = 71561 // +700 Strength -}; - -// Item - 50362: Deathbringer's Will -// 71519 - Item - Icecrown 25 Normal Melee Trinket - -// Item - 50363: Deathbringer's Will -// 71562 - Item - Icecrown 25 Heroic Melee Trinket -template -class spell_item_deathbringers_will : public SpellScriptLoader -{ -public: - spell_item_deathbringers_will(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_item_deathbringers_will_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_deathbringers_will_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - Strength, - Agility, - AttackPower, - Critical, - Haste - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static std::vector const triggeredSpells[MAX_CLASSES] = - { - //CLASS_NONE - { }, - //CLASS_WARRIOR - { Strength, Critical, Haste }, - //CLASS_PALADIN - { Strength, Critical, Haste }, - //CLASS_HUNTER - { Agility, Critical, AttackPower }, - //CLASS_ROGUE - { Agility, Haste, AttackPower }, - //CLASS_PRIEST - { }, - //CLASS_DEATH_KNIGHT - { Strength, Critical, Haste }, - //CLASS_SHAMAN - { Agility, Haste, AttackPower }, - //CLASS_MAGE - { }, - //CLASS_WARLOCK - { }, - //CLASS_UNK - { }, - //CLASS_DRUID - { Strength, Agility, Haste } - }; - - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - std::vector const& randomSpells = triggeredSpells[caster->getClass()]; - if (randomSpells.empty()) - return; - - uint32 spellId = Acore::Containers::SelectRandomContainerElement(randomSpells); - caster->CastSpell(caster, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_deathbringers_will_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_deathbringers_will_AuraScript(); - } -}; - -enum DiscerningEyeBeastMisc -{ - SPELL_DISCERNING_EYE_BEAST = 59914 -}; - -// 59915 - Discerning Eye of the Beast Dummy -class spell_item_discerning_eye_beast_dummy : public AuraScript -{ - PrepareAuraScript(spell_item_discerning_eye_beast_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_DISCERNING_EYE_BEAST }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_DISCERNING_EYE_BEAST, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_discerning_eye_beast_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum FrozenShadoweave -{ - SPELL_SHADOWMEND = 39373 -}; - -// 39372 - Frozen Shadoweave -// Frozen Shadoweave set 3p bonus -class spell_item_frozen_shadoweave : public AuraScript -{ - PrepareAuraScript(spell_item_frozen_shadoweave); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHADOWMEND }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_SHADOWMEND, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_frozen_shadoweave::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// Item 23004 - Idol of Longevity -// 28847 - Healing Touch Refund -enum IdolOfLongevity -{ - SPELL_HEALING_TOUCH_MANA = 28848 -}; - -class spell_item_healing_touch_refund : public AuraScript -{ - PrepareAuraScript(spell_item_healing_touch_refund); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_HEALING_TOUCH_MANA }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_HEALING_TOUCH_MANA, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_healing_touch_refund::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum Heartpierce -{ - SPELL_INVIGORATION_MANA = 71881, - SPELL_INVIGORATION_ENERGY = 71882, - SPELL_INVIGORATION_RAGE = 71883, - SPELL_INVIGORATION_RP = 71884, - - SPELL_INVIGORATION_RP_HERO = 71885, - SPELL_INVIGORATION_RAGE_HERO = 71886, - SPELL_INVIGORATION_ENERGY_HERO = 71887, - SPELL_INVIGORATION_MANA_HERO = 71888 -}; - -// Item - 49982: Heartpierce -// 71880 - Item - Icecrown 25 Normal Dagger Proc - -// Item - 50641: Heartpierce (Heroic) -// 71892 - Item - Icecrown 25 Heroic Dagger Proc -template -class spell_item_heartpierce : public SpellScriptLoader -{ -public: - spell_item_heartpierce(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_item_heartpierce_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_heartpierce_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - Energy, - Mana, - Rage, - RunicPower - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - - uint32 spellId; - switch (caster->getPowerType()) - { - case POWER_MANA: - spellId = Mana; - break; - case POWER_ENERGY: - spellId = Energy; - break; - case POWER_RAGE: - spellId = Rage; - break; - // Death Knights can't use daggers, but oh well - case POWER_RUNIC_POWER: - spellId = RunicPower; - break; - default: - return; - } - - caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_heartpierce_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_heartpierce_AuraScript(); - } -}; - -// 40971 - Bonus Healing (Crystal Spire of Karabor) -class spell_item_crystal_spire_of_karabor : public AuraScript -{ - PrepareAuraScript(spell_item_crystal_spire_of_karabor); - - bool CheckProc(ProcEventInfo& eventInfo) - { - int32 pct = GetSpellInfo()->Effects[EFFECT_0].BasePoints; - if (HealInfo* healInfo = eventInfo.GetHealInfo()) - if (Unit* healTarget = healInfo->GetTarget()) - if (healTarget->GetHealth() - healInfo->GetEffectiveHeal() <= healTarget->CountPctFromMaxHealth(pct)) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_item_crystal_spire_of_karabor::CheckProc); - } -}; - -enum MarkOfConquest -{ - SPELL_MARK_OF_CONQUEST_ENERGIZE = 39599 -}; - -// Item - 27920: Mark of Conquest -// Item - 27921: Mark of Conquest -// 33510 - Health Restore -class spell_item_mark_of_conquest : public AuraScript -{ - PrepareAuraScript(spell_item_mark_of_conquest); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MARK_OF_CONQUEST_ENERGIZE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - if (eventInfo.GetTypeMask() & (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS)) - { - // in that case, do not cast heal spell - PreventDefaultAction(); - // but mana instead - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MARK_OF_CONQUEST_ENERGIZE, true, nullptr, aurEff); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_mark_of_conquest::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -enum PersistentShieldMisc -{ - SPELL_PERSISTENT_SHIELD_TRIGGERED = 26470 -}; - -// 26467 - Persistent Shield -class spell_item_persistent_shield : public AuraScript -{ - PrepareAuraScript(spell_item_persistent_shield); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PERSISTENT_SHIELD_TRIGGERED }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetHeal(); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - int32 bp0 = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15); - - // Scarab Brooch does not replace stronger shields - if (AuraEffect const* shield = target->GetAuraEffect(SPELL_PERSISTENT_SHIELD_TRIGGERED, EFFECT_0, caster->GetGUID())) - if (shield->GetAmount() > bp0) - return; - - caster->CastCustomSpell(SPELL_PERSISTENT_SHIELD_TRIGGERED, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_item_persistent_shield::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_item_persistent_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -enum PetHealing -{ - SPELL_HEALTH_LINK = 37382 -}; - -// 37381 - Pet Healing -// Hunter T5 2P Bonus -// Warlock T5 2P Bonus -class spell_item_pet_healing : public AuraScript -{ - PrepareAuraScript(spell_item_pet_healing); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_HEALTH_LINK }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell(SPELL_HEALTH_LINK, SPELLVALUE_BASE_POINT0, bp, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_pet_healing::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum SwiftHandJusticeMisc -{ - SPELL_SWIFT_HAND_OF_JUSTICE_HEAL = 59913 -}; - -// 59906 - Swift Hand of Justice Dummy -class spell_item_swift_hand_justice_dummy : public AuraScript -{ - PrepareAuraScript(spell_item_swift_hand_justice_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SWIFT_HAND_OF_JUSTICE_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - int32 amount = caster->CountPctFromMaxHealth(aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SWIFT_HAND_OF_JUSTICE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_swift_hand_justice_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum TotemOfFlowingWater -{ - SPELL_LESSER_HEALING_WAVE_MANA = 28850 -}; - -// Item - 23005: Totem of Flowing Water -// 28849 - Lesser Healing Wave -class spell_item_totem_of_flowing_water : public AuraScript -{ - PrepareAuraScript(spell_item_totem_of_flowing_water); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_LESSER_HEALING_WAVE_MANA }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_LESSER_HEALING_WAVE_MANA, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_totem_of_flowing_water::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -enum ShardOfTheScale -{ - SPELL_PURIFIED_CAUTERIZING_HEAL = 69733, - SPELL_PURIFIED_SEARING_FLAMES = 69729, - - SPELL_SHINY_CAUTERIZING_HEAL = 69734, - SPELL_SHINY_SEARING_FLAMES = 69730 -}; - -// Item - 49310: Purified Shard of the Scale -// 69755 - Purified Shard of the Scale - Equip Effect - -// Item - 49488: Shiny Shard of the Scale -// 69739 - Shiny Shard of the Scale - Equip Effect -template -class spell_item_shard_of_the_scale : public SpellScriptLoader -{ -public: - spell_item_shard_of_the_scale(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_item_shard_of_the_scale_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_shard_of_the_scale_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - HealProc, - DamageProc - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) - caster->CastSpell(target, HealProc, true, nullptr, aurEff); - - if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG) - caster->CastSpell(target, DamageProc, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_shard_of_the_scale_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_shard_of_the_scale_AuraScript(); - } -}; - -enum ExaltedSunwellNeck -{ - SPELL_LIGHTS_WRATH = 45479, // Light's Wrath if Exalted by Aldor - SPELL_ARCANE_BOLT = 45429, // Arcane Bolt if Exalted by Scryers - - SPELL_LIGHTS_STRENGTH = 45480, // Light's Strength if Exalted by Aldor - SPELL_ARCANE_STRIKE = 45428, // Arcane Strike if Exalted by Scryers - - SPELL_LIGHTS_WARD = 45432, // Light's Ward if Exalted by Aldor - SPELL_ARCANE_INSIGHT = 45431, // Arcane Insight if Exalted by Scryers - - SPELL_LIGHTS_SALVATION = 45478, // Light's Salvation if Exalted by Aldor - SPELL_ARCANE_SURGE = 45430, // Arcane Surge if Exalted by Scryers - - FACTION_ALDOR = 932, - FACTION_SCRYERS = 934 -}; - -// Item - 34678: Shattered Sun Pendant of Acumen -// 45481 - Sunwell Exalted Caster Neck - -// Item - 34679: Shattered Sun Pendant of Might -// 45482 - Sunwell Exalted Melee Neck - -// Item - 34680: Shattered Sun Pendant of Resolve -// 45483 - Sunwell Exalted Tank Neck - -// Item - 34677: Shattered Sun Pendant of Restoration -// 45484 Sunwell Exalted Healer Neck -template -class spell_item_sunwell_neck : public SpellScriptLoader -{ -public: - spell_item_sunwell_neck(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_item_sunwell_neck_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_sunwell_neck_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ Aldors, Scryers }) && - sFactionStore.LookupEntry(FACTION_ALDOR) && - sFactionStore.LookupEntry(FACTION_SCRYERS); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetActor()->GetTypeId() != TYPEID_PLAYER) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Player* player = eventInfo.GetActor()->ToPlayer(); - Unit* target = eventInfo.GetProcTarget(); - - // Aggression checks are in the spell system... just cast and forget - if (player->GetReputationRank(FACTION_ALDOR) == REP_EXALTED) - player->CastSpell(target, Aldors, true, nullptr, aurEff); - - if (player->GetReputationRank(FACTION_SCRYERS) == REP_EXALTED) - player->CastSpell(target, Scryers, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_item_sunwell_neck_AuraScript::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_item_sunwell_neck_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_sunwell_neck_AuraScript(); - } -}; - -enum ZandalarianCharms -{ - SPELL_UNSTABLE_POWER_AURA_STACK = 24659, - SPELL_RESTLESS_STRENGTH_AURA_STACK = 24662 -}; - -// Item - 19950: Zandalarian Hero Charm -// 24658 - Unstable Power - -// Item - 19949: Zandalarian Hero Medallion -// 24661 - Restless Strength -class spell_item_zandalarian_charm : public SpellScriptLoader -{ -public: - spell_item_zandalarian_charm(char const* ScriptName, uint32 SpellId) : SpellScriptLoader(ScriptName), _spellId(SpellId) { } - - class spell_item_zandalarian_charm_AuraScript : public AuraScript - { - friend class spell_item_zandalarian_charm; - spell_item_zandalarian_charm_AuraScript(uint32 SpellId) : AuraScript(), _spellId(SpellId) { } - - PrepareAuraScript(spell_item_zandalarian_charm_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ _spellId }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - if (spellInfo->Id != m_scriptSpellId) - return true; - - return false; - } - - void HandleStackDrop(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - GetTarget()->RemoveAuraFromStack(_spellId); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_item_zandalarian_charm_AuraScript::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_item_zandalarian_charm_AuraScript::HandleStackDrop, EFFECT_0, SPELL_AURA_DUMMY); - } - - uint32 _spellId; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_item_zandalarian_charm_AuraScript(_spellId); - } - -private: - uint32 _spellId; -}; - -class spell_item_blood_draining_enchant : public AuraScript -{ - PrepareAuraScript(spell_item_blood_draining_enchant); - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (!eventInfo.GetActionTarget() || !eventInfo.GetDamageInfo() || (eventInfo.GetActionTarget()->GetHealth() - eventInfo.GetDamageInfo()->GetDamage()) >= eventInfo.GetActionTarget()->CountPctFromMaxHealth(35)) - { - return; - } - - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/)) - { - int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); - eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(64569 /*SPELL_BLOOD_RESERVE*/); - int32 basepoints = spellInfo->Effects[EFFECT_0].CalcValue() * this->GetStackAmount(); - eventInfo.GetActionTarget()->CastCustomSpell(spellInfo->Id, SPELLVALUE_BASE_POINT0, basepoints, eventInfo.GetActionTarget(), true); - eventInfo.GetActionTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id); // Remove rest auras - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_item_blood_draining_enchant::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - class spell_item_snowman : public SpellScript { PrepareSpellScript(spell_item_snowman); @@ -5137,43 +3851,6 @@ void AddSC_item_spell_scripts() RegisterSpellScript(spell_item_recall); RegisterSpellScript(spell_item_wraith_scythe_drain_life); RegisterSpellScript(spell_item_mirrens_drinking_hat); - RegisterSpellScript(spell_item_soul_preserver); - RegisterSpellScript(spell_item_death_choice); - new spell_item_trinket_stack("spell_item_lightning_capacitor", SPELL_LIGHTNING_CAPACITOR_STACK, SPELL_LIGHTNING_CAPACITOR_TRIGGER); - new spell_item_trinket_stack("spell_item_thunder_capacitor", SPELL_THUNDER_CAPACITOR_STACK, SPELL_THUNDER_CAPACITOR_TRIGGER); - new spell_item_trinket_stack("spell_item_toc25_normal_caster_trinket", SPELL_TOC25_CASTER_TRINKET_NORMAL_STACK, SPELL_TOC25_CASTER_TRINKET_NORMAL_TRIGGER); - new spell_item_trinket_stack("spell_item_toc25_heroic_caster_trinket", SPELL_TOC25_CASTER_TRINKET_HEROIC_STACK, SPELL_TOC25_CASTER_TRINKET_HEROIC_TRIGGER); - RegisterSpellScript(spell_item_darkmoon_card_greatness); - RegisterSpellScript(spell_item_charm_witch_doctor); - RegisterSpellScript(spell_item_mana_drain); - RegisterSpellScript(spell_item_alchemists_stone); - new spell_item_anger_capacitor<8>("spell_item_tiny_abomination_in_a_jar"); - new spell_item_anger_capacitor<7>("spell_item_tiny_abomination_in_a_jar_hero"); - RegisterSpellScript(spell_item_aura_of_madness); - RegisterSpellScript(spell_item_dementia); - RegisterSpellScript(spell_item_deadly_precision); - RegisterSpellScript(spell_item_deadly_precision_dummy); - new spell_item_deathbringers_will("spell_item_deathbringers_will_normal"); - new spell_item_deathbringers_will("spell_item_deathbringers_will_heroic"); - RegisterSpellScript(spell_item_discerning_eye_beast_dummy); - RegisterSpellScript(spell_item_frozen_shadoweave); - RegisterSpellScript(spell_item_healing_touch_refund); - new spell_item_heartpierce("spell_item_heartpierce"); - new spell_item_heartpierce("spell_item_heartpierce_hero"); - RegisterSpellScript(spell_item_crystal_spire_of_karabor); - RegisterSpellScript(spell_item_mark_of_conquest); - RegisterSpellScript(spell_item_persistent_shield); - RegisterSpellScript(spell_item_pet_healing); - RegisterSpellScript(spell_item_swift_hand_justice_dummy); - RegisterSpellScript(spell_item_totem_of_flowing_water); - new spell_item_shard_of_the_scale("spell_item_purified_shard_of_the_scale"); - new spell_item_shard_of_the_scale("spell_item_shiny_shard_of_the_scale"); - new spell_item_sunwell_neck("spell_item_sunwell_exalted_caster_neck"); - new spell_item_sunwell_neck("spell_item_sunwell_exalted_melee_neck"); - new spell_item_sunwell_neck("spell_item_sunwell_exalted_tank_neck"); - new spell_item_sunwell_neck("spell_item_sunwell_exalted_healer_neck"); - new spell_item_zandalarian_charm("spell_item_unstable_power", SPELL_UNSTABLE_POWER_AURA_STACK); - new spell_item_zandalarian_charm("spell_item_restless_strength", SPELL_RESTLESS_STRENGTH_AURA_STACK); RegisterSpellScript(spell_item_snowman); RegisterSpellScript(spell_item_freeze_rookery_egg); } diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index f2e32797a..699ae8ff4 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -31,11 +31,12 @@ enum MageSpells { - SPELL_MAGE_BLAZING_SPEED = 31643, + // Ours SPELL_MAGE_BURNOUT_TRIGGER = 44450, SPELL_MAGE_IMPROVED_BLIZZARD_CHILLED = 12486, SPELL_MAGE_COMBUSTION = 11129, + // Theirs SPELL_MAGE_COLD_SNAP = 11958, SPELL_MAGE_FOCUS_MAGIC_PROC = 54648, SPELL_MAGE_FROST_WARDING_R1 = 11189, @@ -54,49 +55,9 @@ enum MageSpells SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907, SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126, - - SPELL_MAGE_CHILLED = 12484, - SPELL_MAGE_MANA_SURGE = 37445, - SPELL_MAGE_MAGIC_ABSORPTION_MANA = 29442, - SPELL_MAGE_ARCANE_POTENCY_RANK_1 = 57529, - SPELL_MAGE_ARCANE_POTENCY_RANK_2 = 57531, - SPELL_MAGE_HOT_STREAK_PROC = 48108, - SPELL_MAGE_ARCANE_SURGE = 37436, - SPELL_MAGE_COMBUSTION_PROC = 28682, - SPELL_MAGE_EMPOWERED_FIRE_PROC = 67545, - SPELL_MAGE_T10_2P_BONUS = 70752, - SPELL_MAGE_T10_2P_BONUS_EFFECT = 70753, - SPELL_MAGE_T8_4P_BONUS = 64869, - SPELL_MAGE_MISSILE_BARRAGE = 44401, - SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA = 44544, SPELL_MAGE_FINGERS_OF_FROST = 44543 }; -// -31641 - Blazing Speed -class spell_mage_blazing_speed : public AuraScript -{ - PrepareAuraScript(spell_mage_blazing_speed); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_BLAZING_SPEED }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (Unit* target = eventInfo.GetActionTarget()) - { - target->CastSpell(target, SPELL_MAGE_BLAZING_SPEED, true, nullptr, aurEff); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_blazing_speed::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - class spell_mage_arcane_blast : public SpellScript { PrepareSpellScript(spell_mage_arcane_blast); @@ -139,7 +100,7 @@ class spell_mage_burning_determination : public AuraScript return false; // Xinef: immuned effect should just eat charge - if (eventInfo.GetHitMask() & PROC_HIT_IMMUNE) + if (eventInfo.GetHitMask() & PROC_EX_IMMUNE) { eventInfo.GetActionTarget()->RemoveAurasDueToSpell(54748); return false; @@ -154,10 +115,10 @@ class spell_mage_burning_determination : public AuraScript return true; } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); - GetUnitOwner()->CastSpell(GetUnitOwner(), 54748, true, nullptr, aurEff); + GetUnitOwner()->CastSpell(GetUnitOwner(), 54748, true); } void Register() override @@ -972,349 +933,6 @@ class spell_mage_summon_water_elemental : public SpellScript } }; -// -31571 - Arcane Potency -class spell_mage_arcane_potency : public AuraScript -{ - PrepareAuraScript(spell_mage_arcane_potency); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_MAGE_ARCANE_POTENCY_RANK_1, - SPELL_MAGE_ARCANE_POTENCY_RANK_2 - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static uint32 const triggerSpell[2] = { SPELL_MAGE_ARCANE_POTENCY_RANK_1, SPELL_MAGE_ARCANE_POTENCY_RANK_2 }; - - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - uint32 spellId = triggerSpell[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_arcane_potency::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 11129 - Combustion -class spell_mage_combustion : public AuraScript -{ - PrepareAuraScript(spell_mage_combustion); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_COMBUSTION_PROC }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - // Do not take charges, add a stack of crit buff - if (!(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)) - { - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_COMBUSTION_PROC, true); - return false; - } - - return true; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_mage_combustion::CheckProc); - } -}; - -// -11185 - Improved Blizzard -class spell_mage_imp_blizzard : public AuraScript -{ - PrepareAuraScript(spell_mage_imp_blizzard); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_CHILLED }); - } - - void HandleChill(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - uint32 triggerSpellId = sSpellMgr->GetSpellWithRank(SPELL_MAGE_CHILLED, GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), triggerSpellId, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_imp_blizzard::HandleChill, EFFECT_0, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - } -}; - -// 37447 - Improved Mana Gems -// 61062 - Improved Mana Gems -class spell_mage_imp_mana_gems : public AuraScript -{ - PrepareAuraScript(spell_mage_imp_mana_gems); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_MANA_SURGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell((Unit*)nullptr, SPELL_MAGE_MANA_SURGE, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_imp_mana_gems::HandleProc, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - } -}; - -// -31656 - Empowered Fire -class spell_mage_empowered_fire : public AuraScript -{ - PrepareAuraScript(spell_mage_empowered_fire); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_EMPOWERED_FIRE_PROC }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - if (spellInfo->Id == SPELL_MAGE_IGNITE) - return true; - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - - Unit* target = GetTarget(); - int32 bp0 = int32(CalculatePct(target->GetCreateMana(), aurEff->GetAmount())); - target->CastCustomSpell(SPELL_MAGE_EMPOWERED_FIRE_PROC, SPELLVALUE_BASE_POINT0, bp0, target, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_mage_empowered_fire::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_mage_empowered_fire::HandleProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER); - } -}; - -// 74396 - Fingers of Frost -class spell_mage_fingers_of_frost : public AuraScript -{ - PrepareAuraScript(spell_mage_fingers_of_frost); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA }); - } - - void HandleDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->RemoveAuraFromStack(GetId()); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAurasDueToSpell(SPELL_MAGE_FINGERS_OF_FROST_AURASTATE_AURA); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost::HandleDummy, EFFECT_0, SPELL_AURA_DUMMY); - AfterEffectRemove += AuraEffectRemoveFn(spell_mage_fingers_of_frost::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } -}; - -// 48108 - Hot Streak -// 57761 - Fireball! -class spell_mage_gen_extra_effects : public AuraScript -{ - PrepareAuraScript(spell_mage_gen_extra_effects); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_MAGE_T10_2P_BONUS, - SPELL_MAGE_T10_2P_BONUS_EFFECT, - SPELL_MAGE_T8_4P_BONUS - }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - Unit* caster = eventInfo.GetActor(); - // Prevent double proc for Arcane missiles - if (caster == eventInfo.GetProcTarget()) - return false; - - // Proc chance is unknown, we'll just use dummy aura amount - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_MAGE_T8_4P_BONUS, EFFECT_0)) - if (roll_chance_i(aurEff->GetAmount())) - return false; - - return true; - } - - void HandleProc(ProcEventInfo& eventInfo) - { - Unit* caster = eventInfo.GetActor(); - - if (caster->HasAura(SPELL_MAGE_T10_2P_BONUS)) - caster->CastSpell((Unit*)nullptr, SPELL_MAGE_T10_2P_BONUS_EFFECT, true); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_mage_gen_extra_effects::CheckProc); - OnProc += AuraProcFn(spell_mage_gen_extra_effects::HandleProc); - } -}; - -// 56375 - Glyph of Polymorph -class spell_mage_glyph_of_polymorph : public AuraScript -{ - PrepareAuraScript(spell_mage_glyph_of_polymorph); - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* target = eventInfo.GetProcTarget(); - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, ObjectGuid::Empty, target->GetAura(32409)); // SW:D shall not be removed. - target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); - target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_polymorph::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 56374 - Glyph of Icy Veins -class spell_mage_glyph_of_icy_veins : public AuraScript -{ - PrepareAuraScript(spell_mage_glyph_of_icy_veins); - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - caster->RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, ObjectGuid::Empty, 0, true, false); - caster->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_glyph_of_icy_veins::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -44445 - Hot Streak -class spell_mage_hot_streak : public AuraScript -{ - PrepareAuraScript(spell_mage_hot_streak); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_HOT_STREAK_PROC }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - AuraEffect* counter = GetEffect(EFFECT_1); - if (!counter) - return; - - // Count spell criticals in a row in second aura - if (eventInfo.GetHitMask() & PROC_HIT_CRITICAL) - { - counter->SetAmount(counter->GetAmount() * 2); - if (counter->GetAmount() < 100) // not enough - return; - - // roll chance - if (!roll_chance_i(aurEff->GetAmount())) - return; - - Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_MAGE_HOT_STREAK_PROC, true, nullptr, aurEff); - } - - // reset counter - counter->SetAmount(25); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_hot_streak::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -29441 - Magic Absorption -class spell_mage_magic_absorption : public AuraScript -{ - PrepareAuraScript(spell_mage_magic_absorption); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MAGE_MAGIC_ABSORPTION_MANA }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActionTarget(); - int32 bp = CalculatePct(static_cast(caster->GetMaxPower(POWER_MANA)), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_MAGE_MAGIC_ABSORPTION_MANA, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_mage_magic_absorption::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -44404 - Missile Barrage -class spell_mage_missile_barrage : public AuraScript -{ - PrepareAuraScript(spell_mage_missile_barrage); - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - // Arcane Blast - full chance - if (spellInfo->SpellFamilyFlags[0] & 0x20000000) - return true; - - // Rest of spells have half chance - return roll_chance_i(50); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_mage_missile_barrage::CheckProc); - } -}; - #define FingersOfFrostScriptName "spell_mage_fingers_of_frost_proc_aura" class spell_mage_fingers_of_frost_proc_aura : public AuraScript { PrepareAuraScript(spell_mage_fingers_of_frost_proc_aura); @@ -1425,7 +1043,6 @@ class spell_mage_fingers_of_frost_proc : public AuraScript void AddSC_mage_spell_scripts() { - RegisterSpellScript(spell_mage_blazing_speed); RegisterSpellScript(spell_mage_arcane_blast); RegisterSpellScript(spell_mage_burning_determination); RegisterSpellScript(spell_mage_molten_armor); @@ -1447,18 +1064,6 @@ void AddSC_mage_spell_scripts() RegisterSpellScript(spell_mage_master_of_elements); RegisterSpellScript(spell_mage_polymorph_cast_visual); RegisterSpellScript(spell_mage_summon_water_elemental); - RegisterSpellScript(spell_mage_arcane_potency); - RegisterSpellScript(spell_mage_combustion); - RegisterSpellScript(spell_mage_imp_blizzard); - RegisterSpellScript(spell_mage_imp_mana_gems); - RegisterSpellScript(spell_mage_empowered_fire); - RegisterSpellScript(spell_mage_fingers_of_frost); - RegisterSpellScript(spell_mage_gen_extra_effects); - RegisterSpellScript(spell_mage_glyph_of_polymorph); - RegisterSpellScript(spell_mage_glyph_of_icy_veins); - RegisterSpellScript(spell_mage_hot_streak); - RegisterSpellScript(spell_mage_magic_absorption); - RegisterSpellScript(spell_mage_missile_barrage); RegisterSpellScript(spell_mage_fingers_of_frost_proc_aura); RegisterSpellScript(spell_mage_fingers_of_frost_proc); } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index c77f49d8e..a3588b7d1 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -28,7 +28,6 @@ #include "SpellMgr.h" #include "SpellScript.h" #include "UnitAI.h" -#include "GameTime.h" enum PaladinSpells { @@ -39,7 +38,6 @@ enum PaladinSpells SPELL_PALADIN_HOLY_SHOCK_R1 = 20473, SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912, SPELL_PALADIN_HOLY_SHOCK_R1_HEALING = 25914, - SPELL_PALADIN_ILLUMINATION_ENERGIZE = 20272, SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID = 37878, SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN = 37879, @@ -83,50 +81,12 @@ enum PaladinSpells SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364, SPELL_GENERIC_ARENA_DAMPENING = 74410, - SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411, - - SPELL_PALADIN_SACRED_SHIELD = 53601, - SPELL_PALADIN_T9_HOLY_4P_BONUS = 67191, - SPELL_PALADIN_FLASH_OF_LIGHT_PROC = 66922, - - SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC = 68055, - - SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC = 54986, - - SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA = 31930, - SPELL_REPLENISHMENT = 57669, - SPELL_PALADIN_RIGHTEOUS_VENGEANCE_DAMAGE = 61840, - SPELL_PALADIN_SHEATH_OF_LIGHT_HEAL = 54203, - SPELL_PALADIN_SACRED_SHIELD_TRIGGER = 58597, - SPELL_PALADIN_T8_HOLY_4P_BONUS = 64895, - SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 = 21183, - - SPELL_PALADIN_HOLY_POWER_ARMOR = 28790, - SPELL_PALADIN_HOLY_POWER_ATTACK_POWER = 28791, - SPELL_PALADIN_HOLY_POWER_SPELL_POWER = 28793, - SPELL_PALADIN_HOLY_POWER_MP5 = 28795, - - SPELL_PALADIN_HOLY_VENGEANCE = 31803, - SPELL_PALADIN_SEAL_OF_VENGEANCE_DAMAGE = 42463, - SPELL_PALADIN_BLOOD_CORRUPTION = 53742, - SPELL_PALADIN_SEAL_OF_CORRUPTION_DAMAGE = 53739, - - SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA = 31786, - - SPELL_PALADIN_ENDURING_LIGHT = 40471, - SPELL_PALADIN_ENDURING_JUDGEMENT = 40472, - - SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL = 54968, - SPELL_PALADIN_HOLY_MENDING = 64891, - - SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL = 20267, - SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA = 20268 + SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411 }; enum PaladinSpellIcons { - PALADIN_ICON_ID_RETRIBUTION_AURA = 555, - PALADIN_ICON_ID_HAMMER_OF_THE_RIGHTEOUS = 3023 + PALADIN_ICON_ID_RETRIBUTION_AURA = 555 }; class spell_pal_seal_of_command_aura : public AuraScript @@ -258,6 +218,13 @@ class spell_pal_sacred_shield_base : public AuraScript } } + bool CheckProc(ProcEventInfo& eventInfo) + { + HealInfo* healinfo = eventInfo.GetHealInfo(); + DamageInfo* damageinfo = eventInfo.GetDamageInfo(); + return !(eventInfo.GetHitMask() & PROC_EX_INTERNAL_HOT) && ((healinfo && healinfo->GetHeal() > 0) || (damageinfo && damageinfo->GetDamage() > 0)); + } + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); @@ -313,6 +280,7 @@ class spell_pal_sacred_shield_base : public AuraScript void Register() override { DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_sacred_shield_base::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY); + DoCheckProc += AuraCheckProcFn(spell_pal_sacred_shield_base::CheckProc); OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_base::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; @@ -870,51 +838,6 @@ class spell_pal_holy_shock : public SpellScript } }; -// -20210 - Illumination -class spell_pal_illumination : public AuraScript -{ - PrepareAuraScript(spell_pal_illumination); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_HOLY_SHOCK_R1_HEALING, SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELL_PALADIN_HOLY_SHOCK_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - // this script is valid only for the Holy Shock procs of illumination - if (eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetSpellInfo()) - { - SpellInfo const* originalSpell = nullptr; - - // if proc comes from the Holy Shock heal, need to get mana cost of original spell - else it's the original heal itself - if (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[1] & 0x00010000) - { - originalSpell = sSpellMgr->GetSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1, eventInfo.GetHealInfo()->GetSpellInfo()->GetRank())); - } - else - { - originalSpell = eventInfo.GetHealInfo()->GetSpellInfo(); - } - - if (originalSpell && aurEff->GetSpellInfo()) - { - Unit* target = eventInfo.GetActor(); // Paladin is the target of the energize - - uint32 bp = CalculatePct(originalSpell->CalcPowerCost(target, originalSpell->GetSchoolMask()), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue()); - target->CastCustomSpell(SPELL_PALADIN_ILLUMINATION_ENERGIZE, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); - } - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_illumination::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 53407 - Judgement of Justice // 20271 - Judgement of Light // 53408 - Judgement of Wisdom @@ -1120,7 +1043,7 @@ class spell_pal_seal_of_righteousness : public AuraScript return false; } - return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_HIT_ABSORB)); + return target->IsAlive() && !eventInfo.GetTriggerAuraSpell() && (damageInfo->GetDamage() || (eventInfo.GetHitMask() & PROC_EX_ABSORB)); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) @@ -1148,598 +1071,6 @@ class spell_pal_seal_of_righteousness : public AuraScript } }; -// -31871 - Divine Purpose -class spell_pal_divine_purpose : public AuraScript -{ - PrepareAuraScript(spell_pal_divine_purpose); - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (!roll_chance_i(aurEff->GetAmount())) - return; - - eventInfo.GetProcTarget()->RemoveAurasWithMechanic(1 << MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_divine_purpose::HandleProc, EFFECT_2, SPELL_AURA_DUMMY); - } -}; - -// 54939 - Glyph of Divinity -class spell_pal_glyph_of_divinity : public AuraScript -{ - PrepareAuraScript(spell_pal_glyph_of_divinity); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC }); - } - - void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - // Lay on Hands (Rank 1) does not have mana effect - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->Effects[EFFECT_1].Effect != SPELL_EFFECT_ENERGIZE) - return; - - Unit* caster = eventInfo.GetActor(); - if (caster == eventInfo.GetProcTarget()) - return; - - int32 mana = spellInfo->Effects[EFFECT_1].CalcValue() * 2; - caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_DIVINITY_PROC, SPELLVALUE_BASE_POINT1, mana, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_divinity::OnProc, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER); - } -}; - -// 54937 - Glyph of Holy Light (dummy aura) -class spell_pal_glyph_of_holy_light_dummy : public AuraScript -{ - PrepareAuraScript(spell_pal_glyph_of_holy_light_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - - caster->CastCustomSpell(SPELL_PALADIN_GLYPH_OF_HOLY_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_glyph_of_holy_light_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -20335 - Heart of the Crusader -class spell_pal_heart_of_the_crusader : public AuraScript -{ - PrepareAuraScript(spell_pal_heart_of_the_crusader); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HEART_OF_THE_CRUSADER_EFF_R1, GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_heart_of_the_crusader::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -20234 - Improved Lay on Hands -class spell_pal_improved_lay_of_hands : public AuraScript -{ - PrepareAuraScript(spell_pal_improved_lay_of_hands); - - bool Validate(SpellInfo const* spellInfo) override - { - return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActionTarget(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, GetTarget()->GetGUID()); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_improved_lay_of_hands::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// -53569 - Infusion of Light -class spell_pal_infusion_of_light : public AuraScript -{ - PrepareAuraScript(spell_pal_infusion_of_light); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PALADIN_SACRED_SHIELD, - SPELL_PALADIN_T9_HOLY_4P_BONUS, - SPELL_PALADIN_FLASH_OF_LIGHT_PROC - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - { - // Flash of Light HoT on Flash of Light when Sacred Shield active - if (spellInfo->SpellFamilyFlags[0] & 0x40000000 && spellInfo->SpellIconID == 242) - { - PreventDefaultAction(); - - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - Unit* procTarget = eventInfo.GetActionTarget(); - if (procTarget && procTarget->HasAura(SPELL_PALADIN_SACRED_SHIELD)) - { - Unit* target = GetTarget(); - int32 duration = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_FLASH_OF_LIGHT_PROC)->GetMaxDuration() / 1000; - int32 pct = GetSpellInfo()->Effects[EFFECT_2].CalcValue(); - int32 bp0 = CalculatePct(healInfo->GetHeal() / duration, pct); - - // Item - Paladin T9 Holy 4P Bonus - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_PALADIN_T9_HOLY_4P_BONUS, 0)) - AddPct(bp0, aurEff->GetAmount()); - - target->CastCustomSpell(SPELL_PALADIN_FLASH_OF_LIGHT_PROC, SPELLVALUE_BASE_POINT0, bp0, procTarget, true, nullptr, aurEff); - } - } - // but should not proc on non-critical Holy Shocks - else if ((spellInfo->SpellFamilyFlags[0] & 0x200000 || spellInfo->SpellFamilyFlags[1] & 0x10000) && !(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)) - PreventDefaultAction(); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_infusion_of_light::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 40470 - Paladin Tier 6 Trinket -class spell_pal_item_t6_trinket : public AuraScript -{ - PrepareAuraScript(spell_pal_item_t6_trinket); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PALADIN_ENDURING_LIGHT, - SPELL_PALADIN_ENDURING_JUDGEMENT - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - uint32 spellId; - int32 chance; - - // Holy Light & Flash of Light - if (spellInfo->SpellFamilyFlags[0] & 0xC0000000) - { - spellId = SPELL_PALADIN_ENDURING_LIGHT; - chance = 15; - } - // Judgements - else if (spellInfo->SpellFamilyFlags[0] & 0x00800000) - { - spellId = SPELL_PALADIN_ENDURING_JUDGEMENT; - chance = 50; - } - else - return; - - if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 20185 - Judgement of Light -class spell_pal_judgement_of_light_heal : public AuraScript -{ - PrepareAuraScript(spell_pal_judgement_of_light_heal); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetProcTarget(); - int32 amount = static_cast(caster->CountPctFromMaxHealth(aurEff->GetAmount())); - - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_LIGHT_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_light_heal::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 20186 - Judgement of Wisdom -class spell_pal_judgement_of_wisdom_mana : public AuraScript -{ - PrepareAuraScript(spell_pal_judgement_of_wisdom_mana); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetProcTarget()->getPowerType() == POWER_MANA; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetProcTarget(); - int32 amount = CalculatePct(static_cast(caster->GetCreateMana()), aurEff->GetAmount()); - - caster->CastCustomSpell(SPELL_PALADIN_JUDGEMENT_OF_WISDOM_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pal_judgement_of_wisdom_mana::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pal_judgement_of_wisdom_mana::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -53695 - Judgements of the Just -class spell_pal_judgements_of_the_just : public AuraScript -{ - PrepareAuraScript(spell_pal_judgements_of_the_just); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC }); - } - - void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - GetTarget()->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_JUDGEMENTS_OF_THE_JUST_PROC, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_just::OnProc, EFFECT_0, SPELL_AURA_ADD_FLAT_MODIFIER); - } -}; - -// -31876 - Judgements of the Wise -class spell_pal_judgements_of_the_wise : public AuraScript -{ - PrepareAuraScript(spell_pal_judgements_of_the_wise); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_REPLENISHMENT, - SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - caster->CastSpell((Unit*)nullptr, SPELL_PALADIN_JUDGEMENTS_OF_THE_WISE_MANA, true, nullptr, aurEff); - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_judgements_of_the_wise::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 53601 - Sacred Shield (dummy) -class spell_pal_sacred_shield_dummy : public AuraScript -{ - PrepareAuraScript(spell_pal_sacred_shield_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PALADIN_SACRED_SHIELD_TRIGGER, - SPELL_PALADIN_T8_HOLY_4P_BONUS - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = GetCaster(); - if (!caster) - return; - - TimePoint now = GameTime::Now(); - if (_cooldownEnd > now) - return; - - Seconds cooldown(aurEff->GetAmount()); - if (AuraEffect const* bonus = caster->GetAuraEffect(SPELL_PALADIN_T8_HOLY_4P_BONUS, EFFECT_0, caster->GetGUID())) - cooldown = Seconds(bonus->GetAmount()); - - _cooldownEnd = now + cooldown; - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_PALADIN_SACRED_SHIELD_TRIGGER, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_sacred_shield_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - - // Cooldown tracking can't be done in DB because of T8 bonus - TimePoint _cooldownEnd = std::chrono::steady_clock::time_point::min(); -}; - -// 31801 - Seal of Vengeance -// 53736 - Seal of Corruption -template -class spell_pal_seal_of_vengeance : public SpellScriptLoader -{ -public: - spell_pal_seal_of_vengeance(char const* ScriptName) : SpellScriptLoader(ScriptName) { } - - template - class spell_pal_seal_of_vengeance_AuraScript : public AuraScript - { - PrepareAuraScript(spell_pal_seal_of_vengeance_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - DoTSpell, - DamageSpell - }); - } - - /* - When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system). - - 1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..) - 2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided. - - Remember #2 happens regardless of #1 landing, it just requires the initial attack (autos, cs, etc) to land. - - Stack Number % of Weapon Damage % with SotP - 0 0% 0% - 1 6.6% 7.6% - 2 13.2% 15.2% - 3 19.8% 22.8% - 4 26.4% 30.4% - 5 33% 38% - */ - - void HandleApplyDoT(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - if (!(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MELEE_AUTO_ATTACK)) - { - // Patch 3.2.0 Notes: Only auto-attacks and Hammer of the Righteous can place the debuff on the paladin's current target(s). - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->SpellIconID != PALADIN_ICON_ID_HAMMER_OF_THE_RIGHTEOUS) - return; - } - - // don't cast triggered, spell already has SPELL_ATTR4_CAN_CAST_WHILE_CASTING attr - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), DoTSpell, TRIGGERED_NO_PERIODIC_RESET, nullptr, aurEff); - } - - void HandleSeal(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - AuraEffect const* sealDot = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PALADIN, 0x00000000, 0x00000800, 0x00000000, caster->GetGUID()); - if (!sealDot) - return; - - uint8 const stacks = sealDot->GetBase()->GetStackAmount(); - uint8 const maxStacks = sealDot->GetSpellInfo()->StackAmount; - - if (stacks < maxStacks && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS)) - return; - - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(DamageSpell); - int32 amount = spellInfo->Effects[EFFECT_0].CalcValue(); - amount *= stacks; - amount /= maxStacks; - - caster->CastCustomSpell(DamageSpell, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleApplyDoT, EFFECT_0, SPELL_AURA_DUMMY); - OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_vengeance_AuraScript::HandleSeal, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_pal_seal_of_vengeance_AuraScript(); - } -}; - -// 20375 - Seal of Command -// 21084 - Seal of Righteousness -// 31801 - Seal of Vengeance -// 31892 - Seal of Blood -// 33127 - Seal of Command -// 38008 - Seal of Blood -// 41459 - Seal of Blood -// 53720 - Seal of the Martyr -// 53736 - Seal of Corruption -class spell_pal_seals : public AuraScript -{ - PrepareAuraScript(spell_pal_seals); - - // Effect 2 is used by Judgement code, we prevent the proc to avoid console logging of unknown spell trigger - bool CheckDummyProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) - { - return false; - } - - void Register() override - { - DoCheckEffectProc += AuraCheckEffectProcFn(spell_pal_seals::CheckDummyProc, EFFECT_2, SPELL_AURA_DUMMY); - } -}; - -// -31785 - Spiritual Attunement -class spell_pal_spiritual_attunement : public AuraScript -{ - PrepareAuraScript(spell_pal_spiritual_attunement); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - // "when healed by other friendly targets' spells" - if (eventInfo.GetProcTarget() == eventInfo.GetActionTarget()) - return false; - - return eventInfo.GetHealInfo() && eventInfo.GetHealInfo()->GetEffectiveHeal(); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - HealInfo* healInfo = eventInfo.GetHealInfo(); - int32 amount = CalculatePct(static_cast(healInfo->GetEffectiveHeal()), aurEff->GetAmount()); - - eventInfo.GetActionTarget()->CastCustomSpell(SPELL_PALADIN_SPIRITUAL_ATTUNEMENT_MANA, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pal_spiritual_attunement::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pal_spiritual_attunement::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 28789 - Holy Power -class spell_pal_t3_6p_bonus : public AuraScript -{ - PrepareAuraScript(spell_pal_t3_6p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PALADIN_HOLY_POWER_ARMOR, - SPELL_PALADIN_HOLY_POWER_ATTACK_POWER, - SPELL_PALADIN_HOLY_POWER_SPELL_POWER, - SPELL_PALADIN_HOLY_POWER_MP5 - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - uint32 spellId; - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - switch (target->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - spellId = SPELL_PALADIN_HOLY_POWER_MP5; - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - spellId = SPELL_PALADIN_HOLY_POWER_SPELL_POWER; - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - spellId = SPELL_PALADIN_HOLY_POWER_ATTACK_POWER; - break; - case CLASS_WARRIOR: - spellId = SPELL_PALADIN_HOLY_POWER_ARMOR; - break; - default: - return; - } - - caster->CastSpell(target, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pal_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - void AddSC_paladin_spell_scripts() { RegisterSpellAndAuraScriptPair(spell_pal_seal_of_command, spell_pal_seal_of_command_aura); @@ -1760,7 +1091,6 @@ void AddSC_paladin_spell_scripts() RegisterSpellAndAuraScriptPair(spell_pal_hand_of_sacrifice, spell_pal_hand_of_sacrifice_aura); RegisterSpellScript(spell_pal_hand_of_salvation); RegisterSpellScript(spell_pal_holy_shock); - RegisterSpellScript(spell_pal_illumination); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_justice", SPELL_PALADIN_JUDGEMENT_OF_JUSTICE); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_light", SPELL_PALADIN_JUDGEMENT_OF_LIGHT); RegisterSpellScriptWithArgs(spell_pal_judgement, "spell_pal_judgement_of_wisdom", SPELL_PALADIN_JUDGEMENT_OF_WISDOM); @@ -1768,21 +1098,4 @@ void AddSC_paladin_spell_scripts() RegisterSpellScript(spell_pal_lay_on_hands); RegisterSpellScript(spell_pal_righteous_defense); RegisterSpellScript(spell_pal_seal_of_righteousness); - RegisterSpellScript(spell_pal_divine_purpose); - RegisterSpellScript(spell_pal_glyph_of_divinity); - RegisterSpellScript(spell_pal_glyph_of_holy_light_dummy); - RegisterSpellScript(spell_pal_heart_of_the_crusader); - RegisterSpellScript(spell_pal_improved_lay_of_hands); - RegisterSpellScript(spell_pal_infusion_of_light); - RegisterSpellScript(spell_pal_item_t6_trinket); - RegisterSpellScript(spell_pal_judgement_of_light_heal); - RegisterSpellScript(spell_pal_judgement_of_wisdom_mana); - RegisterSpellScript(spell_pal_judgements_of_the_just); - RegisterSpellScript(spell_pal_judgements_of_the_wise); - RegisterSpellScript(spell_pal_sacred_shield_dummy); - new spell_pal_seal_of_vengeance("spell_pal_seal_of_vengeance"); - new spell_pal_seal_of_vengeance("spell_pal_seal_of_corruption"); - RegisterSpellScript(spell_pal_seals); - RegisterSpellScript(spell_pal_spiritual_attunement); - RegisterSpellScript(spell_pal_t3_6p_bonus); } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index e1d9295b9..89624091b 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -31,7 +31,6 @@ enum PriestSpells { - SPELL_PRIEST_BLESSED_RECOVERY_R1 = 27813, SPELL_PRIEST_DIVINE_AEGIS = 47753, SPELL_PRIEST_EMPOWERED_RENEW = 63544, SPELL_PRIEST_GLYPH_OF_CIRCLE_OF_HEALING = 55675, @@ -54,22 +53,7 @@ enum PriestSpells SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411, SPELL_PRIEST_TWIN_DISCIPLINE_R1 = 47586, SPELL_PRIEST_SPIRITUAL_HEALING_R1 = 14898, - SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562, - - SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA = 58227, - SPELL_REPLENISHMENT = 57669, - SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER = 64136, - SPELL_PRIEST_ABOLISH_DISEASE = 552, - SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL = 15290, - SPELL_PRIEST_DIVINE_BLESSING = 40440, - SPELL_PRIEST_DIVINE_WRATH = 40441, - SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL = 56131, - SPELL_PRIEST_ORACULAR_HEAL = 26170, - SPELL_PRIEST_ARMOR_OF_FAITH = 28810, - SPELL_PRIEST_BLESSED_HEALING = 70772, - SPELL_PRIEST_MIND_BLAST_R1 = 8092, - SPELL_PRIEST_SHADOW_WORD_DEATH_R1 = 32379, - SPELL_PRIEST_MIND_FLAY_DAMAGE = 58381 + SPELL_PRIEST_DIVINE_PROVIDENCE_R1 = 47562 }; enum PriestSpellIcons @@ -165,41 +149,6 @@ class spell_pri_shadowfiend_scaling : public AuraScript } }; -// -27811 - Blessed Recovery -class spell_pri_blessed_recovery : public AuraScript -{ - PrepareAuraScript(spell_pri_blessed_recovery); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_BLESSED_RECOVERY_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* dmgInfo = eventInfo.GetDamageInfo(); - if (!dmgInfo || !dmgInfo->GetDamage()) - return; - - Unit* target = eventInfo.GetActionTarget(); - uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_PRIEST_BLESSED_RECOVERY_R1, aurEff->GetSpellInfo()->GetRank()); - SpellInfo const* triggerInfo = sSpellMgr->AssertSpellInfo(triggerSpell); - - int32 bp = CalculatePct(static_cast(dmgInfo->GetDamage()), aurEff->GetAmount()); - - ASSERT(triggerInfo->GetMaxTicks() > 0); - bp /= triggerInfo->GetMaxTicks(); - - target->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_blessed_recovery::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // -34861 - Circle of Healing class spell_pri_circle_of_healing : public SpellScript { @@ -400,6 +349,15 @@ class spell_pri_item_greater_heal_refund : public AuraScript return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY }); } + bool CheckProc(ProcEventInfo& eventInfo) + { + if (HealInfo* healInfo = eventInfo.GetHealInfo()) + if (Unit* healTarget = healInfo->GetTarget()) + if (eventInfo.GetHitMask() & PROC_EX_NO_OVERHEAL && healTarget->IsFullHealth()) + return true; + return false; + } + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); @@ -408,6 +366,7 @@ class spell_pri_item_greater_heal_refund : public AuraScript void Register() override { + DoCheckProc += AuraCheckProcFn(spell_pri_item_greater_heal_refund::CheckProc); OnEffectProc += AuraEffectProcFn(spell_pri_item_greater_heal_refund::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); } }; @@ -563,33 +522,6 @@ class spell_pri_mind_sear : public SpellScript } }; -// -47580 - Pain and Suffering (dummy aura) -class spell_pri_pain_and_suffering_dummy : public SpellScriptLoader -{ -public: - spell_pri_pain_and_suffering_dummy() : SpellScriptLoader("spell_pri_pain_and_suffering_dummy") { } - - class spell_pri_pain_and_suffering_dummy_AuraScript : public AuraScript - { - PrepareAuraScript(spell_pri_pain_and_suffering_dummy_AuraScript); - - bool CheckDummy(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) - { - return false; - } - - void Register() override - { - DoCheckEffectProc += AuraCheckEffectProcFn(spell_pri_pain_and_suffering_dummy_AuraScript::CheckDummy, EFFECT_1, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_pri_pain_and_suffering_dummy_AuraScript; - } -}; - // 47948 - Pain and Suffering (Proc) class spell_pri_pain_and_suffering_proc : public SpellScript { @@ -994,326 +926,9 @@ class spell_pri_mind_control : public AuraScript } }; -// 26169 - Oracle Healing Bonus -class spell_pri_aq_3p_bonus : public AuraScript -{ - PrepareAuraScript(spell_pri_aq_3p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_ORACULAR_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - if (caster == eventInfo.GetProcTarget()) - return; - - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), 10); - caster->CastCustomSpell(SPELL_PRIEST_ORACULAR_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_aq_3p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -64127 - Body and Soul -class spell_pri_body_and_soul : public AuraScript -{ - PrepareAuraScript(spell_pri_body_and_soul); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, - SPELL_PRIEST_ABOLISH_DISEASE - }); - } - - void HandleProcTriggerSpell(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - // Proc only on Power Word: Shield - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || !(spellInfo->SpellFamilyFlags[0] & 0x00000001)) - { - PreventDefaultAction(); - return; - } - } - - void HandleProcDummy(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - // Proc only on self casted abolish disease - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - Unit* caster = eventInfo.GetActor(); - if (spellInfo->Id != SPELL_PRIEST_ABOLISH_DISEASE || caster != eventInfo.GetProcTarget()) - return; - - if (roll_chance_i(aurEff->GetAmount())) - caster->CastSpell(caster, SPELL_PRIEST_BODY_AND_SOUL_POISON_TRIGGER, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcTriggerSpell, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - OnEffectProc += AuraEffectProcFn(spell_pri_body_and_soul::HandleProcDummy, EFFECT_1, SPELL_AURA_DUMMY); - } -}; - -// 55677 - Glyph of Dispel Magic -class spell_pri_glyph_of_dispel_magic : public AuraScript -{ - PrepareAuraScript(spell_pri_glyph_of_dispel_magic); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - // Dispel Magic shares spellfamilyflag with abolish disease - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->SpellIconID != 74) - return; - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - int32 amount = static_cast(target->CountPctFromMaxHealth(aurEff->GetAmount())); - - caster->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_DISPEL_MAGIC_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_dispel_magic::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -47569 - Improved Shadowform -class spell_pri_imp_shadowform : public AuraScript -{ - PrepareAuraScript(spell_pri_imp_shadowform); - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - if (roll_chance_i(aurEff->GetAmount())) - eventInfo.GetActor()->RemoveMovementImpairingAuras(true); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_imp_shadowform::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -15337 - Improved Spirit Tap -class spell_pri_improved_spirit_tap : public AuraScript -{ - PrepareAuraScript(spell_pri_improved_spirit_tap); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PRIEST_SHADOW_WORD_DEATH_R1, - SPELL_PRIEST_MIND_BLAST_R1 - }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - { - if (spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_SHADOW_WORD_DEATH_R1)) || - spellInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_PRIEST_MIND_BLAST_R1))) - return true; - else if (spellInfo->Id == SPELL_PRIEST_MIND_FLAY_DAMAGE) - return roll_chance_i(50); - } - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pri_improved_spirit_tap::CheckProc); - } -}; - -// 40438 - Priest Tier 6 Trinket -class spell_pri_item_t6_trinket : public AuraScript -{ - PrepareAuraScript(spell_pri_item_t6_trinket); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_PRIEST_DIVINE_BLESSING, - SPELL_PRIEST_DIVINE_WRATH - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_HEAL) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_BLESSING, true, nullptr, aurEff); - - if (eventInfo.GetSpellTypeMask() & PROC_SPELL_TYPE_DAMAGE) - caster->CastSpell((Unit*)nullptr, SPELL_PRIEST_DIVINE_WRATH, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 57989 - Shadowfiend Death -class spell_pri_shadowfiend_death : public AuraScript -{ - PrepareAuraScript(spell_pri_shadowfiend_death); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return false; - - Unit* shadowfiend = eventInfo.GetActionTarget(); - if (!shadowfiend->GetOwner()) - return false; - - return shadowfiend->HealthBelowPctDamaged(1, damageInfo->GetDamage()); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActionTarget()->GetOwner(); - caster->CastSpell(caster, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, aurEff, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pri_shadowfiend_death::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pri_shadowfiend_death::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 15286 - Vampiric Embrace -class spell_pri_vampiric_embrace : public AuraScript -{ - PrepareAuraScript(spell_pri_vampiric_embrace); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 selfHeal = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - int32 partyHeal = selfHeal / 5; - Unit* caster = eventInfo.GetActor(); - caster->CastCustomSpell((Unit*)nullptr, SPELL_PRIEST_VAMPIRIC_EMBRACE_HEAL, &partyHeal, &selfHeal, nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_vampiric_embrace::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 28809 - Greater Heal -class spell_pri_t3_4p_bonus : public AuraScript -{ - PrepareAuraScript(spell_pri_t3_4p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_ARMOR_OF_FAITH }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_PRIEST_ARMOR_OF_FAITH, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_pri_t3_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 37594 - Greater Heal Refund -class spell_pri_t5_heal_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_pri_t5_heal_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PRIEST_ITEM_EFFICIENCY }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (HealInfo* healInfo = eventInfo.GetHealInfo()) - if (Unit* healTarget = healInfo->GetTarget()) - if (healInfo->GetEffectiveHeal()) - if (healTarget->GetHealth() >= healTarget->GetMaxHealth()) - return true; - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_PRIEST_ITEM_EFFICIENCY, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_pri_t5_heal_2p_bonus::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_pri_t5_heal_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - void AddSC_priest_spell_scripts() { RegisterSpellScript(spell_pri_shadowfiend_scaling); - RegisterSpellScript(spell_pri_blessed_recovery); RegisterSpellScript(spell_pri_circle_of_healing); RegisterSpellScript(spell_pri_divine_aegis); RegisterSpellScript(spell_pri_divine_hymn); @@ -1326,7 +941,6 @@ void AddSC_priest_spell_scripts() RegisterSpellScript(spell_pri_mana_burn); RegisterSpellScript(spell_pri_mana_leech); RegisterSpellScript(spell_pri_mind_sear); - new spell_pri_pain_and_suffering_dummy(); RegisterSpellScript(spell_pri_pain_and_suffering_proc); RegisterSpellScript(spell_pri_penance); RegisterSpellAndAuraScriptPair(spell_pri_power_word_shield, spell_pri_power_word_shield_aura); @@ -1335,14 +949,4 @@ void AddSC_priest_spell_scripts() RegisterSpellScript(spell_pri_shadow_word_death); RegisterSpellScript(spell_pri_vampiric_touch); RegisterSpellScript(spell_pri_mind_control); - RegisterSpellScript(spell_pri_aq_3p_bonus); - RegisterSpellScript(spell_pri_body_and_soul); - RegisterSpellScript(spell_pri_glyph_of_dispel_magic); - RegisterSpellScript(spell_pri_imp_shadowform); - RegisterSpellScript(spell_pri_improved_spirit_tap); - RegisterSpellScript(spell_pri_item_t6_trinket); - RegisterSpellScript(spell_pri_shadowfiend_death); - RegisterSpellScript(spell_pri_vampiric_embrace); - RegisterSpellScript(spell_pri_t3_4p_bonus); - RegisterSpellScript(spell_pri_t5_heal_2p_bonus); } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index deee9a2a6..bb6b8b9e2 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -42,9 +42,6 @@ enum RogueSpells SPELL_ROGUE_SHIV_TRIGGERED = 5940, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628, - SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER = 63975, - SPELL_ROGUE_QUICK_RECOVERY_ENERGY = 31663, - SPELL_ROGUE_CRIPPLING_POISON = 3409 }; class spell_rog_savage_combat : public AuraScript @@ -129,7 +126,7 @@ class spell_rog_blade_flurry : public AuraScript CustomSpellValues values; values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); - values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_HIT_CRITICAL)); + values.AddSpellMod(SPELLVALUE_FORCED_CRIT_RESULT, int32(eventInfo.GetHitMask() & PROC_EX_CRITICAL_HIT)); GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, values, procTarget, TRIGGERED_FULL_MASK, nullptr, aurEff); } } @@ -641,13 +638,13 @@ class spell_rog_tricks_of_the_trade : public AuraScript return _redirectTarget; } - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); Unit* target = GetTarget(); - target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true, nullptr, aurEff); - target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true, nullptr, aurEff); + target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true); + target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true); Remove(AURA_REMOVE_BY_DEFAULT); // maybe handle by proc charges } @@ -678,154 +675,6 @@ class spell_rog_tricks_of_the_trade_proc : public AuraScript } }; -// -51664 - Cut to the Chase -class spell_rog_cut_to_the_chase : public AuraScript -{ - PrepareAuraScript(spell_rog_cut_to_the_chase); - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - // "refresh your Slice and Dice duration to its 5 combo point maximum" - Unit* caster = eventInfo.GetActor(); - // lookup Slice and Dice - if (AuraEffect const* snd = caster->GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x00040000, 0x00000000, 0x00000000, caster->GetGUID())) - { - // Max 5 cp duration - uint32 countMax = snd->GetSpellInfo()->GetMaxDuration(); - - snd->GetBase()->SetDuration(countMax, true); - snd->GetBase()->SetMaxDuration(snd->GetBase()->GetDuration()); - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_rog_cut_to_the_chase::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -51625 - Deadly Brew -class spell_rog_deadly_brew : public AuraScript -{ - PrepareAuraScript(spell_rog_deadly_brew); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_ROGUE_CRIPPLING_POISON }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_CRIPPLING_POISON, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_rog_deadly_brew::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -31244 - Quick Recovery -class spell_rog_quick_recovery : public AuraScript -{ - PrepareAuraScript(spell_rog_quick_recovery); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_ROGUE_QUICK_RECOVERY_ENERGY }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - Unit* caster = eventInfo.GetActor(); - int32 amount = CalculatePct(spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_ROGUE_QUICK_RECOVERY_ENERGY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_rog_quick_recovery::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 56800 - Glyph of Backstab (dummy) -class spell_rog_glyph_of_backstab : public AuraScript -{ - PrepareAuraScript(spell_rog_glyph_of_backstab); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_rog_glyph_of_backstab::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -13983 - Setup -class spell_rog_setup : public AuraScript -{ - PrepareAuraScript(spell_rog_setup); - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (Player* target = GetTarget()->ToPlayer()) - if (eventInfo.GetActor() == target->GetSelectedUnit()) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_rog_setup::CheckProc); - } -}; - -// -51627 - Turn the Tables -class spell_rog_turn_the_tables : public AuraScript -{ - PrepareAuraScript(spell_rog_turn_the_tables); - - bool Validate(SpellInfo const* spellInfo) override - { - return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - - Unit* caster = GetCaster(); - if (!caster) - return; - - Unit* target = GetTarget(); - target->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true, nullptr, aurEff, caster->GetGUID()); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_rog_turn_the_tables::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - void AddSC_rogue_spell_scripts() { RegisterSpellScript(spell_rog_savage_combat); @@ -841,10 +690,4 @@ void AddSC_rogue_spell_scripts() RegisterSpellScript(spell_rog_shiv); RegisterSpellScript(spell_rog_tricks_of_the_trade); RegisterSpellScript(spell_rog_tricks_of_the_trade_proc); - RegisterSpellScript(spell_rog_cut_to_the_chase); - RegisterSpellScript(spell_rog_deadly_brew); - RegisterSpellScript(spell_rog_quick_recovery); - RegisterSpellScript(spell_rog_glyph_of_backstab); - RegisterSpellScript(spell_rog_setup); - RegisterSpellScript(spell_rog_turn_the_tables); } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 0c4500695..6977a0824 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -31,7 +31,6 @@ enum ShamanSpells { - SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY = 52759, SPELL_SHAMAN_GLYPH_OF_FERAL_SPIRIT = 63271, SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC = 52752, SPELL_SHAMAN_BIND_SIGHT = 6277, @@ -50,10 +49,8 @@ enum ShamanSpells SPELL_SHAMAN_ITEM_MANA_SURGE = 23571, SPELL_SHAMAN_LAVA_FLOWS_R1 = 51480, SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 64694, - SPELL_SHAMAN_LIGHTNING_SHIELD_R1 = 26364, SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE = 52032, SPELL_SHAMAN_MANA_TIDE_TOTEM = 39609, - SPELL_SHAMAN_NATURE_GUARDIAN = 31616, SPELL_SHAMAN_SATED = 57724, SPELL_SHAMAN_STORM_EARTH_AND_FIRE = 51483, SPELL_SHAMAN_TOTEM_EARTHBIND_EARTHGRAB = 64695, @@ -62,66 +59,13 @@ enum ShamanSpells SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042, SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554, SPELL_SHAMAN_STORMSTRIKE = 17364, - SPELL_SHAMAN_LAVA_LASH = 60103, - SPELL_SHAMAN_TOTEMIC_MASTERY = 38437, - SPELL_SHAMAN_TIDAL_FORCE_CRIT = 55166, - SPELL_SHAMAN_TOTEMIC_POWER_MP5 = 28824, - SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER = 28825, - SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER = 28826, - SPELL_SHAMAN_TOTEMIC_POWER_ARMOR = 28827, - SPELL_SHAMAN_WINDFURY_WEAPON_R1 = 8232, - SPELL_SHAMAN_WINDFURY_ATTACK_MH = 25504, - SPELL_SHAMAN_WINDFURY_ATTACK_OH = 33750, - SPELL_SHAMAN_ENERGY_SURGE = 40465, - SPELL_SHAMAN_POWER_SURGE = 40466, - SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL = 55533, - SPELL_SHAMAN_SPIRIT_HUNT_HEAL = 58879, - SPELL_SHAMAN_ELECTRIFIED = 64930, - SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE = 71824, - SPELL_SHAMAN_CHAINED_HEAL = 70809, - SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER = 63283, - SPELL_SHAMAN_FREEZE = 63685, - SPELL_SHAMAN_FLAMETONGUE_ATTACK = 10444, - SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1 = 45284, - SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1 = 45297, - SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 = 26364, - SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC = 30824, - SPELL_SHAMAN_MAELSTROM_POWER = 70831, - SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS = 70832 + SPELL_SHAMAN_LAVA_LASH = 60103 }; enum ShamanSpellIcons { SHAMAN_ICON_ID_RESTORATIVE_TOTEMS = 338, - SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087, - SHAMAN_ICON_ID_TOTEM_OF_WRATH = 2019 -}; - -// -51556 - Ancestral Awakening -class spell_sha_ancestral_awakening : public AuraScript -{ - PrepareAuraScript(spell_sha_ancestral_awakening); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - eventInfo.GetActor()->CastCustomSpell(SPELL_SHAMAN_ANCESTRAL_AWAKENING_DUMMY, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_ancestral_awakening::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } + SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087 }; class spell_sha_totem_of_wrath : public SpellScript @@ -199,30 +143,24 @@ class spell_sha_t10_restoration_4p_bonus : public AuraScript } }; -// 38443 - Totemic Mastery (Tier 6 - 2P) class spell_sha_totemic_mastery : public AuraScript { PrepareAuraScript(spell_sha_totemic_mastery); - bool Validate(SpellInfo const* /*spellInfo*/) override + void HandlePeriodic(AuraEffect const* /*aurEff*/) { - return ValidateSpellInfo({ SPELL_SHAMAN_TOTEMIC_MASTERY }); - } + PreventDefaultAction(); - void HandleDummy(AuraEffect const* aurEff) - { - Unit* target = GetTarget(); - for (uint8 i = SUMMON_TYPE_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i) - if (!target->m_SummonSlot[i]) + for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) + if (!GetTarget()->m_SummonSlot[i]) return; - target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, aurEff); - PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), 38437, true); } void Register() override { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_totemic_mastery::HandleDummy, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_totemic_mastery::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; @@ -834,218 +772,6 @@ class spell_sha_flame_shock : public AuraScript } }; -// -10400 - Flametongue Weapon (Passive) -class spell_sha_flametongue_weapon : public AuraScript -{ - PrepareAuraScript(spell_sha_flametongue_weapon); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_FLAMETONGUE_ATTACK }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - Player* player = eventInfo.GetActor()->ToPlayer(); - if (!player) - return false; - - Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID()); - if (!item || !item->IsEquipped()) - return false; - - WeaponAttackType attType = static_cast(player->GetAttackBySlot(item->GetSlot())); - if (attType != BASE_ATTACK && attType != OFF_ATTACK) - return false; - - if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) || - ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK))) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Player* player = eventInfo.GetActor()->ToPlayer(); - Unit* target = eventInfo.GetProcTarget(); - WeaponAttackType attType = BASE_ATTACK; - if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK) - attType = OFF_ATTACK; - - Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); - - float const basePoints = GetSpellInfo()->Effects[aurEff->GetEffIndex()].CalcValue(); - - // Flametongue max damage is normalized based on a 4.0 speed weapon - // Tooltip says max damage = BasePoints / 25, so BasePoints / 25 / 4 to get base damage per 1.0s AS - float fireDamage = basePoints / 100.0f; - float const attackSpeed = player->GetAttackTime(attType) / 1000.f; - fireDamage *= attackSpeed; - - // clip value between (BasePoints / 77) and (BasePoints / 25) as the tooltip indicates - RoundToInterval(fireDamage, basePoints / 77.0f, basePoints / 25.0f); - - // Calculate Spell Power scaling - float spellPowerBonus = player->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE) + target->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_FIRE); - float const spCoeff = 0.03811f; - spellPowerBonus *= spCoeff * attackSpeed; - - // All done, now proc damage - int32 amount = static_cast(fireDamage + spellPowerBonus); - player->CastCustomSpell(SPELL_SHAMAN_FLAMETONGUE_ATTACK, SPELLVALUE_BASE_POINT0, amount, target, true, item, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_sha_flametongue_weapon::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_flametongue_weapon::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -63373 - Frozen Power -class spell_sha_frozen_power : public AuraScript -{ - PrepareAuraScript(spell_sha_frozen_power); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_FREEZE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - if (!roll_chance_i(aurEff->GetAmount())) - return; - - Unit* caster = eventInfo.GetActor(); - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_FREEZE); - float minDistance(spellInfo->GetEffect(EFFECT_0).CalcValue(caster)); - - Unit* target = eventInfo.GetProcTarget(); - if (caster->GetDistance(target) < minDistance) - return; - - caster->CastSpell(target, SPELL_SHAMAN_FREEZE, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_frozen_power::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); - } -}; - -// 63279 - Glyph of Earth Shield -class spell_sha_glyph_of_earth_shield : public AuraScript -{ - PrepareAuraScript(spell_sha_glyph_of_earth_shield); - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - SpellInfo const* earthShield = eventInfo.GetSpellInfo(); - if (!earthShield) - return; - - AuraEffect* earthShieldEffect = eventInfo.GetProcTarget()->GetAuraEffect(earthShield->Id, EFFECT_0, eventInfo.GetActor()->GetGUID()); - if (!earthShieldEffect) - return; - - int32 amount = earthShieldEffect->GetAmount(); - AddPct(amount, aurEff->GetAmount()); - earthShieldEffect->SetAmount(amount); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_earth_shield::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 55440 - Glyph of Healing Wave -class spell_sha_glyph_of_healing_wave : public AuraScript -{ - PrepareAuraScript(spell_sha_glyph_of_healing_wave); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - if (caster == eventInfo.GetProcTarget()) - return; - - HealInfo* healInfo = eventInfo.GetHealInfo(); - if (!healInfo || !healInfo->GetHeal()) - return; - - int32 amount = CalculatePct(static_cast(healInfo->GetHeal()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_GLYPH_OF_HEALING_WAVE_HEAL, SPELLVALUE_BASE_POINT0, amount, (Unit*)nullptr, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_healing_wave::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 63280 - Glyph of Totem of Wrath -class spell_sha_glyph_of_totem_of_wrath : public AuraScript -{ - PrepareAuraScript(spell_sha_glyph_of_totem_of_wrath); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - // Totem of Wrath shares family flags with other totems - // filter by spellIcon instead - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo || spellInfo->SpellIconID != SHAMAN_ICON_ID_TOTEM_OF_WRATH) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - - // Fire totem summon slot - Creature* totem = ObjectAccessor::GetCreature(*caster, caster->m_SummonSlot[1]); - if (!totem) - return; - - SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(totem->m_spells[0]); - if (!totemSpell) - return; - - int32 bp0 = CalculatePct(totemSpell->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); - int32 bp1 = CalculatePct(totemSpell->Effects[EFFECT_1].CalcValue(caster), aurEff->GetAmount()); - caster->CastCustomSpell((Unit*)nullptr, SPELL_SHAMAN_TOTEM_OF_WRATH_SPELL_POWER, &bp0, &bp1, nullptr, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_sha_glyph_of_totem_of_wrath::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_glyph_of_totem_of_wrath::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 52041, 52046, 52047, 52048, 52049, 52050, 58759, 58760, 58761 - Healing Stream Totem class spell_sha_healing_stream_totem : public SpellScript { @@ -1061,7 +787,6 @@ class spell_sha_healing_stream_totem : public SpellScript int32 damage = GetEffectValue(); SpellInfo const* triggeringSpell = GetTriggeringSpell(); if (Unit* target = GetHitUnit()) - { if (Unit* caster = GetCaster()) { if (Unit* owner = caster->GetOwner()) @@ -1081,7 +806,6 @@ class spell_sha_healing_stream_totem : public SpellScript } caster->CastCustomSpell(target, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); } - } } void Register() override @@ -1097,12 +821,13 @@ class spell_sha_heroism : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo({ SPELL_SHAMAN_EXHAUSTION }); + return ValidateSpellInfo({ SPELL_SHAMAN_EXHAUSTION, SPELL_SHAMAN_SATED }); } void RemoveInvalidTargets(std::list& targets) { targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SHAMAN_EXHAUSTION)); + targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SHAMAN_SATED)); } void ApplyDebuff() @@ -1113,43 +838,140 @@ class spell_sha_heroism : public SpellScript void Register() override { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_RAID); - + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); AfterHit += SpellHitFn(spell_sha_heroism::ApplyDebuff); } }; -// -324 - Lightning Shield -class spell_sha_lightning_shield : public AuraScript +// 23551 - Lightning Shield +class spell_sha_item_lightning_shield : public AuraScript { - PrepareAuraScript(spell_sha_lightning_shield); + PrepareAuraScript(spell_sha_item_lightning_shield); bool Validate(SpellInfo const* /*spellInfo*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LIGHTNING_SHIELD_R1)) - return false; - return true; - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetActionTarget()) - return true; - return false; + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD }); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - uint32 triggerSpell = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_R1, aurEff->GetSpellInfo()->GetRank()); - - eventInfo.GetActionTarget()->CastSpell(eventInfo.GetActor(), triggerSpell, true, nullptr, aurEff); + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff); } void Register() override { - DoCheckProc += AuraCheckProcFn(spell_sha_lightning_shield::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 23552 - Lightning Shield +class spell_sha_item_lightning_shield_trigger : public AuraScript +{ + PrepareAuraScript(spell_sha_item_lightning_shield_trigger); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_MANA_SURGE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield_trigger::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 23572 - Mana Surge +class spell_sha_item_mana_surge : public AuraScript +{ + PrepareAuraScript(spell_sha_item_mana_surge); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE }); + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetSpellInfo() != nullptr; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 mana = eventInfo.GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); + int32 damage = CalculatePct(mana, 35); + + GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, nullptr, aurEff); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_sha_item_mana_surge::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + +// 70811 - Item - Shaman T10 Elemental 2P Bonus +class spell_sha_item_t10_elemental_2p_bonus : public AuraScript +{ + PrepareAuraScript(spell_sha_item_t10_elemental_2p_bonus); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHAMAN_ELEMENTAL_MASTERY }); + } + + void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + if (Player* target = GetTarget()->ToPlayer()) + target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_sha_item_t10_elemental_2p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_DUMMY); + } +}; + +// 60103 - Lava Lash +class spell_sha_lava_lash : public SpellScript +{ + PrepareSpellScript(spell_sha_lava_lash) + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Player* caster = GetCaster()->ToPlayer()) + { + int32 damage = GetEffectValue(); + int32 hitDamage = GetHitDamage(); + if (caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) + { + // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. + if (caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) + AddPct(hitDamage, damage); + SetHitDamage(hitDamage); + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_sha_lava_lash::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); } }; @@ -1213,46 +1035,6 @@ class spell_sha_mana_tide_totem : public SpellScript } }; -// -30881 - Nature's Guardian -class spell_sha_nature_guardian : public AuraScript -{ - PrepareAuraScript(spell_sha_nature_guardian); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_NATURE_GUARDIAN)) - return false; - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - int32 healthpct = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); // %s2 - the 30% threshold for health - - if (Unit* target = eventInfo.GetActionTarget()) - { - if (target->HealthBelowPctDamaged(healthpct, eventInfo.GetDamageInfo()->GetDamage())) - { - - uint32 bp = CalculatePct(target->GetMaxHealth(), aurEff->GetAmount()); - target->CastCustomSpell(SPELL_SHAMAN_NATURE_GUARDIAN, SPELLVALUE_BASE_POINT0, bp, target, true, nullptr, aurEff); - - // @TODO: FIX ME PLEASE - // Threat reduction is around 10% confirmed in retail and from wiki -// Unit* attacker = eventInfo.GetActor(); -// if (attacker->IsAlive()) -// attacker->getThreatMgr().modifyThreatPercent(target, -10); - } - } - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_nature_guardian::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 6495 - Sentry Totem class spell_sha_sentry_totem : public AuraScript { @@ -1322,632 +1104,8 @@ class spell_sha_flurry_proc : public AuraScript } }; -class spell_sha_astral_shift_aura : public AuraScript -{ - PrepareAuraScript(spell_sha_astral_shift_aura); - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - if (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_SILENCE) | (1 << MECHANIC_STUN) | (1 << MECHANIC_FEAR))) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_sha_astral_shift_aura::CheckProc); - } -}; - -// -16180 - Improved Water Shield -class spell_sha_imp_water_shield : public AuraScript -{ - PrepareAuraScript(spell_sha_imp_water_shield); - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - // If we're here, we've already passed initial aura roll - // So just chance based on 100% - - // Default chance for Healing Wave and Riptide - int32 chance = 100; - // Lesser Healing Wave - 0.6 of default - if (spellInfo->SpellFamilyFlags[0] & 0x00000080) - chance = 60; - // Chain heal - 0.3 of default - else if (spellInfo->SpellFamilyFlags[0] & 0x00000100) - chance = 30; - - if (!roll_chance_i(chance)) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - // Get Water Shield - AuraEffect const* waterShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000000, 0x00000020, 0x00000000, caster->GetGUID()); - if (!waterShield) - return; - - uint32 spellId = waterShield->GetSpellInfo()->Effects[waterShield->GetEffIndex()].TriggerSpell; - caster->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_sha_imp_water_shield::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_imp_water_shield::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -30675 - Lightning Overload -class spell_sha_lightning_overload : public AuraScript -{ - PrepareAuraScript(spell_sha_lightning_overload); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1, - SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1 - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - uint32 spellId; - - // Lightning Bolt - if (spellInfo->SpellFamilyFlags[0] & 0x00000001) - spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_R1, spellInfo->GetRank()); - // Chain Lightning - else - { - // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit. - // A maxed LO would have a 33% / 3 = 11% chance to proc of each target. - // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets] - float chance = 100.0f / spellInfo->GetEffect(EFFECT_0).ChainTarget; - if (!roll_chance_f(chance)) - return; - - spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_R1, spellInfo->GetRank()); - } - - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_lightning_overload::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 23551 - Lightning Shield T2 Bonus -class spell_sha_item_lightning_shield : public AuraScript -{ - PrepareAuraScript(spell_sha_item_lightning_shield); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 23552 - Lightning Shield T2 Bonus -class spell_sha_item_lightning_shield_trigger : public AuraScript -{ - PrepareAuraScript(spell_sha_item_lightning_shield_trigger); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - GetTarget()->CastSpell(GetTarget(), SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_lightning_shield_trigger::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 23572 - Mana Surge -class spell_sha_item_mana_surge : public AuraScript -{ - PrepareAuraScript(spell_sha_item_mana_surge); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ITEM_MANA_SURGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - int32 mana = spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetSchoolMask()); - int32 damage = CalculatePct(mana, 35); - - GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_mana_surge::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 40463 - Shaman Tier 6 Trinket -class spell_sha_item_t6_trinket : public AuraScript -{ - PrepareAuraScript(spell_sha_item_t6_trinket); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SHAMAN_ENERGY_SURGE, - SPELL_SHAMAN_POWER_SURGE - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return; - - uint32 spellId; - int32 chance; - - // Lesser Healing Wave - if (spellInfo->SpellFamilyFlags[0] & 0x00000080) - { - spellId = SPELL_SHAMAN_ENERGY_SURGE; - chance = 10; - } - // Lightning Bolt - else if (spellInfo->SpellFamilyFlags[0] & 0x00000001) - { - spellId = SPELL_SHAMAN_ENERGY_SURGE; - chance = 15; - } - // Stormstrike - else if (spellInfo->SpellFamilyFlags[1] & 0x00000010) - { - spellId = SPELL_SHAMAN_POWER_SURGE; - chance = 50; - } - else - return; - - if (roll_chance_i(chance)) - eventInfo.GetActor()->CastSpell((Unit*)nullptr, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_t6_trinket::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 70811 - Item - Shaman T10 Elemental 2P Bonus -class spell_sha_item_t10_elemental_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_sha_item_t10_elemental_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_ELEMENTAL_MASTERY }); - } - - void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - if (Player* target = GetTarget()->ToPlayer()) - target->ModifySpellCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, -aurEff->GetAmount()); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_item_t10_elemental_2p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 60103 - Lava Lash -class spell_sha_lava_lash : public SpellScript -{ - PrepareSpellScript(spell_sha_lava_lash); - - bool Load() override - { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - - void HandleDummy(SpellEffIndex /*effIndex*/) - { - if (Player* caster = GetCaster()->ToPlayer()) - { - int32 damage = GetEffectValue(); - int32 hitDamage = GetHitDamage(); - if (Item* offhand = caster->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) - { - // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000, 0, 0)) - if (aurEff->GetBase()->GetCastItemGUID() == offhand->GetGUID()) - AddPct(hitDamage, damage); - SetHitDamage(hitDamage); - } - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_sha_lava_lash::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); - } - -}; - -// 53817 - Maelstrom Weapon -class spell_sha_maelstrom_weapon : public AuraScript -{ - PrepareAuraScript(spell_sha_maelstrom_weapon); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SHAMAN_MAELSTROM_POWER, - SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS - }); - } - - void HandleBonus(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (GetStackAmount() < GetSpellInfo()->StackAmount) - return; - - Unit* caster = GetUnitOwner(); - AuraEffect const* maelstrom = caster->GetAuraEffect(SPELL_SHAMAN_T10_ENHANCEMENT_4P_BONUS, EFFECT_0); - if (!maelstrom || !roll_chance_i(maelstrom->GetAmount())) - return; - - caster->CastSpell((Unit*)nullptr, SPELL_SHAMAN_MAELSTROM_POWER, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_sha_maelstrom_weapon::HandleBonus, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER, AURA_EFFECT_HANDLE_CHANGE_AMOUNT); - } -}; - -// 30823 - Shamanistic Rage -class spell_sha_shamanistic_rage : public AuraScript -{ - PrepareAuraScript(spell_sha_shamanistic_rage); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - PreventDefaultAction(); - - Unit* target = GetTarget(); - int32 amount = CalculatePct(static_cast(target->GetTotalAttackPowerValue(BASE_ATTACK)), aurEff->GetAmount()); - target->CastCustomSpell(SPELL_SHAMAN_SHAMANISTIC_RAGE_PROC, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_shamanistic_rage::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 58877 - Spirit Hunt -class spell_sha_spirit_hunt : public AuraScript -{ - PrepareAuraScript(spell_sha_spirit_hunt); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_SPIRIT_HUNT_HEAL }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - Unit* caster = eventInfo.GetActor(); - Unit* target = caster->GetOwner(); - if (!target) - return; - - int32 amount = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, caster, true, nullptr, aurEff); - caster->CastCustomSpell(SPELL_SHAMAN_SPIRIT_HUNT_HEAL, SPELLVALUE_BASE_POINT0, amount, target, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_spirit_hunt::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// -51525 - Static Shock -class spell_sha_static_shock : public AuraScript -{ - PrepareAuraScript(spell_sha_static_shock); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - - // Get Lightning Shield - AuraEffect const* lightningShield = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x00000400, 0x00000000, 0x00000000, caster->GetGUID()); - if (!lightningShield) - return; - - uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LIGHTNING_SHIELD_DAMAGE_R1, lightningShield->GetSpellInfo()->GetRank()); - eventInfo.GetActor()->CastSpell(eventInfo.GetProcTarget(), spellId, true, nullptr, aurEff); - lightningShield->GetBase()->DropCharge(); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_static_shock::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 55198 - Tidal Force -class spell_sha_tidal_force_dummy : public AuraScript -{ - PrepareAuraScript(spell_sha_tidal_force_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_SHAMAN_TIDAL_FORCE_CRIT }); - } - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetActor()->RemoveAuraFromStack(SPELL_SHAMAN_TIDAL_FORCE_CRIT); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_tidal_force_dummy::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 28823 - Totemic Power -class spell_sha_t3_6p_bonus : public AuraScript -{ - PrepareAuraScript(spell_sha_t3_6p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SHAMAN_TOTEMIC_POWER_ARMOR, - SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER, - SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER, - SPELL_SHAMAN_TOTEMIC_POWER_MP5 - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - uint32 spellId; - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - switch (target->getClass()) - { - case CLASS_PALADIN: - case CLASS_PRIEST: - case CLASS_SHAMAN: - case CLASS_DRUID: - spellId = SPELL_SHAMAN_TOTEMIC_POWER_MP5; - break; - case CLASS_MAGE: - case CLASS_WARLOCK: - spellId = SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER; - break; - case CLASS_HUNTER: - case CLASS_ROGUE: - spellId = SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER; - break; - case CLASS_WARRIOR: - spellId = SPELL_SHAMAN_TOTEMIC_POWER_ARMOR; - break; - default: - return; - } - - caster->CastSpell(target, spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_t3_6p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 70817 - Item - Shaman T10 Elemental 4P Bonus -class spell_sha_t10_elemental_4p_bonus : public AuraScript -{ - PrepareAuraScript(spell_sha_t10_elemental_4p_bonus); - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* caster = eventInfo.GetActor(); - Unit* target = eventInfo.GetProcTarget(); - - // try to find spell Flame Shock on the target - AuraEffect* flameShock = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x00000000, 0x00000000, caster->GetGUID()); - if (!flameShock) - return; - - Aura* flameShockAura = flameShock->GetBase(); - - int32 maxDuration = flameShockAura->GetMaxDuration(); - int32 newDuration = flameShockAura->GetDuration() + aurEff->GetAmount() * IN_MILLISECONDS; - - flameShockAura->SetDuration(newDuration); - // is it blizzlike to change max duration for FS? - if (newDuration > maxDuration) - flameShockAura->SetMaxDuration(newDuration); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_sha_t10_elemental_4p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 33757 - Windfury Weapon (Passive) -class spell_sha_windfury_weapon : public AuraScript -{ - PrepareAuraScript(spell_sha_windfury_weapon); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_SHAMAN_WINDFURY_WEAPON_R1, - SPELL_SHAMAN_WINDFURY_ATTACK_MH, - SPELL_SHAMAN_WINDFURY_ATTACK_OH - }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - Player* player = eventInfo.GetActor()->ToPlayer(); - if (!player) - return false; - - Item* item = player->GetItemByGuid(GetAura()->GetCastItemGUID()); - if (!item || !item->IsEquipped()) - return false; - - WeaponAttackType attType = static_cast(player->GetAttackBySlot(item->GetSlot())); - if (attType != BASE_ATTACK && attType != OFF_ATTACK) - return false; - - if (((attType == BASE_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK)) || - ((attType == OFF_ATTACK) && !(eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK))) - return false; - - return true; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Player* player = eventInfo.GetActor()->ToPlayer(); - - uint32 spellId = 0; - WeaponAttackType attType = BASE_ATTACK; - if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_MAINHAND_ATTACK) - spellId = SPELL_SHAMAN_WINDFURY_ATTACK_MH; - - if (eventInfo.GetTypeMask() & PROC_FLAG_DONE_OFFHAND_ATTACK) - { - spellId = SPELL_SHAMAN_WINDFURY_ATTACK_OH; - attType = OFF_ATTACK; - } - - Item* item = ASSERT_NOTNULL(player->GetWeaponForAttack(attType)); - - int32 enchantId = static_cast(item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)); - int32 extraAttackPower = 0; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_WINDFURY_WEAPON_R1); - while (spellInfo) - { - if (spellInfo->Effects[EFFECT_0].MiscValue == enchantId) - { - extraAttackPower = spellInfo->Effects[EFFECT_1].CalcValue(player); - break; - } - spellInfo = spellInfo->GetNextRankSpell(); - } - - if (!extraAttackPower) - return; - - // Value gained from additional AP - int32 amount = static_cast(extraAttackPower / 14.f * player->GetAttackTime(attType) / 1000.f); - - // Attack twice - for (uint8 i = 0; i < 2; ++i) - player->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, item, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_sha_windfury_weapon::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_sha_windfury_weapon::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - void AddSC_shaman_spell_scripts() { - RegisterSpellScript(spell_sha_ancestral_awakening); RegisterSpellScript(spell_sha_totem_of_wrath); RegisterSpellScript(spell_sha_spirit_walk); RegisterSpellScript(spell_sha_t10_restoration_4p_bonus); @@ -1972,29 +1130,9 @@ void AddSC_shaman_spell_scripts() RegisterSpellScript(spell_sha_item_mana_surge); RegisterSpellScript(spell_sha_item_t10_elemental_2p_bonus); RegisterSpellScript(spell_sha_lava_lash); - RegisterSpellScript(spell_sha_lightning_shield); RegisterSpellScript(spell_sha_mana_spring_totem); RegisterSpellScript(spell_sha_mana_tide_totem); - RegisterSpellScript(spell_sha_nature_guardian); RegisterSpellScript(spell_sha_sentry_totem); RegisterSpellScript(spell_sha_thunderstorm); RegisterSpellScript(spell_sha_flurry_proc); - RegisterSpellScript(spell_sha_flametongue_weapon); - RegisterSpellScript(spell_sha_frozen_power); - RegisterSpellScript(spell_sha_glyph_of_earth_shield); - RegisterSpellScript(spell_sha_glyph_of_healing_wave); - RegisterSpellScript(spell_sha_glyph_of_totem_of_wrath); - RegisterSpellScript(spell_sha_healing_stream_totem); - RegisterSpellScript(spell_sha_astral_shift_aura); - RegisterSpellScript(spell_sha_imp_water_shield); - RegisterSpellScript(spell_sha_lightning_overload); - RegisterSpellScript(spell_sha_item_t6_trinket); - RegisterSpellScript(spell_sha_maelstrom_weapon); - RegisterSpellScript(spell_sha_shamanistic_rage); - RegisterSpellScript(spell_sha_spirit_hunt); - RegisterSpellScript(spell_sha_static_shock); - RegisterSpellScript(spell_sha_tidal_force_dummy); - RegisterSpellScript(spell_sha_t3_6p_bonus); - RegisterSpellScript(spell_sha_t10_elemental_4p_bonus); - RegisterSpellScript(spell_sha_windfury_weapon); } diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index a2b222b44..f23d3a247 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -43,7 +43,6 @@ enum WarlockSpells SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444, - SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090, SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181, SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_AURA = 58070, SPELL_WARLOCK_GLYPH_OF_DRAIN_SOUL_PROC = 58068, @@ -59,38 +58,17 @@ enum WarlockSpells SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956, SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818, SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553, - SPELL_WARLOCK_NETHER_PROTECTION_HOLY = 54370, - SPELL_WARLOCK_NETHER_PROTECTION_FIRE = 54371, - SPELL_WARLOCK_NETHER_PROTECTION_FROST = 54372, - SPELL_WARLOCK_NETHER_PROTECTION_ARCANE = 54373, - SPELL_WARLOCK_NETHER_PROTECTION_SHADOW = 54374, - SPELL_WARLOCK_NETHER_PROTECTION_NATURE = 54375, SPELL_WARLOCK_SOULSHATTER = 32835, SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106, SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117, SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213, - SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371, - SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED = 63321, - SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 = 27285, - SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC = 32865, - SPELL_WARLOCK_SHADOW_TRANCE = 17941, - SPELL_WARLOCK_SOUL_LEECH_HEAL = 30294, - SPELL_WARLOCK_IMP_SOUL_LEECH_R1 = 54117, - SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1 = 54607, - SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 = 59118, - SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1 = 54300, - SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 = 59117, - SPELL_REPLENISHMENT = 57669, - SPELL_WARLOCK_SHADOWFLAME = 37378, - SPELL_WARLOCK_FLAMESHADOW = 37379, - SPELL_WARLOCK_GLYPH_OF_SUCCUBUS = 56250 + SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371 }; enum WarlockSpellIcons { WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208, - WARLOCK_ICON_ID_MANA_FEED = 1982, - WARLOCK_ICON_ID_DEMONIC_PACT = 3220 + WARLOCK_ICON_ID_MANA_FEED = 1982 }; class spell_warl_eye_of_kilrogg : public AuraScript @@ -659,42 +637,6 @@ class spell_warl_everlasting_affliction : public SpellScript } }; -// 54909, 53646 - Demonic Pact -class spell_warl_demonic_pact : public AuraScript -{ - PrepareAuraScript(spell_warl_demonic_pact); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_DEMONIC_PACT_PROC }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - return eventInfo.GetActor() && eventInfo.GetActor()->IsPet(); - } - - void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - if (Unit* owner = eventInfo.GetActor()->GetOwner()) - { - if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_DEMONIC_PACT, EFFECT_0)) - { - int32 bp0 = static_cast((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC) + 100.0f) / 100.0f); - owner->CastCustomSpell(SPELL_WARLOCK_DEMONIC_PACT_PROC, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true, nullptr, aurEff); - } - } - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warl_demonic_pact::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_warl_demonic_pact::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // 18541 - Ritual of Doom Effect class spell_warl_ritual_of_doom_effect : public SpellScript { @@ -712,92 +654,6 @@ class spell_warl_ritual_of_doom_effect : public SpellScript } }; -// -27243 - Seed of Corruption -class spell_warl_seed_of_corruption_dummy : public AuraScript -{ - PrepareAuraScript(spell_warl_seed_of_corruption_dummy); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 amount = aurEff->GetAmount() - damageInfo->GetDamage(); - if (amount > 0) - { - const_cast(aurEff)->SetAmount(amount); - if (!GetTarget()->HealthBelowPctDamaged(1, damageInfo->GetDamage())) - return; - } - - Remove(); - - Unit* caster = GetCaster(); - if (!caster) - return; - - uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank()); - caster->CastSpell(eventInfo.GetActionTarget(), spellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_dummy::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); - } -}; - -// 32863 - Seed of Corruption -// 36123 - Seed of Corruption -// 38252 - Seed of Corruption -// 39367 - Seed of Corruption -// 44141 - Seed of Corruption -// 70388 - Seed of Corruption -// Monster spells, triggered only on amount drop (not on death) -class spell_warl_seed_of_corruption_generic : public AuraScript -{ - PrepareAuraScript(spell_warl_seed_of_corruption_generic); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - int32 amount = aurEff->GetAmount() - damageInfo->GetDamage(); - if (amount > 0) - { - const_cast(aurEff)->SetAmount(amount); - return; - } - - Remove(); - - Unit* caster = GetCaster(); - if (!caster) - return; - - caster->CastSpell(eventInfo.GetActionTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_GENERIC, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_generic::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); - } -}; - // -27285 - Seed of Corruption class spell_warl_seed_of_corruption : public SpellScript { @@ -828,61 +684,6 @@ class spell_warl_seed_of_corruption : public SpellScript } }; -// -30293 - Soul Leech -class spell_warl_soul_leech : public AuraScript -{ - PrepareAuraScript(spell_warl_soul_leech); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_WARLOCK_SOUL_LEECH_HEAL, - SPELL_WARLOCK_IMP_SOUL_LEECH_R1, - SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, - SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2, - SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, - SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2, - SPELL_REPLENISHMENT - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static uint32 const casterMana[2] = { SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_1, SPELL_WARLOCK_SOUL_LEECH_CASTER_MANA_2 }; - static uint32 const petMana[2] = { SPELL_WARLOCK_SOUL_LEECH_PET_MANA_1, SPELL_WARLOCK_SOUL_LEECH_PET_MANA_2 }; - - PreventDefaultAction(); - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo || !damageInfo->GetDamage()) - return; - - Unit* caster = eventInfo.GetActor(); - int32 bp = CalculatePct(static_cast(damageInfo->GetDamage()), aurEff->GetAmount()); - caster->CastCustomSpell(SPELL_WARLOCK_SOUL_LEECH_HEAL, SPELLVALUE_BASE_POINT0, bp, caster, true, nullptr, aurEff); - - // Improved Soul Leech code below - AuraEffect const* impSoulLeech = GetTarget()->GetAuraEffectOfRankedSpell(SPELL_WARLOCK_IMP_SOUL_LEECH_R1, EFFECT_1, aurEff->GetCasterGUID()); - if (!impSoulLeech) - return; - - uint8 impSoulLeechRank = impSoulLeech->GetSpellInfo()->GetRank(); - uint32 selfSpellId = casterMana[impSoulLeechRank - 1]; - uint32 petSpellId = petMana[impSoulLeechRank - 1]; - - caster->CastSpell((Unit*)nullptr, selfSpellId, true, nullptr, aurEff); - caster->CastSpell((Unit*)nullptr, petSpellId, true, nullptr, aurEff); - - if (roll_chance_i(impSoulLeech->GetAmount())) - caster->CastSpell((Unit*)nullptr, SPELL_REPLENISHMENT, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_soul_leech::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 29858 - Soulshatter class spell_warl_soulshatter : public SpellScript { @@ -1012,97 +813,6 @@ class spell_warl_life_tap : public SpellScript } }; -// -30299 - Nether Protection -class spell_warl_nether_protection : public AuraScript -{ - PrepareAuraScript(spell_warl_nether_protection); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_NETHER_PROTECTION_HOLY, SPELL_WARLOCK_NETHER_PROTECTION_FIRE, SPELL_WARLOCK_NETHER_PROTECTION_FROST, SPELL_WARLOCK_NETHER_PROTECTION_ARCANE, SPELL_WARLOCK_NETHER_PROTECTION_SHADOW, SPELL_WARLOCK_NETHER_PROTECTION_NATURE }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetDamageInfo()) - { - switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) - { - case SPELL_SCHOOL_HOLY: - case SPELL_SCHOOL_FIRE: - case SPELL_SCHOOL_NATURE: - case SPELL_SCHOOL_FROST: - case SPELL_SCHOOL_SHADOW: - case SPELL_SCHOOL_ARCANE: - return true; - default: - break; - } - } - - return false; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - uint32 triggerspell = 0; - - switch (GetFirstSchoolInMask(eventInfo.GetDamageInfo()->GetSchoolMask())) - { - case SPELL_SCHOOL_HOLY: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_HOLY; - break; - case SPELL_SCHOOL_FIRE: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FIRE; - break; - case SPELL_SCHOOL_NATURE: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_NATURE; - break; - case SPELL_SCHOOL_FROST: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_FROST; - break; - case SPELL_SCHOOL_SHADOW: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_SHADOW; - break; - case SPELL_SCHOOL_ARCANE: - triggerspell = SPELL_WARLOCK_NETHER_PROTECTION_ARCANE; - break; - default: - return; - } - - if (Unit* target = eventInfo.GetActionTarget()) - target->CastSpell(target, triggerspell, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warl_nether_protection::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_warl_nether_protection::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// -63156 - Decimation -class spell_warl_decimation : public AuraScript -{ - PrepareAuraScript(spell_warl_decimation); - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - if (eventInfo.GetActionTarget()->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, eventInfo.GetActor())) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warl_decimation::CheckProc); - } -}; - // 48018 - Demonic Circle: Summon class spell_warl_demonic_circle_summon : public AuraScript { @@ -1258,31 +968,6 @@ class spell_warl_haunt_aura : public AuraScript } }; -// 37377 - Shadowflame -// 39437 - Shadowflame Hellfire and RoF -template -class spell_warl_t4_2p_bonus : public AuraScript -{ - PrepareAuraScript(spell_warl_t4_2p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ TriggerSpellId }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, TriggerSpellId, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_t4_2p_bonus::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // -30108 - Unstable Affliction class spell_warl_unstable_affliction : public AuraScript { @@ -1413,53 +1098,6 @@ class spell_warl_shadow_ward : public AuraScript } }; -// -18094 - Nightfall -// 56218 - Glyph of Corruption -class spell_warl_glyph_of_corruption_nightfall : public AuraScript -{ - PrepareAuraScript(spell_warl_glyph_of_corruption_nightfall); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_SHADOW_TRANCE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_SHADOW_TRANCE, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_corruption_nightfall::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - -// 63320 - Glyph of Life Tap -class spell_warl_glyph_of_life_tap : public AuraScript -{ - PrepareAuraScript(spell_warl_glyph_of_life_tap); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warl_glyph_of_life_tap::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 63310 - Glyph of Shadowflame class spell_warl_glyph_of_shadowflame : public AuraScript { @@ -1654,7 +1292,6 @@ void AddSC_warlock_spell_scripts() RegisterSpellAndAuraScriptPair(spell_warl_haunt, spell_warl_haunt_aura); RegisterSpellScript(spell_warl_health_funnel); RegisterSpellScript(spell_warl_life_tap); - RegisterSpellScript(spell_warl_nether_protection); RegisterSpellScript(spell_warl_ritual_of_doom_effect); RegisterSpellScript(spell_warl_seed_of_corruption); RegisterSpellScript(spell_warl_shadow_ward); @@ -1662,15 +1299,6 @@ void AddSC_warlock_spell_scripts() RegisterSpellScript(spell_warl_soulshatter); RegisterSpellScript(spell_warl_unstable_affliction); RegisterSpellScript(spell_warl_drain_soul); - RegisterSpellScript(spell_warl_demonic_pact); - RegisterSpellScript(spell_warl_decimation); - RegisterSpellScript(spell_warl_seed_of_corruption_dummy); - RegisterSpellScript(spell_warl_seed_of_corruption_generic); - RegisterSpellScript(spell_warl_soul_leech); - RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus, "spell_warl_t4_2p_bonus_shadow"); - RegisterSpellScriptWithArgs(spell_warl_t4_2p_bonus, "spell_warl_t4_2p_bonus_fire"); - RegisterSpellScript(spell_warl_glyph_of_corruption_nightfall); - RegisterSpellScript(spell_warl_glyph_of_life_tap); RegisterSpellScript(spell_warl_shadowburn); RegisterSpellScript(spell_warl_glyph_of_felguard); } diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index d91904236..77108ca9a 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -35,7 +35,6 @@ enum WarriorSpells SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER = 59725, SPELL_WARRIOR_BLOODTHIRST = 23885, SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881, - SPELL_WARRIOR_BLOODSURGE_R1 = 29723, SPELL_WARRIOR_CHARGE = 34846, SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653, SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162, @@ -43,8 +42,6 @@ enum WarriorSpells SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721, SPELL_WARRIOR_EXECUTE = 20647, - SPELL_WARRIOR_EXECUTE_GCD_REDUCED = 71069, - SPELL_WARRIOR_EXTRA_CHARGE = 70849, SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367, SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326, SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, @@ -52,8 +49,6 @@ enum WarriorSpells SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976, SPELL_WARRIOR_RETALIATION_DAMAGE = 22858, SPELL_WARRIOR_SLAM = 50783, - SPELL_WARRIOR_SLAM_GCD_REDUCED = 71072, - SPELL_WARRIOR_SUDDEN_DEATH_R1 = 46913, SPELL_WARRIOR_SUNDER_ARMOR = 58567, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1 = 12723, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2 = 26654, @@ -64,11 +59,6 @@ enum WarriorSpells SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, SPELL_WARRIOR_VIGILANCE_PROC = 50725, SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665, - SPELL_WARRIOR_SECOND_WIND_TRIGGER_1 = 29841, - SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 = 29842, - SPELL_WARRIOR_GLYPH_OF_BLOCKING = 58374, - SPELL_WARRIOR_STOICISM = 70845, - SPELL_WARRIOR_T10_MELEE_4P_BONUS = 70847, SPELL_WARRIOR_WHIRLWIND_OFF = 44949 }; @@ -83,7 +73,6 @@ enum MiscSpells SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899, SPELL_PRIEST_RENEWED_HOPE = 63944, SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066, - SPELL_CATEGORY_SHIELD_SLAM = 1209 }; class spell_warr_mocking_blow : public SpellScript @@ -173,7 +162,7 @@ class spell_warr_improved_spell_reflection : public AuraScript CustomSpellValues values; values.AddSpellMod(SPELLVALUE_MAX_TARGETS, aurEff->GetAmount()); values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 2000); // Base range = 100, final range = 20 value / 10000.0f = 0.2f - eventInfo.GetActor()->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, values, eventInfo.GetActor(), TRIGGERED_FULL_MASK, nullptr, aurEff); + eventInfo.GetActor()->CastCustomSpell(SPELL_WARRIOR_IMPROVED_SPELL_REFLECTION_TRIGGER, values, eventInfo.GetActor(), TRIGGERED_FULL_MASK, nullptr); } void Register() override @@ -235,31 +224,6 @@ class spell_warr_improved_spell_reflection_trigger_aura : public AuraScript } }; -// 70844 - Item - Warrior T10 Protection 4P Bonus -class spell_warr_item_t10_prot_4p_bonus : public AuraScript -{ - PrepareAuraScript(spell_warr_item_t10_prot_4p_bonus); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARRIOR_STOICISM }); - } - - void HandleProc(ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* target = eventInfo.GetActionTarget(); - int32 bp0 = CalculatePct(target->GetMaxHealth(), GetSpellInfo()->Effects[EFFECT_1].CalcValue()); - target->CastCustomSpell(SPELL_WARRIOR_STOICISM, SPELLVALUE_BASE_POINT0, bp0, (Unit*)nullptr, true); - } - - void Register() override - { - OnProc += AuraProcFn(spell_warr_item_t10_prot_4p_bonus::HandleProc); - } -}; - // 12975 - Last Stand class spell_warr_last_stand : public SpellScript { @@ -290,13 +254,7 @@ class spell_warr_deep_wounds : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo( - { - SPELL_WARRIOR_DEEP_WOUNDS_RANK_1, - SPELL_WARRIOR_DEEP_WOUNDS_RANK_2, - SPELL_WARRIOR_DEEP_WOUNDS_RANK_3, - SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC - }); + return ValidateSpellInfo({ SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -311,7 +269,7 @@ class spell_warr_deep_wounds : public SpellScript ApplyPct(damage, 16.0f * GetSpellInfo()->GetRank() / 6.0f); target->CastDelayedSpellWithPeriodicAmount(caster, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, SPELL_AURA_PERIODIC_DAMAGE, damage, EFFECT_0); - caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true); + //caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, nullptr, nullptr, true); } } @@ -415,47 +373,6 @@ class spell_warr_damage_shield : public AuraScript } }; -// -12834 - Deep Wounds Aura -class spell_warr_deep_wounds_aura : public AuraScript -{ - PrepareAuraScript(spell_warr_deep_wounds_aura); - - bool Validate(SpellInfo const* spellInfo) override - { - return ValidateSpellInfo({ spellInfo->GetEffect(EFFECT_0).TriggerSpell }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (!damageInfo) - return false; - - return eventInfo.GetActor()->GetTypeId() == TYPEID_PLAYER; - } - - void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - - Unit* actor = eventInfo.GetActor(); - float damage = 0.f; - - if (eventInfo.GetDamageInfo()->GetAttackType() == OFF_ATTACK) - damage = (actor->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2.f; - else - damage = (actor->GetFloatValue(UNIT_FIELD_MINDAMAGE) + actor->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2.f; - - actor->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, SPELLVALUE_BASE_POINT0, int32(damage), eventInfo.GetProcTarget(), true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warr_deep_wounds_aura::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_warr_deep_wounds_aura::OnProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - // -5308 - Execute class spell_warr_execute : public SpellScript { @@ -513,71 +430,6 @@ class spell_warr_execute : public SpellScript } }; -// -29723 - Sudden Death -// -46913 - Bloodsurge -class spell_warr_extra_proc : public AuraScript -{ - PrepareAuraScript(spell_warr_extra_proc); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_WARRIOR_T10_MELEE_4P_BONUS, - SPELL_WARRIOR_EXTRA_CHARGE, - SPELL_WARRIOR_SLAM_GCD_REDUCED, - SPELL_WARRIOR_EXECUTE_GCD_REDUCED - }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) - { - Unit* target = GetTarget(); - AuraEffect const* bonusAurEff = target->GetAuraEffect(SPELL_WARRIOR_T10_MELEE_4P_BONUS, EFFECT_0); - if (!bonusAurEff) - return; - - if (!roll_chance_i(bonusAurEff->GetAmount())) - return; - - target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXTRA_CHARGE, true, nullptr, aurEff); - - SpellInfo const* auraInfo = aurEff->GetSpellInfo(); - if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_BLOODSURGE_R1))) - target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_SLAM_GCD_REDUCED, true, nullptr, aurEff); - else if (auraInfo->IsRankOf(sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_SUDDEN_DEATH_R1))) - target->CastSpell((Unit*)nullptr, SPELL_WARRIOR_EXECUTE_GCD_REDUCED, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warr_extra_proc::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } -}; - -// 58375 - Glyph of Blocking -class spell_warr_glyph_of_blocking : public AuraScript -{ - PrepareAuraScript(spell_warr_glyph_of_blocking); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_WARRIOR_GLYPH_OF_BLOCKING }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - Unit* caster = eventInfo.GetActor(); - caster->CastSpell(caster, SPELL_WARRIOR_GLYPH_OF_BLOCKING, true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_warr_glyph_of_blocking::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 12809 - Concussion Blow class spell_warr_concussion_blow : public SpellScript { @@ -736,46 +588,6 @@ class spell_warr_rend : public AuraScript } }; -// -29834 - Second Wind -class spell_warr_second_wind : public AuraScript -{ - PrepareAuraScript(spell_warr_second_wind); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo( - { - SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, - SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 - }); - } - - bool CheckProc(ProcEventInfo& eventInfo) - { - SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); - if (!spellInfo) - return false; - - return (spellInfo->GetAllEffectsMechanicMask() & ((1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN))) != 0; - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - static uint32 const triggeredSpells[2] = { SPELL_WARRIOR_SECOND_WIND_TRIGGER_1, SPELL_WARRIOR_SECOND_WIND_TRIGGER_2 }; - - PreventDefaultAction(); - Unit* caster = eventInfo.GetActionTarget(); - uint32 spellId = triggeredSpells[GetSpellInfo()->GetRank() - 1]; - caster->CastSpell(caster, spellId, true, nullptr, aurEff); - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warr_second_wind::CheckProc); - OnEffectProc += AuraEffectProcFn(spell_warr_second_wind::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } -}; - // 64380, 65941 - Shattering Throw class spell_warr_shattering_throw : public SpellScript { @@ -846,7 +658,7 @@ class spell_warr_sweeping_strikes : public AuraScript if (spellInfo && spellInfo->Id == SPELL_WARRIOR_EXECUTE && !_procTarget->HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT)) { // If triggered by Execute (while target is not under 20% hp) deals normalized weapon damage - GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, true, nullptr, aurEff); + GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_2, aurEff); } else { @@ -866,30 +678,6 @@ private: Unit* _procTarget = nullptr; }; -// 28845 - Cheat Death -class spell_warr_t3_prot_8p_bonus : public AuraScript -{ - PrepareAuraScript(spell_warr_t3_prot_8p_bonus); - - bool CheckProc(ProcEventInfo& eventInfo) - { - if (eventInfo.GetActionTarget()->HealthBelowPct(20)) - return true; - - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - if (damageInfo && damageInfo->GetDamage()) - if (GetTarget()->HealthBelowPctDamaged(20, damageInfo->GetDamage())) - return true; - - return false; - } - - void Register() override - { - DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc); - } -}; - // 50720 - Vigilance class spell_warr_vigilance : public AuraScript { @@ -1024,6 +812,38 @@ class spell_warr_glyph_of_sunder_armor : public AuraScript } }; +// Spell 28845 - Cheat Death + +enum CheatDeath +{ + SPELL_CHEAT_DEATH_TRIGGER = 28846 +}; + +class spell_warr_t3_prot_8p_bonus : public AuraScript +{ + PrepareAuraScript(spell_warr_t3_prot_8p_bonus); + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetActionTarget() && eventInfo.GetActionTarget()->GetHealthPct() <= 20.0f; + } + + void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (Unit* target = eventInfo.GetActionTarget()) + { + target->CastSpell(target, SPELL_CHEAT_DEATH_TRIGGER, true); + } + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_warr_t3_prot_8p_bonus::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warr_t3_prot_8p_bonus::HandleEffectProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } +}; + // 20230 - Retaliation class spell_warr_retaliation : public AuraScript { @@ -1084,10 +904,4 @@ void AddSC_warrior_spell_scripts() RegisterSpellScript(spell_warr_vigilance); RegisterSpellScript(spell_warr_vigilance_trigger); RegisterSpellScript(spell_warr_t3_prot_8p_bonus); - RegisterSpellScript(spell_warr_item_t10_prot_4p_bonus); - RegisterSpellScript(spell_warr_deep_wounds_aura); - RegisterSpellScript(spell_warr_extra_proc); - RegisterSpellScript(spell_warr_glyph_of_blocking); - RegisterSpellScript(spell_warr_second_wind); - RegisterSpellScript(spell_warr_t3_prot_8p_bonus); } diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index fd173dd18..38f0d6405 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -1676,7 +1676,7 @@ struct SpellEntry std::array SpellVisual; // 131-132 m_spellVisualID uint32 SpellIconID; // 133 m_spellIconID uint32 ActiveIconID; // 134 m_activeIconID - uint32 SpellPriority; // 135 + uint32 SpellPriority; // 135 not used std::array SpellName; // 136-151 m_name_lang //uint32 SpellNameFlag; // 152 not used std::array Rank; // 153-168 m_nameSubtext_lang diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 737338ae4..584e0c3f8 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -455,7 +455,7 @@ enum SpellAttr2 : uint32 SPELL_ATTR2_IGNORE_WEAPONSKILL = 0x08000000, // TITLE Unknown attribute 27@Attr2 SPELL_ATTR2_NOT_AN_ACTION = 0x10000000, // TITLE Unknown attribute 28@Attr2 SPELL_ATTR2_CANT_CRIT = 0x20000000, // TITLE Cannot critically strike - SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs + SPELL_ATTR2_ACTIVE_THREAT = 0x40000000, // TITLE Allow triggered spell to trigger (type 1) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs SPELL_ATTR2_RETAIN_ITEM_CAST = 0x80000000 // TITLE Food buff (client only) }; @@ -471,7 +471,7 @@ enum SpellAttr3 : uint32 SPELL_ATTR3_NO_AVOIDANCE = 0x00000040, // TITLE Unknown attribute 6@Attr3 SPELL_ATTR3_DOT_STACKING_RULE = 0x00000080, // TITLE Stack separately for each caster SPELL_ATTR3_ONLY_ON_PLAYER = 0x00000100, // TITLE Can only target players - SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs + SPELL_ATTR3_NOT_A_PROC = 0x00000200, // TITLE Allow triggered spell to trigger (type 2) DESCRIPTION Without this attribute, any triggered spell will be unable to trigger other auras' procs SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON = 0x00000400, // TITLE Require main hand weapon SPELL_ATTR3_ONLY_BATTLEGROUNDS = 0x00000800, // TITLE Can only be cast in battleground SPELL_ATTR3_ONLY_ON_GHOSTS = 0x00001000, // TITLE Can only target ghost players @@ -481,14 +481,14 @@ enum SpellAttr3 : uint32 SPELL_ATTR3_SUPRESS_CASTER_PROCS = 0x00010000, // TITLE Cannot trigger procs SPELL_ATTR3_SUPRESS_TARGET_PROCS = 0x00020000, // TITLE No initial aggro SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked - SPELL_ATTR3_DISABLE_PROC = 0x00080000, // TITLE Cannot trigger spells during aura proc + SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death SPELL_ATTR3_ONLY_PROC_OUTDOORS = 0x00200000, // TITLE Unknown attribute 21@Attr3 SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT = 0x00400000, // TITLE Requires equipped Wand (Mainline: Do Not Trigger Target Stand) SPELL_ATTR3_NO_DAMAGE_HISTORY = 0x00800000, // TITLE Unknown attribute 23@Attr3 SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON = 0x01000000, // TITLE Requires offhand weapon SPELL_ATTR3_TREAT_AS_PERIODIC = 0x02000000, // TITLE Treat as periodic effect - SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED = 0x04000000, // TITLE Can trigger from triggered spells + SPELL_ATTR3_CAN_PROC_FROM_PROCS = 0x04000000, // TITLE Can trigger from triggered spells SPELL_ATTR3_ONLY_PROC_ON_CASTER = 0x08000000, // TITLE Drain Soul SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS = 0x10000000, // TITLE Unknown attribute 28@Attr3 SPELL_ATTR3_IGNORE_CASTER_MODIFIERS = 0x20000000, // TITLE Damage dealt is unaffected by modifiers @@ -3225,7 +3225,7 @@ enum DiminishingReturnsType }; // Diminishing Return Groups -enum DiminishingGroup : uint16 +enum DiminishingGroup { DIMINISHING_NONE = 0, DIMINISHING_BANISH = 1, diff --git a/src/server/shared/enuminfo_SharedDefines.cpp b/src/server/shared/enuminfo_SharedDefines.cpp index 23c16f9b8..751437861 100644 --- a/src/server/shared/enuminfo_SharedDefines.cpp +++ b/src/server/shared/enuminfo_SharedDefines.cpp @@ -445,7 +445,7 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr2 value) case SPELL_ATTR2_IGNORE_WEAPONSKILL: return { "SPELL_ATTR2_IGNORE_WEAPONSKILL", "Unknown attribute 27@Attr2", "" }; case SPELL_ATTR2_NOT_AN_ACTION: return { "SPELL_ATTR2_NOT_AN_ACTION", "Unknown attribute 28@Attr2", "" }; case SPELL_ATTR2_CANT_CRIT: return { "SPELL_ATTR2_CANT_CRIT", "Cannot critically strike", "" }; - case SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC: return { "SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; + case SPELL_ATTR2_ACTIVE_THREAT: return { "SPELL_ATTR2_ACTIVE_THREAT", "Allow triggered spell to trigger (type 1)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; case SPELL_ATTR2_RETAIN_ITEM_CAST: return { "SPELL_ATTR2_RETAIN_ITEM_CAST", "Food buff (client only)", "" }; default: throw std::out_of_range("value"); } @@ -489,7 +489,7 @@ AC_API_EXPORT SpellAttr2 EnumUtils::FromIndex(size_t index) case 27: return SPELL_ATTR2_IGNORE_WEAPONSKILL; case 28: return SPELL_ATTR2_NOT_AN_ACTION; case 29: return SPELL_ATTR2_CANT_CRIT; - case 30: return SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC; + case 30: return SPELL_ATTR2_ACTIVE_THREAT; case 31: return SPELL_ATTR2_RETAIN_ITEM_CAST; default: throw std::out_of_range("index"); } @@ -530,7 +530,7 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr2 value) case SPELL_ATTR2_IGNORE_WEAPONSKILL: return 27; case SPELL_ATTR2_NOT_AN_ACTION: return 28; case SPELL_ATTR2_CANT_CRIT: return 29; - case SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC: return 30; + case SPELL_ATTR2_ACTIVE_THREAT: return 30; case SPELL_ATTR2_RETAIN_ITEM_CAST: return 31; default: throw std::out_of_range("value"); } @@ -553,7 +553,7 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr3 value) case SPELL_ATTR3_NO_AVOIDANCE: return { "SPELL_ATTR3_NO_AVOIDANCE", "Unknown attribute 6@Attr3", "" }; case SPELL_ATTR3_DOT_STACKING_RULE: return { "SPELL_ATTR3_DOT_STACKING_RULE", "Stack separately for each caster", "" }; case SPELL_ATTR3_ONLY_ON_PLAYER: return { "SPELL_ATTR3_ONLY_ON_PLAYER", "Can only target players", "" }; - case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return { "SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; + case SPELL_ATTR3_NOT_A_PROC: return { "SPELL_ATTR3_NOT_A_PROC", "Allow triggered spell to trigger (type 2)", "Without this attribute, any triggered spell will be unable to trigger other auras' procs" }; case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON", "Require main hand weapon", "" }; case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return { "SPELL_ATTR3_ONLY_BATTLEGROUNDS", "Can only be cast in battleground", "" }; case SPELL_ATTR3_ONLY_ON_GHOSTS: return { "SPELL_ATTR3_ONLY_ON_GHOSTS", "Can only target ghost players", "" }; @@ -563,14 +563,14 @@ AC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr3 value) case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return { "SPELL_ATTR3_SUPRESS_CASTER_PROCS", "Cannot trigger procs", "" }; case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return { "SPELL_ATTR3_SUPRESS_TARGET_PROCS", "No initial aggro", "" }; case SPELL_ATTR3_ALWAYS_HIT: return { "SPELL_ATTR3_ALWAYS_HIT", "Ignore hit result", "Spell cannot miss, or be dodged/parried/blocked" }; - case SPELL_ATTR3_DISABLE_PROC: return { "SPELL_ATTR3_DISABLE_PROC", "Cannot trigger spells during aura proc", "" }; + case SPELL_ATTR3_INSTANT_TARGET_PROCS: return { "SPELL_ATTR3_INSTANT_TARGET_PROCS", "Cannot trigger spells during aura proc", "" }; case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return { "SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD", "Persists through death", "" }; case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return { "SPELL_ATTR3_ONLY_PROC_OUTDOORS", "Unknown attribute 21@Attr3", "" }; case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return { "SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT", "Requires equipped Wand (Mainline: Do Not Trigger Target Stand)", "" }; case SPELL_ATTR3_NO_DAMAGE_HISTORY: return { "SPELL_ATTR3_NO_DAMAGE_HISTORY", "Unknown attribute 23@Attr3", "" }; case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return { "SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON", "Requires offhand weapon", "" }; case SPELL_ATTR3_TREAT_AS_PERIODIC: return { "SPELL_ATTR3_TREAT_AS_PERIODIC", "Treat as periodic effect", "" }; - case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return { "SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED", "Can trigger from triggered spells", "" }; + case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return { "SPELL_ATTR3_CAN_PROC_FROM_PROCS", "Can trigger from triggered spells", "" }; case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return { "SPELL_ATTR3_ONLY_PROC_ON_CASTER", "Drain Soul", "" }; case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return { "SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS", "Unknown attribute 28@Attr3", "" }; case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return { "SPELL_ATTR3_IGNORE_CASTER_MODIFIERS", "Damage dealt is unaffected by modifiers", "" }; @@ -597,7 +597,7 @@ AC_API_EXPORT SpellAttr3 EnumUtils::FromIndex(size_t index) case 6: return SPELL_ATTR3_NO_AVOIDANCE; case 7: return SPELL_ATTR3_DOT_STACKING_RULE; case 8: return SPELL_ATTR3_ONLY_ON_PLAYER; - case 9: return SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2; + case 9: return SPELL_ATTR3_NOT_A_PROC; case 10: return SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON; case 11: return SPELL_ATTR3_ONLY_BATTLEGROUNDS; case 12: return SPELL_ATTR3_ONLY_ON_GHOSTS; @@ -607,14 +607,14 @@ AC_API_EXPORT SpellAttr3 EnumUtils::FromIndex(size_t index) case 16: return SPELL_ATTR3_SUPRESS_CASTER_PROCS; case 17: return SPELL_ATTR3_SUPRESS_TARGET_PROCS; case 18: return SPELL_ATTR3_ALWAYS_HIT; - case 19: return SPELL_ATTR3_DISABLE_PROC; + case 19: return SPELL_ATTR3_INSTANT_TARGET_PROCS; case 20: return SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD; case 21: return SPELL_ATTR3_ONLY_PROC_OUTDOORS; case 22: return SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT; case 23: return SPELL_ATTR3_NO_DAMAGE_HISTORY; case 24: return SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON; case 25: return SPELL_ATTR3_TREAT_AS_PERIODIC; - case 26: return SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; + case 26: return SPELL_ATTR3_CAN_PROC_FROM_PROCS; case 27: return SPELL_ATTR3_ONLY_PROC_ON_CASTER; case 28: return SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS; case 29: return SPELL_ATTR3_IGNORE_CASTER_MODIFIERS; @@ -638,7 +638,7 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr3 value) case SPELL_ATTR3_NO_AVOIDANCE: return 6; case SPELL_ATTR3_DOT_STACKING_RULE: return 7; case SPELL_ATTR3_ONLY_ON_PLAYER: return 8; - case SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2: return 9; + case SPELL_ATTR3_NOT_A_PROC: return 9; case SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON: return 10; case SPELL_ATTR3_ONLY_BATTLEGROUNDS: return 11; case SPELL_ATTR3_ONLY_ON_GHOSTS: return 12; @@ -648,14 +648,14 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr3 value) case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return 16; case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return 17; case SPELL_ATTR3_ALWAYS_HIT: return 18; - case SPELL_ATTR3_DISABLE_PROC: return 19; + case SPELL_ATTR3_INSTANT_TARGET_PROCS: return 19; case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return 20; case SPELL_ATTR3_ONLY_PROC_OUTDOORS: return 21; case SPELL_ATTR3_CASTING_CANCELS_AUTOREPEAT: return 22; case SPELL_ATTR3_NO_DAMAGE_HISTORY: return 23; case SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON: return 24; case SPELL_ATTR3_TREAT_AS_PERIODIC: return 25; - case SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED: return 26; + case SPELL_ATTR3_CAN_PROC_FROM_PROCS: return 26; case SPELL_ATTR3_ONLY_PROC_ON_CASTER: return 27; case SPELL_ATTR3_IGNORE_CASTER_AND_TARGET_RESTRICTIONS: return 28; case SPELL_ATTR3_IGNORE_CASTER_MODIFIERS: return 29; From bf98a481b7bb61c9adc2800fe0d69de1781c2fb5 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Wed, 5 Oct 2022 19:55:34 +0000 Subject: [PATCH 10/25] chore(DB): import pending files Referenced commit(s): ad4ce0895f04e633e259941aee470c138700ee8e --- .../rev_1664980163888388800.sql => db_world/2022_10_05_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664980163888388800.sql => db_world/2022_10_05_00.sql} (99%) diff --git a/data/sql/updates/pending_db_world/rev_1664980163888388800.sql b/data/sql/updates/db_world/2022_10_05_00.sql similarity index 99% rename from data/sql/updates/pending_db_world/rev_1664980163888388800.sql rename to data/sql/updates/db_world/2022_10_05_00.sql index d7baaa402..55b9dbf16 100644 --- a/data/sql/updates/pending_db_world/rev_1664980163888388800.sql +++ b/data/sql/updates/db_world/2022_10_05_00.sql @@ -1,3 +1,4 @@ +-- DB update 2022_10_02_00 -> 2022_10_05_00 -- -- Restoring spell_proc to how it was before the commit. DROP TABLE IF EXISTS `spell_proc`; From 60efd8215db373d3bf7754e41f08c12ca9594a1e Mon Sep 17 00:00:00 2001 From: Angelo Venturini Date: Wed, 5 Oct 2022 21:06:11 -0300 Subject: [PATCH 11/25] fix(Core/Vehicle): Crash (#13180) --- src/server/game/Entities/Vehicle/Vehicle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 7256c0a6e..f4f7d1559 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -344,6 +344,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) ASSERT(seat->second.IsEmpty()); } + if (!seat->second.SeatInfo) + return false; + LOG_DEBUG("vehicles", "Unit {} enter vehicle entry {} id {} ({}) seat {}", unit->GetName(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUID().ToString(), (int32)seat->first); From 6fbfbc5f01d712f8b0967f22231257b7d42ea37f Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 02:13:00 +0200 Subject: [PATCH 12/25] =?UTF-8?q?fix(Scripts/Temple=20of=20AhnQiraj):=20Sa?= =?UTF-8?q?rtura's=20Sundering=20Cleave=20should=20be=E2=80=A6=20(#13184)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... casted on Whirlwind end. --- .../rev_1664616629895100900.sql | 2 + .../TempleOfAhnQiraj/boss_sartura.cpp | 42 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1664616629895100900.sql diff --git a/data/sql/updates/pending_db_world/rev_1664616629895100900.sql b/data/sql/updates/pending_db_world/rev_1664616629895100900.sql new file mode 100644 index 000000000..2a0a3bfd1 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664616629895100900.sql @@ -0,0 +1,2 @@ +-- +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=26084; diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp index 6dabe7337..2cb8072a8 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp @@ -49,14 +49,15 @@ enum events EVENT_SPELL_BERSERK = 4, EVENT_SARTURA_AGGRO_RESET = 5, EVENT_SARTURA_AGGRO_RESET_END = 6, + EVENT_SARTURA_SUNDERING_CLEAVE = 7, // Sartura's Royal Guard - EVENT_GUARD_WHIRLWIND = 7, - EVENT_GUARD_WHIRLWIND_RANDOM = 8, - EVENT_GUARD_WHIRLWIND_END = 9, - EVENT_GUARD_KNOCKBACK = 10, - EVENT_GUARD_AGGRO_RESET = 11, - EVENT_GUARD_AGGRO_RESET_END = 12 + EVENT_GUARD_WHIRLWIND = 8, + EVENT_GUARD_WHIRLWIND_RANDOM = 9, + EVENT_GUARD_WHIRLWIND_END = 10, + EVENT_GUARD_KNOCKBACK = 11, + EVENT_GUARD_AGGRO_RESET = 12, + EVENT_GUARD_AGGRO_RESET_END = 13 }; struct boss_sartura : public BossAI @@ -99,6 +100,7 @@ struct boss_sartura : public BossAI events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 30000); events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(45000, 55000)); events.ScheduleEvent(EVENT_SPELL_BERSERK, 10 * 60000); + events.ScheduleEvent(EVENT_SARTURA_SUNDERING_CLEAVE, 2400ms, 3s); } void JustDied(Unit* /*killer*/) override @@ -121,14 +123,6 @@ struct boss_sartura : public BossAI } } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id != SPELL_SUNDERING_CLEAVE) - return; - - me->RemoveAura(SPELL_SUNDERING_CLEAVE); - } - void UpdateAI(uint32 diff) override { if (!UpdateVictim()) @@ -203,6 +197,18 @@ struct boss_sartura : public BossAI berserked = true; } break; + case EVENT_SARTURA_SUNDERING_CLEAVE: + if (whirlwind) + { + Milliseconds whirlwindTimer = events.GetTimeUntilEvent(EVENT_SARTURA_WHIRLWIND_END); + events.RescheduleEvent(EVENT_SARTURA_SUNDERING_CLEAVE, whirlwindTimer + 500ms); + } + else + { + DoCastVictim(SPELL_SUNDERING_CLEAVE, false); + events.RescheduleEvent(EVENT_SARTURA_SUNDERING_CLEAVE, 2400ms, 3s); + } + break; default: break; } @@ -238,14 +244,6 @@ struct npc_sartura_royal_guard : public ScriptedAI events.ScheduleEvent(EVENT_GUARD_KNOCKBACK, 10000); } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id != SPELL_SUNDERING_CLEAVE) - return; - - me->RemoveAura(SPELL_SUNDERING_CLEAVE); - } - void UpdateAI(uint32 diff) override { if (!UpdateVictim()) From f386e35d8cf2ccba87d8db106b1702e99fd11fa2 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 00:14:58 +0000 Subject: [PATCH 13/25] chore(DB): import pending files Referenced commit(s): 6fbfbc5f01d712f8b0967f22231257b7d42ea37f --- .../rev_1664616629895100900.sql => db_world/2022_10_06_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664616629895100900.sql => db_world/2022_10_06_00.sql} (59%) diff --git a/data/sql/updates/pending_db_world/rev_1664616629895100900.sql b/data/sql/updates/db_world/2022_10_06_00.sql similarity index 59% rename from data/sql/updates/pending_db_world/rev_1664616629895100900.sql rename to data/sql/updates/db_world/2022_10_06_00.sql index 2a0a3bfd1..44020d188 100644 --- a/data/sql/updates/pending_db_world/rev_1664616629895100900.sql +++ b/data/sql/updates/db_world/2022_10_06_00.sql @@ -1,2 +1,3 @@ +-- DB update 2022_10_05_00 -> 2022_10_06_00 -- DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=26084; From 78a383f4f7dea20777fd1b936901895b2ec29410 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 02:35:46 +0200 Subject: [PATCH 14/25] =?UTF-8?q?fix(Core/Spells):=20Rental=20Racing=20Ram?= =?UTF-8?q?=20will=20not=20be=20removed=20upon=20entering=E2=80=A6=20(#131?= =?UTF-8?q?92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...water. --- src/server/game/Spells/SpellInfoCorrections.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index e9f247979..d113409af 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4409,6 +4409,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(27); }); + // Rental Racing Ram + ApplySpellFix({ 43883 }, [](SpellInfo* spellInfo) + { + spellInfo->AuraInterruptFlags &= ~AURA_INTERRUPT_FLAG_NOT_ABOVEWATER; + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; From 8a6a8cc9cc8e21e73ec9c82d7d9d0c92bb6c1ca4 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 02:38:08 +0200 Subject: [PATCH 15/25] fix(DB/Disables): Ossirian Crystals should not block LoS. (#13210) --- data/sql/updates/pending_db_world/rev_1664728395247854700.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1664728395247854700.sql diff --git a/data/sql/updates/pending_db_world/rev_1664728395247854700.sql b/data/sql/updates/pending_db_world/rev_1664728395247854700.sql new file mode 100644 index 000000000..ad96e0187 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664728395247854700.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `disables` WHERE `sourceType`=7 AND `entry`=180619; +INSERT INTO `disables` VALUES +(7,180619,0,0,0,'Ignore LoS by Ossirian Crystal'); From 0cd0d0dad3008411d823a01eea6b35ac89adf22f Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 00:40:21 +0000 Subject: [PATCH 16/25] chore(DB): import pending files Referenced commit(s): 8a6a8cc9cc8e21e73ec9c82d7d9d0c92bb6c1ca4 --- .../rev_1664728395247854700.sql => db_world/2022_10_06_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664728395247854700.sql => db_world/2022_10_06_01.sql} (77%) diff --git a/data/sql/updates/pending_db_world/rev_1664728395247854700.sql b/data/sql/updates/db_world/2022_10_06_01.sql similarity index 77% rename from data/sql/updates/pending_db_world/rev_1664728395247854700.sql rename to data/sql/updates/db_world/2022_10_06_01.sql index ad96e0187..09298ba0b 100644 --- a/data/sql/updates/pending_db_world/rev_1664728395247854700.sql +++ b/data/sql/updates/db_world/2022_10_06_01.sql @@ -1,3 +1,4 @@ +-- DB update 2022_10_06_00 -> 2022_10_06_01 -- DELETE FROM `disables` WHERE `sourceType`=7 AND `entry`=180619; INSERT INTO `disables` VALUES From bd02bf5ab40795cb8224159eee9d1735b1263b31 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 02:43:23 +0200 Subject: [PATCH 17/25] =?UTF-8?q?fix(DB/Spells):=20Using=20Ossirian=20Crys?= =?UTF-8?q?tal=20should=20not=20prevent=20from=20castin=E2=80=A6=20(#13211?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...g other spells. --- data/sql/updates/pending_db_world/rev_1664729326847928700.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1664729326847928700.sql diff --git a/data/sql/updates/pending_db_world/rev_1664729326847928700.sql b/data/sql/updates/pending_db_world/rev_1664729326847928700.sql new file mode 100644 index 000000000..3d0fcfb94 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664729326847928700.sql @@ -0,0 +1,2 @@ +-- +UPDATE `spell_dbc` SET `CastingTimeIndex`=1 WHERE `id`=25186; From fab614d709337cf135f87ec1ea5b77f8e46544bf Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 00:45:28 +0000 Subject: [PATCH 18/25] chore(DB): import pending files Referenced commit(s): bd02bf5ab40795cb8224159eee9d1735b1263b31 --- .../rev_1664729326847928700.sql => db_world/2022_10_06_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664729326847928700.sql => db_world/2022_10_06_02.sql} (59%) diff --git a/data/sql/updates/pending_db_world/rev_1664729326847928700.sql b/data/sql/updates/db_world/2022_10_06_02.sql similarity index 59% rename from data/sql/updates/pending_db_world/rev_1664729326847928700.sql rename to data/sql/updates/db_world/2022_10_06_02.sql index 3d0fcfb94..5725930e9 100644 --- a/data/sql/updates/pending_db_world/rev_1664729326847928700.sql +++ b/data/sql/updates/db_world/2022_10_06_02.sql @@ -1,2 +1,3 @@ +-- DB update 2022_10_06_01 -> 2022_10_06_02 -- UPDATE `spell_dbc` SET `CastingTimeIndex`=1 WHERE `id`=25186; From 26017b645e3f15bdc137dd12ad176d2927629246 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 5 Oct 2022 22:17:45 -0300 Subject: [PATCH 19/25] fix(Scripts/TempleOfAhnQiraj): C'thun (#13153) --- .../rev_1664246616057619800.sql | 11 ++ .../Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp | 151 +++++++++++------- 2 files changed, 108 insertions(+), 54 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1664246616057619800.sql diff --git a/data/sql/updates/pending_db_world/rev_1664246616057619800.sql b/data/sql/updates/pending_db_world/rev_1664246616057619800.sql new file mode 100644 index 000000000..677a183ca --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664246616057619800.sql @@ -0,0 +1,11 @@ +-- +DELETE FROM `creature_template_movement` WHERE `creatureId` IN (21221, 15728, 15334, 15802, 15725, 15726); +INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES +(21221, 1, 0, 0, 1, 0, 0, 0), +(15728, 1, 0, 0, 1, 0, 0, 0), +(15334, 1, 0, 0, 1, 0, 0, 0), +(15802, 1, 0, 0, 1, 0, 0, 0), +(15725, 1, 0, 0, 1, 0, 0, 0), +(15726, 1, 0, 0, 1, 0, 0, 0); + +UPDATE `creature_template` SET `unit_flags` = `unit_flags` |33554432 WHERE `entry` IN (15910, 15904, 15896); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 9c19e2747..21e6faab3 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -70,6 +70,7 @@ enum Spells // Tentacles SPELL_SUBMERGE_VISUAL = 26234, SPELL_BIRTH = 26262, + SPELL_ROCKY_GROUND_IMPACT = 26271, // Areatriggers SPELL_SPIT_OUT = 25383, @@ -186,9 +187,9 @@ struct boss_eye_of_cthun : public BossAI void EnterCombat(Unit* who) override { - DoZoneInCombat(); ScheduleTasks(); BossAI::EnterCombat(who); + _beamTarget = who->GetGUID(); } void MoveInLineOfSight(Unit* who) override @@ -222,11 +223,29 @@ struct boss_eye_of_cthun : public BossAI _scheduler. Schedule(3s, [this](TaskContext task) { - DoCastRandomTarget(SPELL_GREEN_BEAM); + if (task.GetRepeatCounter() < 3) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, _beamTarget)) + { + DoCast(target, SPELL_GREEN_BEAM); + } + + task.Repeat(); + } + else + { + _scheduler.Schedule(5s, [this](TaskContext task) + { + DoCastRandomTarget(SPELL_GREEN_BEAM); + + task.SetGroup(GROUP_BEAM_PHASE); + task.Repeat(3s); + }); + } + task.SetGroup(GROUP_BEAM_PHASE); - task.Repeat(); }) - .Schedule(12s, [this](TaskContext task) + .Schedule(8s, [this](TaskContext task) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) { @@ -324,48 +343,32 @@ struct boss_eye_of_cthun : public BossAI void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { - switch (instance->GetData(DATA_CTHUN_PHASE)) + //Only if it will kill + if (damage < me->GetHealth()) + return; + + //Fake death in phase 0 or 1 (green beam or dark glare phase) + me->InterruptNonMeleeSpells(false); + + //Remove Red coloration from c'thun + me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); + + //Reset to normal emote state and prevent select and attack + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + //Remove Target field + me->SetTarget(); + + me->SetHealth(0); + damage = 0; + + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + _scheduler.CancelAll(); + + if (Creature* cthun = instance->GetCreature(DATA_CTHUN)) { - case PHASE_EYE_GREEN_BEAM: - case PHASE_EYE_RED_BEAM: - //Only if it will kill - if (damage < me->GetHealth()) - return; - - //Fake death in phase 0 or 1 (green beam or dark glare phase) - me->InterruptNonMeleeSpells(false); - - //Remove Red coloration from c'thun - me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - //Reset to normal emote state and prevent select and attack - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - //Remove Target field - me->SetTarget(); - - me->SetHealth(0); - damage = 0; - - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - _scheduler.CancelAll(); - - if (Creature* cthun = instance->GetCreature(DATA_CTHUN)) - { - cthun->AI()->DoAction(ACTION_START_PHASE_TWO); - } - - break; - - case PHASE_CTHUN_DONE: - //Allow death here - return; - - default: - //Prevent death in these phases - damage = 0; - return; + cthun->AI()->DoAction(ACTION_START_PHASE_TWO); } } @@ -376,6 +379,7 @@ private: bool ClockWise; uint32 _eyeTentacleCounter; + ObjectGuid _beamTarget; TaskScheduler _scheduler; }; @@ -424,7 +428,7 @@ struct boss_cthun : public BossAI //Spawn flesh tentacle for (uint8 i = 0; i < 2; i++) { - me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN); + me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); } ScheduleTasks(); @@ -457,25 +461,27 @@ struct boss_cthun : public BossAI } context.Repeat(30s); - }).Schedule(15s, [this](TaskContext context) + }).Schedule(8s, [this](TaskContext context) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID)) { //Spawn claw tentacle on the random target if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) - if (spawned->AI()) - spawned->AI()->AttackStart(target); + { + spawned->AI()->AttackStart(target); + } } context.Repeat(1min); - }).Schedule(15s, [this](TaskContext context) + }).Schedule(38s, [this](TaskContext context) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID)) { //Spawn claw tentacle on the random target if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) - if (spawned->AI()) - spawned->AI()->AttackStart(target); + { + spawned->AI()->AttackStart(target); + } } context.Repeat(1min); @@ -536,6 +542,8 @@ struct boss_cthun : public BossAI { ++_fleshTentaclesKilled; + creature->CastSpell(creature, SPELL_ROCKY_GROUND_IMPACT, true); + if (_fleshTentaclesKilled > 1) { _scheduler.CancelAll(); @@ -580,6 +588,14 @@ struct npc_eye_tentacle : public ScriptedAI { portal->SetReactState(REACT_PASSIVE); _portalGUID = portal->GetGUID(); + + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + { + if (Creature* creature = summoner->ToCreature()) + { + creature->AI()->JustSummoned(portal); + } + } } SetCombatMovement(false); @@ -643,6 +659,14 @@ struct npc_claw_tentacle : public ScriptedAI { portal->SetReactState(REACT_PASSIVE); _portalGUID = portal->GetGUID(); + + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + { + if (Creature* creature = summoner->ToCreature()) + { + creature->AI()->JustSummoned(portal); + } + } } } @@ -702,6 +726,14 @@ struct npc_giant_claw_tentacle : public ScriptedAI { portal->SetReactState(REACT_PASSIVE); _portalGUID = portal->GetGUID(); + + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + { + if (Creature* creature = summoner->ToCreature()) + { + creature->AI()->JustSummoned(portal); + } + } } } @@ -835,6 +867,14 @@ struct npc_giant_eye_tentacle : public ScriptedAI { portal->SetReactState(REACT_PASSIVE); _portalGUID = portal->GetGUID(); + + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + { + if (Creature* creature = summoner->ToCreature()) + { + creature->AI()->JustSummoned(portal); + } + } } } @@ -931,9 +971,12 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override { - if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f)) + if (InstanceScript* instance = player->GetInstanceScript()) { - trigger->CastSpell(player, SPELL_SPIT_OUT, true); + if (Creature* cthun = instance->GetCreature(DATA_CTHUN)) + { + cthun->CastSpell(player, SPELL_SPIT_OUT, true); + } } return true; From f720bf6f745ebf73539f693027fee1e875df3073 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 01:19:46 +0000 Subject: [PATCH 20/25] chore(DB): import pending files Referenced commit(s): 26017b645e3f15bdc137dd12ad176d2927629246 --- .../rev_1664246616057619800.sql => db_world/2022_10_06_03.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664246616057619800.sql => db_world/2022_10_06_03.sql} (92%) diff --git a/data/sql/updates/pending_db_world/rev_1664246616057619800.sql b/data/sql/updates/db_world/2022_10_06_03.sql similarity index 92% rename from data/sql/updates/pending_db_world/rev_1664246616057619800.sql rename to data/sql/updates/db_world/2022_10_06_03.sql index 677a183ca..78ec7fb10 100644 --- a/data/sql/updates/pending_db_world/rev_1664246616057619800.sql +++ b/data/sql/updates/db_world/2022_10_06_03.sql @@ -1,3 +1,4 @@ +-- DB update 2022_10_06_02 -> 2022_10_06_03 -- DELETE FROM `creature_template_movement` WHERE `creatureId` IN (21221, 15728, 15334, 15802, 15725, 15726); INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES From c34cb0c54a2becaf28f4f6368a2f64c06bd874d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francesco=20Borz=C3=AC?= Date: Thu, 6 Oct 2022 03:20:58 +0200 Subject: [PATCH 21/25] fix(DB/QuestPOI): Trial of the Sea Lion (#13302) Co-authored-by: Malcrom --- .../updates/pending_db_world/rev_1645510338718214836.sql | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1645510338718214836.sql diff --git a/data/sql/updates/pending_db_world/rev_1645510338718214836.sql b/data/sql/updates/pending_db_world/rev_1645510338718214836.sql new file mode 100644 index 000000000..5300953bd --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1645510338718214836.sql @@ -0,0 +1,6 @@ +-- Horde "Trial of the Sea Lion" Quest ID 30 POI fix +UPDATE `quest_poi` SET `WorldMapAreaId`=17 WHERE `QuestID`=30 AND `MapID`=1; +UPDATE `quest_poi_points` SET `X`=1050, `Y`=-3119 WHERE `QuestID`=30 AND `Idx1`=2; +-- Alliance "Trial of the Sea Lion" Quest ID 272 POI fix +UPDATE `quest_poi` SET `WorldMapAreaId`=40 WHERE `QuestID`=272 AND `MapID`=0; +UPDATE `quest_poi_points` SET `X`=-10172, `Y`=2391 WHERE `QuestID`=272 AND `Idx1`=2; From 52353733636b82b77f38fb705775813035bde90d Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 01:23:08 +0000 Subject: [PATCH 22/25] chore(DB): import pending files Referenced commit(s): c34cb0c54a2becaf28f4f6368a2f64c06bd874d7 --- .../rev_1645510338718214836.sql => db_world/2022_10_06_04.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1645510338718214836.sql => db_world/2022_10_06_04.sql} (90%) diff --git a/data/sql/updates/pending_db_world/rev_1645510338718214836.sql b/data/sql/updates/db_world/2022_10_06_04.sql similarity index 90% rename from data/sql/updates/pending_db_world/rev_1645510338718214836.sql rename to data/sql/updates/db_world/2022_10_06_04.sql index 5300953bd..bcec71c02 100644 --- a/data/sql/updates/pending_db_world/rev_1645510338718214836.sql +++ b/data/sql/updates/db_world/2022_10_06_04.sql @@ -1,3 +1,4 @@ +-- DB update 2022_10_06_03 -> 2022_10_06_04 -- Horde "Trial of the Sea Lion" Quest ID 30 POI fix UPDATE `quest_poi` SET `WorldMapAreaId`=17 WHERE `QuestID`=30 AND `MapID`=1; UPDATE `quest_poi_points` SET `X`=1050, `Y`=-3119 WHERE `QuestID`=30 AND `Idx1`=2; From 29ea8a2e596c02f80f0ae2489aafda8b42bf8ec9 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 03:36:08 +0200 Subject: [PATCH 23/25] fix(Scripts/Temple of AhnQiraj): Adjusted Sartura's event timers. (#13187) --- src/common/Utilities/EventMap.h | 10 ++++------ .../Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h index 1ed115e42..1d3df6222 100644 --- a/src/common/Utilities/EventMap.h +++ b/src/common/Utilities/EventMap.h @@ -182,12 +182,9 @@ public: void RescheduleEvent(uint32 eventId, Milliseconds minTime, Milliseconds maxTime, uint32 group = 0, uint32 phase = 0); /** - * @name RescheduleEvent - * @brief Cancels the given event and reschedules it. - * @param eventId The id of the event. - * @param time The time in milliseconds until the event occurs. - * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. - * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. + * @name RepeatEvent + * @brief Repeats the most recently executed event. + * @param time Time until the event occurs as std::chrono type. */ void RepeatEvent(uint32 time); @@ -199,6 +196,7 @@ public: void Repeat(Milliseconds time); /** + * @name RepeatEvent * @brief Repeats the most recently executed event. * @param minTime The minimum time until the event occurs as std::chrono type. diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp index 2cb8072a8..46de14dcc 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp @@ -97,7 +97,7 @@ struct boss_sartura : public BossAI { BossAI::EnterCombat(who); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 30000); + events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 12s, 22s); events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(45000, 55000)); events.ScheduleEvent(EVENT_SPELL_BERSERK, 10 * 60000); events.ScheduleEvent(EVENT_SARTURA_SUNDERING_CLEAVE, 2400ms, 3s); @@ -155,7 +155,7 @@ struct boss_sartura : public BossAI case EVENT_SARTURA_WHIRLWIND_END: events.CancelEvent(EVENT_SARTURA_WHIRLWIND_RANDOM); whirlwind = false; - events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, urand(25000, 40000)); + events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 5s, 11s); break; case EVENT_SARTURA_AGGRO_RESET: if (aggroReset == false) @@ -239,9 +239,9 @@ struct npc_sartura_royal_guard : public ScriptedAI void EnterCombat(Unit* /*who*/) override { - events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, 30000); + events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, 6s, 10s); events.ScheduleEvent(EVENT_GUARD_AGGRO_RESET, urand(45000, 55000)); - events.ScheduleEvent(EVENT_GUARD_KNOCKBACK, 10000); + events.ScheduleEvent(EVENT_GUARD_KNOCKBACK, 12s, 16s); } void UpdateAI(uint32 diff) override @@ -259,7 +259,7 @@ struct npc_sartura_royal_guard : public ScriptedAI DoCastSelf(SPELL_GUARD_WHIRLWIND); whirlwind = true; events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_RANDOM, urand(3000, 7000)); - events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_END, 15000); + events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_END, 8s); break; case EVENT_GUARD_WHIRLWIND_RANDOM: if (whirlwind == true) @@ -276,7 +276,7 @@ struct npc_sartura_royal_guard : public ScriptedAI case EVENT_GUARD_WHIRLWIND_END: events.CancelEvent(EVENT_GUARD_WHIRLWIND_RANDOM); whirlwind = false; - events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, urand(25000, 40000)); + events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, 500ms, 9s); break; case EVENT_GUARD_AGGRO_RESET: if (aggroReset == true) @@ -313,7 +313,7 @@ struct npc_sartura_royal_guard : public ScriptedAI break; case EVENT_GUARD_KNOCKBACK: DoCastVictim(SPELL_GUARD_KNOCKBACK); - events.RepeatEvent(urand(10000, 20000)); + events.Repeat(21s, 37s); break; } } From 0ae8790956a121f93a83e000b1e1fab442623a14 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 6 Oct 2022 05:18:05 +0200 Subject: [PATCH 24/25] fix(Core/Creatures): Renamed `CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE` to `CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL` (#13130) --- .../updates/pending_db_world/rev_1664702825623205700.sql | 2 ++ src/server/game/Entities/Creature/Creature.cpp | 6 ++++++ src/server/game/Entities/Creature/CreatureData.h | 2 +- .../game/Entities/Creature/enuminfo_CreatureData.cpp | 6 +++--- src/server/game/Entities/Unit/Unit.cpp | 8 ++------ 5 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1664702825623205700.sql diff --git a/data/sql/updates/pending_db_world/rev_1664702825623205700.sql b/data/sql/updates/pending_db_world/rev_1664702825623205700.sql new file mode 100644 index 000000000..e24f686a3 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1664702825623205700.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x02000000 WHERE `entry` IN (15341,14834,11380,12460); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 512e7c39e..4fbf74345 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2423,6 +2423,12 @@ bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction / if (GetCharmerOrOwnerGUID()) return false; + // Check for ignore assistance extra flag + if (m_creatureInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL)) + { + return false; + } + // only from same creature faction if (checkfaction) { diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 519b640f6..eaff79bce 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -71,7 +71,7 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_AVOID_AOE = 0x00400000, // pussywizard: ignored by aoe attacks (for icc blood prince council npc - Dark Nucleus) CREATURE_FLAG_EXTRA_NO_DODGE = 0x00800000, // xinef: target cannot dodge CREATURE_FLAG_EXTRA_MODULE = 0x01000000, - CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE = 0x02000000, // Creatures do not call periodically assistance in combat + CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL = 0x02000000, // Creatures are not aggroed by other mobs assistance functions CREATURE_FLAG_EXTRA_UNUSED_27 = 0x04000000, CREATURE_FLAG_EXTRA_UNUSED_28 = 0x08000000, CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB) diff --git a/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp b/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp index 4e294ae4e..e6e79e755 100644 --- a/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp +++ b/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp @@ -56,7 +56,7 @@ AC_API_EXPORT EnumText EnumUtils::ToString(CreatureFlagsExtr case CREATURE_FLAG_EXTRA_AVOID_AOE: return { "CREATURE_FLAG_EXTRA_AVOID_AOE", "CREATURE_FLAG_EXTRA_AVOID_AOE", "pussywizard: ignored by aoe attacks (for icc blood prince council npc - Dark Nucleus)" }; case CREATURE_FLAG_EXTRA_NO_DODGE: return { "CREATURE_FLAG_EXTRA_NO_DODGE", "CREATURE_FLAG_EXTRA_NO_DODGE", "xinef: target cannot dodge" }; case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "Used by module creatures to avoid blizzlike checks." }; - case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Creatures do not call periodically assistance in combat", "" }; + case CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL: return { "CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL", "Creatures are not aggroed by other mobs assistance functions", "" }; case CREATURE_FLAG_EXTRA_UNUSED_27: return { "CREATURE_FLAG_EXTRA_UNUSED_27", "CREATURE_FLAG_EXTRA_UNUSED_27", "" }; case CREATURE_FLAG_EXTRA_UNUSED_28: return { "CREATURE_FLAG_EXTRA_UNUSED_28", "CREATURE_FLAG_EXTRA_UNUSED_28", "" }; case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return { "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)" }; @@ -100,7 +100,7 @@ AC_API_EXPORT CreatureFlagsExtra EnumUtils::FromIndex(size_t case 22: return CREATURE_FLAG_EXTRA_AVOID_AOE; case 23: return CREATURE_FLAG_EXTRA_NO_DODGE; case 24: return CREATURE_FLAG_EXTRA_MODULE; - case 25: return CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE; + case 25: return CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL; case 26: return CREATURE_FLAG_EXTRA_UNUSED_27; case 27: return CREATURE_FLAG_EXTRA_UNUSED_28; case 28: return CREATURE_FLAG_EXTRA_DUNGEON_BOSS; @@ -141,7 +141,7 @@ AC_API_EXPORT size_t EnumUtils::ToIndex(CreatureFlagsExtra v case CREATURE_FLAG_EXTRA_AVOID_AOE: return 22; case CREATURE_FLAG_EXTRA_NO_DODGE: return 23; case CREATURE_FLAG_EXTRA_MODULE: return 24; - case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return 25; + case CREATURE_FLAG_EXTRA_IGNORE_ASSISTANCE_CALL: return 25; case CREATURE_FLAG_EXTRA_UNUSED_27: return 26; case CREATURE_FLAG_EXTRA_UNUSED_28: return 27; case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return 28; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d190cbdcd..230e256a3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10014,12 +10014,8 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) creature->SendAIReaction(AI_REACTION_HOSTILE); - CreatureTemplate const* cInfo = creature->GetCreatureTemplate(); - if (!cInfo || !cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE)) - { - creature->CallAssistance(); - creature->SetAssistanceTimer(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD)); - } + creature->CallAssistance(); + creature->SetAssistanceTimer(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD)); SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); } From 177acf626c39a46f1b3921998c0d30cdbc2779ad Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 6 Oct 2022 03:20:05 +0000 Subject: [PATCH 25/25] chore(DB): import pending files Referenced commit(s): 0ae8790956a121f93a83e000b1e1fab442623a14 --- .../rev_1664702825623205700.sql => db_world/2022_10_06_05.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1664702825623205700.sql => db_world/2022_10_06_05.sql} (72%) diff --git a/data/sql/updates/pending_db_world/rev_1664702825623205700.sql b/data/sql/updates/db_world/2022_10_06_05.sql similarity index 72% rename from data/sql/updates/pending_db_world/rev_1664702825623205700.sql rename to data/sql/updates/db_world/2022_10_06_05.sql index e24f686a3..2c30a9860 100644 --- a/data/sql/updates/pending_db_world/rev_1664702825623205700.sql +++ b/data/sql/updates/db_world/2022_10_06_05.sql @@ -1,2 +1,3 @@ +-- DB update 2022_10_06_04 -> 2022_10_06_05 -- UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x02000000 WHERE `entry` IN (15341,14834,11380,12460);