fix(Core/Spells): Implement TrinityCore spell_group and spell_group_stack_rules (#23346)

Co-authored-by: treeston <treeston.mmoc@gmail.com>
Co-authored-by: Trisjdc <trisjdc@gmail.com>
Co-authored-by: QAston <none@none>
Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Jelle Meeus <sogladev@gmail.com>
This commit is contained in:
Tereneckla 2025-11-28 19:01:25 +00:00 committed by GitHub
parent 55989205e7
commit 2f7f9bd72f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1976 additions and 1705 deletions

View file

@ -0,0 +1,213 @@
ALTER TABLE `spell_group` DROP `special_flag`;
ALTER TABLE `spell_group` MODIFY COLUMN `spell_id` int;
-- import from trinitycore
DELETE FROM `spell_group`;
INSERT INTO `spell_group` (`id`,`spell_id`) VALUES
(1, 2367), (1, 2374), (1, 3160), (1, 3164), (1, 7844), (1, 8212), (1, 10667), (1, 10669), (1, 11328), (1, 11334), (1, 11390), (1, 11405), (1, 11406), (1, 11474), (1, 16322), (1, 16323), (1, 16329), (1, 17038), (1, 17537), (1, 17538), (1, 17539), (1, 17626), (1, 17627), (1, 17628), (1, 17629), (1, 21920), (1, 26276), (1, 28486), (1, 28488), (1, 28490), (1, 28491), (1, 28493), (1, 28497), (1, 28501), (1, 28503), (1, 28518), (1, 28519), (1, 28520), (1, 28521), (1, 28540), (1, 33720), (1, 33721), (1, 33726), (1, 38954), (1, 40567), (1, 40568), (1, 40572), (1, 40573), (1, 40575), (1, 40576), (1, 41608), (1, 41609), (1, 41610), (1, 41611), (1, 42735), (1, 45373), (1, 46837), (1, 46839), (1, 53746), (1, 53748), (1, 53749), (1, 53752), (1, 53755), (1, 53758), (1, 53760), (1, 54212), (1, 54452), (1, 54494), (1, 60340), (1, 60341), (1, 60344), (1, 60345), (1, 60346), (1, 62380), (1, 63729), (1, 67016), (1, 67017), (1, 67018),
(2, 673), (2, 2378), (2, 2380), (2, 3166), (2, 3219), (2, 3220), (2, 3222), (2, 3223), (2, 3593), (2, 10668), (2, 10692), (2, 10693), (2, 11319), (2, 11348), (2, 11349), (2, 11371), (2, 11396), (2, 15231), (2, 15233), (2, 16321), (2, 16325), (2, 16326), (2, 16327), (2, 17535), (2, 17626), (2, 17627), (2, 17628), (2, 17629), (2, 24361), (2, 24363), (2, 24382), (2, 24383), (2, 24417), (2, 27652), (2, 27653), (2, 28502), (2, 28509), (2, 28514), (2, 28518), (2, 28519), (2, 28520), (2, 28521), (2, 28540), (2, 29348), (2, 39625), (2, 39626), (2, 39627), (2, 39628), (2, 40567), (2, 40568), (2, 40572), (2, 40573), (2, 40575), (2, 40576), (2, 41608), (2, 41609), (2, 41610), (2, 41611), (2, 42735), (2, 46837), (2, 46839), (2, 53747), (2, 53751), (2, 53752), (2, 53755), (2, 53758), (2, 53760), (2, 53763), (2, 53764), (2, 54212), (2, 60343), (2, 60347), (2, 62380), (2, 67016), (2, 67017), (2, 67018),
(1001, 18125), (1001, 18141), (1001, 19705), (1001, 19706), (1001, 19708), (1001, 19709), (1001, 19710), (1001, 19711), (1001, 20875), (1001, 23697), (1001, 24799), (1001, 24870), (1001, 25037), (1001, 25694), (1001, 25722), (1001, 25804), (1001, 25941), (1001, 33254), (1001, 33256), (1001, 33257), (1001, 33259), (1001, 33261), (1001, 33263), (1001, 33265), (1001, 33268), (1001, 33272), (1001, 35272), (1001, 40323), (1001, 42293), (1001, 43722), (1001, 43764), (1001, 43771), (1001, 44097), (1001, 44098), (1001, 44099), (1001, 44100), (1001, 44101), (1001, 44102), (1001, 44104), (1001, 44105), (1001, 44106), (1001, 45245), (1001, 45619), (1001, 45694), (1001, 46682), (1001, 46687), (1001, 46899), (1001, 53284), (1001, 57079), (1001, 57097), (1001, 57100), (1001, 57102), (1001, 57107), (1001, 57111), (1001, 57139), (1001, 57286), (1001, 57288), (1001, 57291), (1001, 57294), (1001, 57325), (1001, 57327), (1001, 57329), (1001, 57332), (1001, 57334), (1001, 57356), (1001, 57358), (1001, 57360), (1001, 57363), (1001, 57365), (1001, 57367), (1001, 57371), (1001, 57373), (1001, 57399), (1001, 58468), (1001, 58479), (1001, 59230), (1001, 62349), (1001, 64057), (1001, 65247), (1001, 65365), (1001, 65410), (1001, 65412), (1001, 65414), (1001, 65415), (1001, 65416), (1001, 66623), (1001, 66624), (1001, 69559),
(1002, 19740), (1002, 25782), (1002, 56520), -- Blessing of Might
(1003, 6673), -- Battle Shout
(1004, -1003), (1004, -1002), -- Flap AP Buffs
(1005, 19742), (1005, 25894), (1005, 56521), -- Blessing of Wisdom
(1006, 20217), (1006, 25898), (1006, 43223), (1006, 56525), (1006, 58054), (1006, 72586), -- All Stats Percentage
(1007, 20911), (1007, 25899), -- Blessing of Sanctuary
(1008, 23415), (1008, 41450), -- Blessing of Protection
(1009, 32770), -- Blessing of Light
(1010, -1009), (1010, -1008), (1010, -1007), (1010, -1006), (1010, -1005), (1010, -1002), -- Blessings
(1011, -1091), (1011, -1003), -- Warrior Shouts
(1012, 55749), -- Acid Spit
(1013, 8647), -- Expose Armor
(1014, 58567), -- Sunder Armor
(1015, -1014), (1015, -1013), (1015, -1012), -- Major Armor Debuffs
(1016, 770), (1016, 16857), -- Faerie Fire
(1017, 56626), -- Sting
(1019, -1063), (1019, -1017), (1019, -1016), -- Minor Armor Debuffs
(1020, 55610), -- Icy Talons
(1021, 8515), -- Windfury Totem
(1022, -1021), (1022, -1020), -- Melee Haste Buffs
(1023, 24932), -- Leader of the Pack
(1024, 29801), -- Rampage
(1025, -1024), (1025, -1023), -- Physical Crit Buffs
(1026, 53137), -- Abomination's Might
(1027, 19506), -- Trueshot Aura
(1028, 30802), -- Unleashed Rage
(1029, -1028), (1029, -1027), (1029, -1026), -- Percentage AP Buffs
(1030, 33878), -- Mangle (Bear)
(1031, 33876), -- Mangle (Cat)
(1032, 46856), -- Trauma
(1033, -1032), (1033, -1031), (1033, -1030), -- Bleed Debuffs
(1034, 24907), -- Moonkin Aura
(1035, 51466), -- Elemental Oath
(1036, -1035), (1036, -1034), -- Spell Crit Buffs
(1037, 12579), (1037, 17794), (1037, 17797), (1037, 17798), (1037, 17799), (1037, 17800), (1037, 22959), -- Spell Crit Debuffs
(1038, -1006), (1038, 67480), -- All Stats Percentage with Sanctuary
-- 1039-44
(1045, 52109), -- Flametongue Totem
(1046, 57658), -- Totem of Wrath
(1047, 48090), -- Demonic Pact
(1048, -1047), (1048, -1046), (1048, -1045), -- Spell Power Buffs
-- 1049
(1050, 33196), -- Misery
(1051, -1050), (1051, -1016), -- Spell Hit Debuffs
(1052, 7294), -- Retribution Aura
(1053, 63531), -- Sanctified Retribution
(1054, -1053), (1054, -1052), (1054, 50170), -- Haste Buffs
-- 1055
(1056, -1053), (1056, -1052), (1056, 31579), (1056, 75593), -- Damage Done Buffs
(1057, 13218), -- Wound Poison
(1058, -1057), (1058, 2818), (1058, 3409), (1058, 5760), (1058, 21183), (1058, 30708), -- Crit Taken Debuffs
(1059, 89), (1059, 6136), (1059, 6343), (1059, 6360), (1059, 7321), (1059, 8042), (1059, 16914), (1059, 20005), (1059, 27648), (1059, 51693), (1059, 55095), (1059, 58179), (1059, 68055), -- Attack Speed Debuffs
(1060, 3043), (1060, 5570), -- Hit Chance Debuffs
(1061, -1057), (1061, 12294), (1061, 19434), (1061, 56112), -- Healing Taken Debuffs
(1062, -1063), (1062, 67), (1062, 99), (1062, 1160), -- AP Debuffs
(1063, 702), -- Curse of Weakness
(1064, 8076), -- Strength of Earth
(1065, 57330), -- Horn of Winter
(1066, 8118), -- Strength Scroll
(1067, 8115), -- Agility Scroll
(1068, 8096), -- Intellect Scroll
(1069, 8099), -- Stamina Scroll
(1070, 8112), -- Spirit Scroll
(1071, 8091), -- Armor Scroll
(1072, 1459), -- Arcane Intellect
(1073, 54424), -- Fel Intelligence
(1074, 1243), -- Power Word: Fortitude
(1075, 21562), -- Prayer of Fortitude
(1076, 14752), -- Divine Spirit
(1077, 27681), -- Prayer of Spirit
(1078, 1126), -- Mark of the Wild
(1079, 21849), -- Gift of the Wild
(1080, 23028), -- Arcane Brilliance
(1081, 61024), -- Dalaran Intellect
(1082, 61316), -- Dalaran Brilliance
(1083, -1082), (1083, -1081), (1083, -1080), (1083, -1072), (1083, -1068), -- Mage Intellect Buffs
(1084, -1075), (1084, -1074), (1084, -1069), (1084, 72590), -- Priest Stamina Buffs
(1085, -1077), (1085, -1076), (1085, -1070), -- Priest Spirit Buffs
(1086, -1071), (1086, 8072), -- Armor Buffs
(1087, -1071), (1087, -1070), (1087, -1069), (1087, -1068), (1087, -1067), (1087, -1066),-- Scrolls
(1088, -1065), (1088, -1064), -- Strength and Agility Buffs
(1091, 469), -- Commanding Shout
(1092, 6307), -- Blood Pact
(1093, -1092), (1093, -1091), -- HP Buffs
(1094, 34123), (1094, 63514), -- Healing Taken Buffs
(1095, 14893), (1095, 16177), -- Physical Taken Buffs
(1096, 1714), (1096, 5760), (1096, 31589), -- Cast Time Debuffs
(1097, 122), (1097, 33395), (1097, 55080), -- Frost Novas
(1098, 976), (1098, 27683), -- Shadow Protection
(1099, 348), (1099, 30108), -- Immolate and Unstable Affliction
(1100, 604), (1100, 1008), -- Dampen/Amplify Magic
(1101, 1490), (1101, 51726), (1101, 60431), -- Spell Damage Taken Debuffs
(1102, 40055), (1102, 40165), (1102, 40166), (1102, 40167), -- Introspection
(1103, 40623), (1103, 40625), (1103, 40626), -- Apexis Movement Speed
(1104, 12880), (1104, 57514), (1104, 57518), -- Warrior Enrages
(1105, -1005), (1105, 5677), -- MP5 Buffs
(1106, 6562), (1106, 28878), -- Heroic Presence
(1107, 12042), (1107, 12292), (1107, 31884), (1107, 34471), (1107, 49016), (1107, 57933), -- Temporary Damage Increases
(1108, 30069), (1108, 58684), -- Phys Damage Taken Debuffs
(1110, 74826), (1110, 74827), (1110, 74828), (1110, 74829), (1110, 74830), (1110, 74831), (1110, 74832), (1110, 74833), (1110, 74834), (1110, 74835), (1110, 74836), -- Corporeality
(1111, 62727), (1111, 63438), (1111, 63439), (1111, 63440), (1111, 63441), (1111, 63442), (1111, 63443), (1111, 63444), (1111, 63445), (1111, 63446), -- Champion's Pennant
(1112, 8219), (1112, 8220), (1112, 8221), (1112, 8222), -- Flip Out
-- 1116-20
(1121, 3671), (1121, 3672), (1121, 3673), -- Elemental Slave Buffs
(1122, 2825), (1122, 10060), (1122, 32182), -- Temporary Haste Buffs
(1123, 10060), (1123, 12042), -- Power Infusion and Arcane Power
(1124, -1085), (1124, -1073), -- Intellect Buffs
(1125, -1083), (1125, -1073), -- Spirit Buffs
-- values missing from trinitycore
(1, 33053), -- Crawdad Flask
(1001, 5020), (1001, 5021), (1001, 5257), (1001, 6114), (1001, 15852), (1001, 18191), (1001, 18192), (1001, 18193), (1001, 18194), (1001, 18222), (1001, 22730), (1001, 22789), (1001, 25661), (1001, 37058), (1001, 43730), -- More Foods
(1006, 26393), -- Elune's Blessing
(1062, 24423), -- Demoralizing Screech
(1019, 50274), -- Spore Cloud
(1022, 23060), -- Battle Squawk
-- (1058, 45176), -- Server Side Master Poisoner (is it needed?)
(1084, 23947), (1084, 23948), -- NPC Power Word Fortitude
(1096, 35387), -- Poison Spit
(1096, 58604), -- Lava Breath
(1089, -1079), (1089, -1078), (1089, 72588), (1089, 16878), (1089, 24752), (1089, 39233), -- Mark of the Wild
(1107, 48391), -- Owlkin Frenzy
(1090, 7481), (1090, 7483), (1090, 7484), -- Howling Rage
(1113, 467), -- Thorns
(1114, 70233), (1114, 70234), (1114, 70235), (1114, 70242), (1114, 70243), (1114, 70244), -- Perfumes/Colognes
(1115, 46302), -- K'iru's Song of Victory
(1126, -1115), (1126, -1084), -- Stamina Buffs
(1124, -1115); -- Intellect Buffs
DELETE FROM `spell_group_stack_rules`;
INSERT INTO `spell_group_stack_rules` (`group_id`,`stack_rule`, `description`) VALUES
(1, 1,'Battle Elixir'),
(2, 1, 'Guardian Elixir'),
(1001, 1, 'Well Fed'),
(1002, 4, 'Blessing of Might'),
(1003, 4, 'Battle Shout'),
(1004, 4, 'Flat AP Buffs'),
(1005, 4, 'Blessing of Wisdom'),
(1006, 1, 'All Stats Percentage'),
(1007, 1, 'Blessing of Sanctuary'),
(1008, 1, 'Blessing of Protection'),
(1009, 1, 'Blessing of Light'),
(1010, 2, 'Blessings'),
(1011, 2, 'Warrior Shouts'),
(1015, 3, 'Major Armor Debuffs'),
(1016, 4, 'Faerie Fire'),
(1019, 3, 'Minor Armor Debuffs'),
(1022, 3, 'Melee Haste Buffs'),
(1023, 4, 'Leader of the Pack'),
(1024, 4, 'Rampage'),
(1025, 3, 'Physical Crit Buffs'),
(1029, 1, 'Percentage AP Buffs'),
(1033, 1, 'Bleed Debuffs'),
(1036, 4, 'Spell Crit Buffs'),
(1037, 3, 'Spell Crit Debuffs'),
(1038, 3, 'All Stats Percentage with Sanctuary'),
(1046, 4, 'Totem of Wrath'),
(1048, 4, 'Spell Power Buffs'),
(1051, 3, 'Spell Hit Debuffs'),
(1054, 3, 'Haste Buffs'),
(1056, 3, 'Damage Done Buffs'),
(1058, 3, 'Poisons'),
(1059, 3, 'Attack Speed Debuffs'),
(1060, 3, 'Hit Chance Debuffs'),
(1061, 4, 'Healing Taken Debuffs'),
(1062, 4, 'AP Debuffs'),
(1083, 4, 'Single Intellect Buffs'),
(1084, 4, 'Single Stamina Buffs'),
(1085, 4, 'Single Spirit Buffs'),
(1086, 4, 'Armor Buffs'),
(1087, 4, 'Scrolls'),
(1088, 4, 'Strength and Agility Buffs'),
(1091, 0, 'Commanding Shout'),
(1092, 0, 'Blood Pact'),
(1093, 4, 'Flat HP Buffs'),
(1094, 3, 'Healing Taken Buffs'),
(1095, 4, 'Physical Taken Buffs'),
(1096, 4, 'Cast Time Debuffs'),
(1097, 1, 'Frost Novals'),
(1098, 4, 'Shadow Protection'),
(1099, 2, 'Immolate and Unstable Affliction'),
(1100, 1, 'Dampen/Amplify Magic'),
(1101, 3, 'Spell Damage Taken Debuffs'),
(1104, 1, 'Warrior Enrages'),
(1105, 3, 'MP5 Buffs'),
(1106, 1, 'Heroic Presence'),
(1107, 4, 'Temporary Damage Increases'),
(1108, 4, 'Phys Damage Taken Debuffs'),
(1110, 1, 'Corporeality'),
(1111, 1, 'Champion''s Pennants'),
(1112, 1, 'Flip Out'),
(1121, 1, 'Elemental Slave Buffs'),
(1122, 4, 'Temporary Haste Buffs'),
(1123, 1, 'Power Infusion and Arcane Power'),
(1124, 3, 'Intellect Buffs'),
(1125, 3, 'Spirit Buffs'),
-- additions
(1089, 4, 'Mark of the Wild'),
(1113, 4, 'Thorns'),
(1126, 3, 'Stamina Buffs');
DELETE FROM `spell_script_names` WHERE `spell_id` IN (18735, 56246, 56247);
INSERT INTO `spell_script_names` VALUES (18735, 'spell_warl_voidwalker_pet_passive');

View file

@ -47,15 +47,6 @@ AC_COMMON_API Optional<int32> MoneyStringToMoney(std::string_view moneyString);
std::string secsToTimeString(uint64 timeInSecs, bool shortText = false);
uint32 TimeStringToSecs(const std::string& timestring);
inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
{
if (val == -100.0f) // prevent set var to zero
{
val = -99.99f;
}
var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
}
// Percentage calculation
template <class T, class U>
inline T CalculatePct(T base, U pct)

View file

@ -38,6 +38,7 @@
#include "PoolMgr.h"
#include "ScriptMgr.h"
#include "ScriptedGossip.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
@ -601,13 +602,13 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(GetLevel(), cInfo->unit_class);
float armor = stats->GenerateArmor(cInfo);
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE]));
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST]));
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW]));
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE]));
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, armor);
SetStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
SetStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
SetStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE]));
SetStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST]));
SetStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW]));
SetStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE]));
SetCanModifyStats(true);
UpdateAllStats();
@ -1017,10 +1018,7 @@ void Creature::Regenerate(Powers power)
}
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if (Powers((*i)->GetMiscValue()) == power)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (power == POWER_FOCUS ? PET_FOCUS_REGEN_INTERVAL.count() : CREATURE_REGEN_INTERVAL) / (5 * IN_MILLISECONDS);
@ -1056,9 +1054,7 @@ void Creature::RegenerateHealth()
}
// Apply modifiers (if any).
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
@ -1558,8 +1554,8 @@ void Creature::SelectLevel(bool changelevel)
/// @todo: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
// damage
@ -1577,8 +1573,8 @@ void Creature::SelectLevel(bool changelevel)
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, weaponBaseMinDamage);
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
sScriptMgr->OnCreatureSelectLevel(cInfo, this);
}

View file

@ -815,13 +815,6 @@ void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
SetFloatValue(index, cur);
}
void Object::ApplyPercentModFloatValue(uint16 index, float val, bool apply)
{
float value = GetFloatValue(index);
ApplyPercentModFloatVar(value, val, apply);
SetFloatValue(index, value);
}
void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
{
float cur = GetFloatValue(index);

View file

@ -165,7 +165,6 @@ public:
void ApplyModUInt64Value(uint16 index, int32 val, bool apply);
void ApplyModPositiveFloatValue(uint16 index, float val, bool apply);
void ApplyModSignedFloatValue(uint16 index, float val, bool apply);
void ApplyPercentModFloatValue(uint16 index, float val, bool apply);
void SetFlag(uint16 index, uint32 newFlag);
void RemoveFlag(uint16 index, uint32 oldFlag);

View file

@ -1075,7 +1075,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
}
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
uint32 attackTime = BASE_ATTACK_TIME;
if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET) && cinfo->BaseAttackTime >= 1000)
@ -1094,7 +1094,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
// xinef: hunter pets should not inherit template resistances
if (!IsHunterPet())
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
SetStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
//health, mana, armor and resistance
PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel);
@ -1111,15 +1111,15 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
SetCreateHealth(pInfo->health*factorHealth);
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
if (petType != HUNTER_PET) //hunter pet use focus
{
SetCreateMana(pInfo->mana);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)pInfo->mana);
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)pInfo->mana);
}
if (pInfo->armor > 0)
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
@ -1138,9 +1138,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
SetCreateHealth(std::max<uint32>(1, stats->BaseHealth[cinfo->expansion]*factorHealth));
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
SetCreateMana(stats->BaseMana * factorMana);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
// xinef: added some multipliers so debuffs can affect pets in any way...
SetCreateStat(STAT_STRENGTH, 22);
@ -1174,24 +1174,6 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
switch (GetEntry())
{
case NPC_FELGUARD:
{
// xinef: Glyph of Felguard, so ugly im crying... no appropriate spell
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_FELGUARD))
{
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
}
break;
}
case NPC_VOIDWALKER:
{
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_VOIDWALKER))
{
HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
}
break;
}
case NPC_WATER_ELEMENTAL_PERM:
{
AddAura(SPELL_PET_AVOIDANCE, this);

View file

@ -21,6 +21,7 @@
#include "Pet.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
// KillRewarder incapsulates logic of rewarding player upon kill with:
@ -162,9 +163,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
if (xp)
{
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
Unit::AuraEffectList const& auras = player->GetAuraEffectsByType(SPELL_AURA_MOD_XP_PCT);
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
AddPct(xp, (*i)->GetAmount());
xp *= player->GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_PCT);
// 4.2.3. Give XP to player.
sScriptMgr->OnPlayerGiveXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);

View file

@ -69,8 +69,10 @@
#include "Realm.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
#include "SharedDefines.h"
#include "SocialMgr.h"
#include "Spell.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
@ -312,8 +314,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this)
for (uint8 i = 0; i < BASEMOD_END; ++i)
{
m_auraBaseMod[i][FLAT_MOD] = 0.0f;
m_auraBaseMod[i][PCT_MOD] = 1.0f;
m_auraBaseFlatMod[i] = 0.0f;
m_auraBasePctMod[i] = 1.0f;
}
for (uint8 i = 0; i < MAX_COMBAT_RATING; i++)
@ -831,9 +833,7 @@ int32 Player::getMaxTimer(MirrorTimerType timer)
if (!IsAlive() || HasWaterBreathingAura() || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING)))
return DISABLED_MIRROR_TIMER;
int32 UnderWaterTime = sWorld->getIntConfig(CONFIG_WATER_BREATH_TIMER);
AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING);
for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
AddPct(UnderWaterTime, (*i)->GetAmount());
UnderWaterTime *= GetTotalAuraMultiplier(SPELL_AURA_MOD_WATER_BREATHING);
return UnderWaterTime;
}
case FIRE_TIMER:
@ -1922,10 +1922,7 @@ void Player::Regenerate(Powers power)
// Mana regen calculated in Player::UpdateManaRegen(), energy regen calculated in Player::UpdateEnergyRegen()
if (power != POWER_MANA && power != POWER_ENERGY)
{
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if (Powers((*i)->GetMiscValue()) == power)
AddPct(addvalue, (*i)->GetAmount());
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
// Butchery requires combat for this effect
if (power != POWER_RUNIC_POWER || IsInCombat())
@ -2008,11 +2005,7 @@ void Player::RegenerateHealth()
addvalue *= 1.33f;
}
AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
{
AddPct(addvalue, (*i)->GetAmount());
}
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
if (!IsInCombat())
{
@ -2666,14 +2659,14 @@ void Player::InitStatsForLevel(bool reapplyMods)
// set armor (resistance 0) to original value (create_agility*2)
SetArmor(int32(m_createStats[STAT_AGILITY] * 2));
SetResistanceBuffMods(SpellSchools(0), true, 0.0f);
SetResistanceBuffMods(SpellSchools(0), false, 0.0f);
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
// set other resistance to original value (0)
for (uint8 i = 1; i < MAX_SPELL_SCHOOL; ++i)
{
SetResistance(SpellSchools(i), 0);
SetResistanceBuffMods(SpellSchools(i), true, 0.0f);
SetResistanceBuffMods(SpellSchools(i), false, 0.0f);
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + i, 0.0f);
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + i, 0.0f);
}
SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, 0);
@ -5012,24 +5005,107 @@ void Player::ClearChannelWatch()
(*itr)->RemoveWatching(this);
}
void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply)
void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
{
if (modGroup >= BASEMOD_END)
{
LOG_ERROR("entities.player", "ERROR in HandleBaseModValue(): non existed BaseModGroup!");
LOG_ERROR("entities.player", "Player::HandleBaseModFlatValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
modGroup, FLAT_MOD, GetName(), GetGUID().ToString());
return;
}
switch (modType)
m_auraBaseFlatMod[modGroup] += apply ? amount : -amount;
UpdateBaseModGroup(modGroup);
}
void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct)
{
if (modGroup >= BASEMOD_END)
{
case FLAT_MOD:
m_auraBaseMod[modGroup][modType] += apply ? amount : -amount;
LOG_ERROR("entities.player", "Player::ApplyBaseModPctValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
modGroup, PCT_MOD, GetName(), GetGUID().ToString());
return;
}
m_auraBasePctMod[modGroup] += CalculatePct(1.0f, pct);
UpdateBaseModGroup(modGroup);
}
void Player::SetBaseModFlatValue(BaseModGroup modGroup, float val)
{
if (m_auraBaseFlatMod[modGroup] == val)
return;
m_auraBaseFlatMod[modGroup] = val;
UpdateBaseModGroup(modGroup);
}
void Player::SetBaseModPctValue(BaseModGroup modGroup, float val)
{
if (m_auraBasePctMod[modGroup] == val)
return;
m_auraBasePctMod[modGroup] = val;
UpdateBaseModGroup(modGroup);
}
void Player::UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot /*= -1*/)
{
Unit::UpdateDamageDoneMods(attackType, skipEnchantSlot);
UnitMods unitMod;
switch (attackType)
{
case BASE_ATTACK:
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
break;
case PCT_MOD:
ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply);
case OFF_ATTACK:
unitMod = UNIT_MOD_DAMAGE_OFFHAND;
break;
case RANGED_ATTACK:
unitMod = UNIT_MOD_DAMAGE_RANGED;
break;
default:
ABORT();
break;
}
float amount = 0.0f;
Item* item = GetWeaponForAttack(attackType, true);
if (!item)
return;
for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot)
{
if (skipEnchantSlot == slot)
continue;
SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot)));
if (!enchantmentEntry)
continue;
for (uint8 i = 0; i < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++i)
{
switch (enchantmentEntry->type[i])
{
case ITEM_ENCHANTMENT_TYPE_DAMAGE:
amount += enchantmentEntry->amount[i];
break;
case ITEM_ENCHANTMENT_TYPE_TOTEM:
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
amount += enchantmentEntry->amount[i] * item->GetTemplate()->Delay / 1000.0f;
break;
default:
break;
}
}
}
HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true);
}
void Player::UpdateBaseModGroup(BaseModGroup modGroup)
{
if (!CanModifyStats())
return;
@ -5060,10 +5136,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
return 0.0f;
}
if (modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
return 0.0f;
return m_auraBaseMod[modGroup][modType];
return (modType == FLAT_MOD ? m_auraBaseFlatMod[modGroup] : m_auraBasePctMod[modGroup]);
}
float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
@ -5074,15 +5147,15 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
return 0.0f;
}
if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
if (m_auraBasePctMod[modGroup] <= 0.0f)
return 0.0f;
return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD];
return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup];
}
uint32 Player::GetShieldBlockValue() const
{
float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD];
float value = (m_auraBaseFlatMod[SHIELD_BLOCK_VALUE] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBasePctMod[SHIELD_BLOCK_VALUE];
value = (value < 0) ? 0 : value;
@ -5151,7 +5224,7 @@ void Player::GetDodgeFromAgility(float& diminishing, float& nondiminishing)
return;
/// @todo: research if talents/effects that increase total agility by x% should increase non-diminishing part
float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + static_cast<uint16>(STAT_AGILITY)][BASE_PCT];
float base_agility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + AsUnderlyingType(STAT_AGILITY)), BASE_PCT);
float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
// calculate diminishing (green in char screen) and non-diminishing (white) contribution
@ -6574,20 +6647,22 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
LOG_DEBUG("entities.player", "applying mods for item {} ", item->GetGUID().ToString());
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
if (item->HasSocket()) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
CorrectMetaGemEnchants(slot, apply);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(item, attacktype, apply);
_ApplyItemBonuses(proto, slot, apply);
if (slot == EQUIPMENT_SLOT_RANGED)
_ApplyAmmoBonuses();
ApplyItemEquipSpell(item, apply);
ApplyItemDependentAuras(item, apply);
WeaponAttackType const attackType = Player::GetAttackBySlot(slot);
if (attackType != MAX_ATTACK)
UpdateWeaponDependentAuras(attackType);
ApplyEnchantment(item, apply);
LOG_DEBUG("entities.player.items", "_ApplyItemMods complete.");
@ -6658,30 +6733,30 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
switch (statType)
{
case ITEM_MOD_MANA:
HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
break;
case ITEM_MOD_HEALTH: // modify HP
HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
break;
case ITEM_MOD_AGILITY: // modify agility
HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
ApplyStatBuffMod(STAT_AGILITY, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_AGILITY);
break;
case ITEM_MOD_STRENGTH: //modify strength
HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
ApplyStatBuffMod(STAT_STRENGTH, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_STRENGTH);
break;
case ITEM_MOD_INTELLECT: //modify intellect
HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
ApplyStatBuffMod(STAT_INTELLECT, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_INTELLECT);
break;
case ITEM_MOD_SPIRIT: //modify spirit
HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
ApplyStatBuffMod(STAT_SPIRIT, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_SPIRIT);
break;
case ITEM_MOD_STAMINA: //modify stamina
HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
ApplyStatBuffMod(STAT_STAMINA, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_STAMINA);
break;
case ITEM_MOD_DEFENSE_SKILL_RATING:
ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply);
@ -6770,11 +6845,11 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
ApplyRatingMod(CR_EXPERTISE, int32(val), apply);
break;
case ITEM_MOD_ATTACK_POWER:
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
break;
case ITEM_MOD_RANGED_ATTACK_POWER:
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
break;
// case ITEM_MOD_FERAL_ATTACK_POWER:
// ApplyFeralAPBonus(int32(val), apply);
@ -6795,7 +6870,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
ApplySpellPenetrationBonus(val, apply);
break;
case ITEM_MOD_BLOCK_VALUE:
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(val), apply);
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(val), apply);
break;
/// @deprecated item mods
case ITEM_MOD_SPELL_HEALING_DONE:
@ -6825,7 +6900,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
if (armor)
{
UnitModifierType modType = TOTAL_VALUE;
UnitModifierFlatType modType = TOTAL_VALUE;
if (proto->Class == ITEM_CLASS_ARMOR)
{
switch (proto->SubClass)
@ -6839,33 +6914,33 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
break;
}
}
HandleStatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply);
HandleStatFlatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply);
}
// Add armor bonus from ArmorDamageModifier if > 0
if (proto->ArmorDamageModifier > 0 && sScriptMgr->OnPlayerCanArmorDamageModifier(this))
HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
if (proto->Block)
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(proto->Block), apply);
if (proto->HolyRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
if (proto->FireRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
if (proto->NatureRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
if (proto->FrostRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
if (proto->ShadowRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
if (proto->ArcaneRes)
HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
WeaponAttackType attType = Player::GetAttackBySlot(slot);
if (attType != MAX_ATTACK)
@ -7036,6 +7111,84 @@ void Player::UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot)
ApplyItemObtainSpells(item, true);
}
// this one rechecks weapon auras and stores them in BaseModGroup container
// needed for things like axe specialization applying only to axe weapons in case of dual-wield
void Player::UpdateWeaponDependentCritAuras(WeaponAttackType attackType)
{
BaseModGroup modGroup;
switch (attackType)
{
case BASE_ATTACK:
modGroup = CRIT_PERCENTAGE;
break;
case OFF_ATTACK:
modGroup = OFFHAND_CRIT_PERCENTAGE;
break;
case RANGED_ATTACK:
modGroup = RANGED_CRIT_PERCENTAGE;
break;
default:
ABORT();
break;
}
float amount = 0.0f;
amount += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
// these auras don't have item requirement (only Combat Expertise in 3.3.5a)
amount += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
SetBaseModFlatValue(modGroup, amount);
}
void Player::UpdateAllWeaponDependentCritAuras()
{
for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
UpdateWeaponDependentCritAuras(WeaponAttackType(i));
}
void Player::UpdateWeaponDependentAuras(WeaponAttackType attackType)
{
UpdateWeaponDependentCritAuras(attackType);
UpdateDamageDoneMods(attackType);
UpdateDamagePctDoneMods(attackType);
}
void Player::ApplyItemDependentAuras(Item* item, bool apply)
{
if (apply)
{
PlayerSpellMap const& spells = GetSpellMap();
for (auto itr = spells.begin(); itr != spells.end(); ++itr)
{
if (itr->second->State == PLAYERSPELL_REMOVED)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
continue;
if (!HasAura(itr->first) && HasItemFitToSpellRequirements(spellInfo))
AddAura(itr->first, this); // no SMSG_SPELL_GO in sniff found
}
}
else
RemoveItemDependentAurasAndCasts(item);
}
bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const
{
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
if (spellInfo->EquippedItemClass == -1)
return true;
Item* item = GetWeaponForAttack(attackType, true);
if (!item || !item->IsFitToSpellRequirements(spellInfo))
return false;
return true;
}
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
{
if (Item const* weapon = GetWeaponForAttack(attackType, true))
@ -7046,110 +7199,6 @@ SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*=
return SPELL_SCHOOL_MASK_NORMAL;
}
void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
{
AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr)
_ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply);
AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr)
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr)
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
}
void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
{
// don't apply mod if item is broken or cannot be used
if (item->IsBroken() || !CanUseAttackType(attackType))
return;
// generic not weapon specific case processes in aura code
if (aura->GetSpellInfo()->EquippedItemClass == -1)
return;
if (!sScriptMgr->OnPlayerCanApplyWeaponDependentAuraDamageMod(this, item, attackType, aura, apply))
return;
BaseModGroup mod = BASEMOD_END;
switch (attackType)
{
case BASE_ATTACK:
mod = CRIT_PERCENTAGE;
break;
case OFF_ATTACK:
mod = OFFHAND_CRIT_PERCENTAGE;
break;
case RANGED_ATTACK:
mod = RANGED_CRIT_PERCENTAGE;
break;
default:
return;
}
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
}
void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
{
// don't apply mod if item is broken or cannot be used
if (item->IsBroken() || !CanUseAttackType(attackType))
return;
// ignore spell mods for not wands
if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0)
return;
// generic not weapon specific case processes in aura code
if (aura->GetSpellInfo()->EquippedItemClass == -1)
return;
UnitMods unitMod = UNIT_MOD_END;
switch (attackType)
{
case BASE_ATTACK:
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
break;
case OFF_ATTACK:
unitMod = UNIT_MOD_DAMAGE_OFFHAND;
break;
case RANGED_ATTACK:
unitMod = UNIT_MOD_DAMAGE_RANGED;
break;
default:
return;
}
UnitModifierType unitModType = TOTAL_VALUE;
switch (aura->GetAuraType())
{
case SPELL_AURA_MOD_DAMAGE_DONE:
unitModType = TOTAL_VALUE;
break;
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
unitModType = TOTAL_PCT;
break;
default:
return;
}
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
{
HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply);
if (unitModType == TOTAL_VALUE)
{
if (aura->GetAmount() > 0)
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply);
else
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply);
}
}
}
void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
{
if (!item)
@ -7464,12 +7513,6 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
continue;
}
if (!spellInfo->CheckElixirStacking(this))
{
Spell::SendCastResult(this, spellInfo, cast_count, SPELL_FAILED_AURA_BOUNCED);
continue;
}
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
spell->m_CastItem = item;
spell->m_cast_count = cast_count; // set count of casts
@ -7578,10 +7621,7 @@ void Player::_RemoveAllItemMods()
if (!proto)
continue;
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, false);
ApplyItemDependentAuras(m_items[i], false);
_ApplyItemBonuses(proto, i, false);
if (i == EQUIPMENT_SLOT_RANGED)
@ -7607,12 +7647,13 @@ void Player::_ApplyAllItemMods()
if (!proto)
continue;
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
if (attacktype < MAX_ATTACK)
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, true);
ApplyItemDependentAuras(m_items[i], false);
_ApplyItemBonuses(proto, i, true);
WeaponAttackType const attackType = Player::GetAttackBySlot(i);
if (attackType != MAX_ATTACK)
UpdateWeaponDependentAuras(attackType);
if (i == EQUIPMENT_SLOT_RANGED)
_ApplyAmmoBonuses();
}
@ -12583,9 +12624,9 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem)
{
Aura* aura = itr->second;
// skip passive (passive item dependent spells work in another way) and not self applied auras
// skip not self applied auras
SpellInfo const* spellInfo = aura->GetSpellInfo();
if (aura->IsPassive() || aura->GetCasterGUID() != GetGUID())
if (aura->GetCasterGUID() != GetGUID())
{
++itr;
continue;

View file

@ -1334,7 +1334,7 @@ public:
{
return StoreItem(dest, pItem, update);
}
void RemoveItem(uint8 bag, uint8 slot, bool update, bool swap = false);
void RemoveItem(uint8 bag, uint8 slot, bool update);
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update);
// in trade, auction, guild bank, mail....
void MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB = false);
@ -2187,11 +2187,19 @@ public:
[[nodiscard]] bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); }
void SetRegularAttackTime();
void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; }
void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply);
void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply);
void ApplyBaseModPctValue(BaseModGroup modGroup, float pct);
void SetBaseModFlatValue(BaseModGroup modGroup, float val);
void SetBaseModPctValue(BaseModGroup modGroup, float val);
void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot = -1) override;
void UpdateBaseModGroup(BaseModGroup modGroup);
[[nodiscard]] float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const;
[[nodiscard]] float GetTotalBaseModValue(BaseModGroup modGroup) const;
[[nodiscard]] float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; }
void _ApplyAllStatBonuses();
void _RemoveAllStatBonuses();
@ -2203,9 +2211,13 @@ public:
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
void UpdateWeaponDependentAuras(WeaponAttackType attackType);
void ApplyItemDependentAuras(Item* item, bool apply);
bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const override;
void UpdateWeaponDependentCritAuras(WeaponAttackType attackType);
void UpdateAllWeaponDependentCritAuras();
void _ApplyItemMods(Item* item, uint8 slot, bool apply);
void _RemoveAllItemMods();
@ -2829,7 +2841,8 @@ protected:
ActionButtonList m_actionButtons;
float m_auraBaseMod[BASEMOD_END][MOD_END];
float m_auraBaseFlatMod[BASEMOD_END];
float m_auraBasePctMod[BASEMOD_END];
int32 m_baseRatingValue[MAX_COMBAT_RATING];
uint32 m_baseSpellPower;
uint32 m_baseSpellDamage;

View file

@ -1405,9 +1405,7 @@ uint32 Player::CalculateQuestRewardXP(Quest const* quest)
uint32 xp = uint32(quest->XPValue(GetLevel()) * GetQuestRate(quest->IsDFQuest()));
// handle SPELL_AURA_MOD_XP_QUEST_PCT auras
Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT);
for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
AddPct(xp, (*i)->GetAmount());
xp *= GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_QUEST_PCT);
return xp;
}

View file

@ -60,6 +60,7 @@
#include "StringConvert.h"
#include "Tokenize.h"
#include "Transport.h"
#include "Unit.h"
#include "UpdateFieldFlags.h"
#include "Util.h"
#include "World.h"
@ -2896,7 +2897,7 @@ void Player::VisualizeItem(uint8 slot, Item* pItem)
pItem->SetState(ITEM_CHANGED, this);
}
void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
{
// note: removeitem does not actually change the item
// it only takes the item out of storage temporarily
@ -2931,12 +2932,6 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
// remove item dependent auras and casts (only weapon and armor slots)
if (slot < INVENTORY_SLOT_BAG_END && slot < EQUIPMENT_SLOT_END)
{
// Xinef: Ensure that this function is called for places with swap=true
if (!swap)
{
RemoveItemDependentAurasAndCasts(pItem);
}
// remove held enchantments, update expertise
if (slot == EQUIPMENT_SLOT_MAINHAND)
{
@ -3071,9 +3066,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
if (slot < EQUIPMENT_SLOT_END)
{
// remove item dependent auras and casts (only weapon and armor slots)
RemoveItemDependentAurasAndCasts(pItem);
// update expertise and armor penetration - passive auras may need it
switch (slot)
{
@ -3865,8 +3857,8 @@ void Player::SwapItem(uint16 src, uint16 dst)
}
// now do moves, remove...
RemoveItem(dstbag, dstslot, false, true);
RemoveItem(srcbag, srcslot, false, true);
RemoveItem(dstbag, dstslot, false);
RemoveItem(srcbag, srcslot, false);
// add to dest
if (IsInventoryPos(dst))
@ -4355,13 +4347,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
// processed in Player::CastItemCombatSpell
break;
case ITEM_ENCHANTMENT_TYPE_DAMAGE:
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply);
else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply);
else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED)
HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
{
WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot());
if (attackType != MAX_ATTACK)
UpdateDamageDoneMods(attackType, apply ? -1 : slot);
break;
}
case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL:
if (enchant_spell_id)
{
@ -4412,7 +4403,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
}
}
HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
break;
case ITEM_ENCHANTMENT_TYPE_STAT:
{
@ -4439,36 +4430,36 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
{
case ITEM_MOD_MANA:
LOG_DEBUG("entities.player.items", "+ {} MANA", enchant_amount);
HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
break;
case ITEM_MOD_HEALTH:
LOG_DEBUG("entities.player.items", "+ {} HEALTH", enchant_amount);
HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
break;
case ITEM_MOD_AGILITY:
LOG_DEBUG("entities.player.items", "+ {} AGILITY", enchant_amount);
HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
ApplyStatBuffMod(STAT_AGILITY, (float)enchant_amount, apply);
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
UpdateStatBuffMod(STAT_AGILITY);
break;
case ITEM_MOD_STRENGTH:
LOG_DEBUG("entities.player.items", "+ {} STRENGTH", enchant_amount);
HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
ApplyStatBuffMod(STAT_STRENGTH, (float)enchant_amount, apply);
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
UpdateStatBuffMod(STAT_STRENGTH);
break;
case ITEM_MOD_INTELLECT:
LOG_DEBUG("entities.player.items", "+ {} INTELLECT", enchant_amount);
HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
ApplyStatBuffMod(STAT_INTELLECT, (float)enchant_amount, apply);
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
UpdateStatBuffMod(STAT_INTELLECT);
break;
case ITEM_MOD_SPIRIT:
LOG_DEBUG("entities.player.items", "+ {} SPIRIT", enchant_amount);
HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
ApplyStatBuffMod(STAT_SPIRIT, (float)enchant_amount, apply);
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
UpdateStatBuffMod(STAT_SPIRIT);
break;
case ITEM_MOD_STAMINA:
LOG_DEBUG("entities.player.items", "+ {} STAMINA", enchant_amount);
HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
ApplyStatBuffMod(STAT_STAMINA, (float)enchant_amount, apply);
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
UpdateStatBuffMod(STAT_STAMINA);
break;
case ITEM_MOD_DEFENSE_SKILL_RATING:
ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
@ -4579,12 +4570,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
LOG_DEBUG("entities.player.items", "+ {} EXPERTISE", enchant_amount);
break;
case ITEM_MOD_ATTACK_POWER:
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply);
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
LOG_DEBUG("entities.player.items", "+ {} ATTACK_POWER", enchant_amount);
break;
case ITEM_MOD_RANGED_ATTACK_POWER:
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
LOG_DEBUG("entities.player.items", "+ {} RANGED_ATTACK_POWER", enchant_amount);
break;
// case ITEM_MOD_FERAL_ATTACK_POWER:
@ -4612,7 +4603,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
LOG_DEBUG("entities.player.items", "+ {} SPELL_PENETRATION", enchant_amount);
break;
case ITEM_MOD_BLOCK_VALUE:
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply);
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(enchant_amount), apply);
LOG_DEBUG("entities.player.items", "+ {} BLOCK_VALUE", enchant_amount);
break;
/// @deprecated item mods
@ -4631,20 +4622,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
}
case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
{
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
{
float addValue = 0.0f;
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
{
addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f);
HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply);
}
else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
{
addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f);
HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply);
}
}
WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot());
if (attackType != MAX_ATTACK)
UpdateDamageDoneMods(attackType);
break;
}
case ITEM_ENCHANTMENT_TYPE_USE_SPELL:

View file

@ -701,7 +701,7 @@ void Player::UpdateRating(CombatRating cr)
void Player::UpdateAllRatings()
{
for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
for (uint cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}

View file

@ -204,7 +204,7 @@ void Player::UpdateSpellDamageAndHealingBonus()
bool Player::UpdateAllStats()
{
for (int8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
float value = GetTotalStatValue(Stats(i));
SetStat(Stats(i), int32(value));
@ -247,9 +247,9 @@ void Player::UpdateResistances(uint32 school)
float value = 0.0f;
UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
value = GetModifierValue(unitMod, BASE_VALUE);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value = GetFlatModifierValue(unitMod, BASE_VALUE);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
for(AuraEffectList::const_iterator i = mResbyIntellect.begin(); i != mResbyIntellect.end(); ++i)
@ -258,7 +258,7 @@ void Player::UpdateResistances(uint32 school)
value += int32(GetStat(Stats((*i)->GetMiscValueB())) * (*i)->GetAmount() / 100.0f);
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetResistance(SpellSchools(school), int32(value));
}
@ -270,10 +270,10 @@ void Player::UpdateArmor()
{
UnitMods unitMod = UNIT_MOD_ARMOR;
float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
value += GetModifierValue(unitMod, TOTAL_VALUE);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
@ -283,7 +283,7 @@ void Player::UpdateArmor()
value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount());
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetArmor(int32(value));
@ -314,10 +314,10 @@ void Player::UpdateMaxHealth()
{
UnitMods unitMod = UNIT_MOD_HEALTH;
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
sScriptMgr->OnPlayerAfterUpdateMaxHealth(this, value);
SetMaxHealth((uint32)value);
@ -329,10 +329,10 @@ void Player::UpdateMaxPower(Powers power)
float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0;
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
sScriptMgr->OnPlayerAfterUpdateMaxPower(this, power, value);
SetMaxPower(power, uint32(value));
@ -487,10 +487,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
}
}
SetModifierValue(unitMod, BASE_VALUE, val2);
SetStatFlatModifier(unitMod, BASE_VALUE, val2);
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
if (ranged)
@ -514,7 +514,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
attPowerMod += int32(GetArmor() / (*iter)->GetAmount());
}
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
sScriptMgr->OnPlayerAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
@ -576,10 +576,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
float attackSpeedMod = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
float basePct = GetModifierValue(unitMod, BASE_PCT);
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
float basePct = GetPctModifierValue(unitMod, BASE_PCT);
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
@ -681,7 +681,8 @@ void Player::UpdateCritPercentage(WeaponAttackType attType)
break;
}
float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
// flat = bonus from crit auras, pct = bonus from agility, combat rating = mods from items
float value = GetBaseModValue(modGroup, FLAT_MOD) + GetBaseModValue(modGroup, PCT_MOD) + GetRatingBonusValue(cr);
// Modify crit from weapon skill and maximized defense skill of same level victim difference
value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
@ -698,9 +699,9 @@ void Player::UpdateAllCritPercentages()
{
float value = GetMeleeCritFromAgility();
SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModPctValue(CRIT_PERCENTAGE, value);
SetBaseModPctValue(OFFHAND_CRIT_PERCENTAGE, value);
SetBaseModPctValue(RANGED_CRIT_PERCENTAGE, value);
UpdateCritPercentage(BASE_ATTACK);
UpdateCritPercentage(OFF_ATTACK);
@ -849,7 +850,7 @@ void Player::UpdateSpellCritChance(uint32 school)
// Crit from Intellect
crit += GetSpellCritFromIntellect();
// Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
crit += GetTotalAuraModifierAreaExclusive(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
// Increase crit from SPELL_AURA_MOD_CRIT_PCT
crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
// Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@ -900,16 +901,11 @@ void Player::UpdateExpertise(WeaponAttackType attack)
Item* weapon = GetWeaponForAttack(attack, true);
AuraEffectList const& expAuras = GetAuraEffectsByType(SPELL_AURA_MOD_EXPERTISE);
for (AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
expertise += GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE, [weapon](AuraEffect const* aurEff)
{
// item neutral spell
if ((*itr)->GetSpellInfo()->EquippedItemClass == -1)
expertise += (*itr)->GetAmount();
// item dependent spell
else if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
expertise += (*itr)->GetAmount();
}
return aurEff->GetSpellInfo()->EquippedItemClass == -1 || // item neutral spell
(weapon && weapon->IsFitToSpellRequirements(aurEff->GetSpellInfo())); // item dependent spell
});
if (expertise < 0)
expertise = 0;
@ -1100,9 +1096,9 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
}
float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attackPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER
SetInt32Value(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS
@ -1166,10 +1162,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
float attackPower = GetTotalAttackPowerValue(attType);
float attackSpeedMulti = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance;
float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance;
float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float dmgMultiplier = GetCreatureTemplate()->DamageModifier; // = DamageModifier * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
@ -1233,11 +1229,11 @@ bool Guardian::UpdateAllStats()
void Guardian::UpdateArmor()
{
float value = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
float value = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
value += std::max<float>(GetStat(STAT_AGILITY) - GetCreateStat(STAT_AGILITY), 0.0f) * 2.0f;
value += GetModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
value += GetFlatModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
SetArmor(int32(value));
}
@ -1278,10 +1274,10 @@ void Guardian::UpdateMaxHealth()
break;
}
float value = GetModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
@ -1311,11 +1307,11 @@ void Guardian::UpdateMaxPower(Powers power)
break;
}
// xinef: Do NOT add base mana TWICE
float value = GetModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
// Do NOT add base mana TWICE
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, uint32(value));
}
@ -1335,12 +1331,12 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
else
val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
SetModifierValue(unitMod, BASE_VALUE, val);
SetStatFlatModifier(unitMod, BASE_VALUE, val);
//in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
//UNIT_FIELD_(RANGED)_ATTACK_POWER field
SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
@ -1362,10 +1358,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
float att_speed = float(GetAttackTime(BASE_ATTACK)) / 1000.0f;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed;
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed;
float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT);
float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);

File diff suppressed because it is too large Load diff

View file

@ -123,13 +123,18 @@ enum HitInfo
HITINFO_FAKE_DAMAGE = 0x01000000 // enables damage animation even if no damage done, set only if no damage
};
enum UnitModifierType
enum UnitModifierFlatType
{
BASE_VALUE = 0,
BASE_PCT = 1,
TOTAL_VALUE = 2,
TOTAL_PCT = 3,
MODIFIER_TYPE_END = 4
TOTAL_VALUE = 1,
MODIFIER_TYPE_FLAT_END = 3
};
enum UnitModifierPctType
{
BASE_PCT = 0,
TOTAL_PCT = 1,
MODIFIER_TYPE_PCT_END = 2
};
enum WeaponDamageRange
@ -1050,16 +1055,32 @@ public:
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + i, 0);
}
bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply);
void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; }
[[nodiscard]] float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const;
bool HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply);
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount);
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val);
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val);
[[nodiscard]] float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const;
[[nodiscard]] float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const;
void UpdateUnitMod(UnitMods unitMod);
// only players have item requirements
[[nodiscard]] virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType /*attackType*/, AuraEffect const* /*aurEff*/) const { return true; }
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot = -1);
void UpdateAllDamageDoneMods();
void UpdateDamagePctDoneMods(WeaponAttackType attackType);
void UpdateAllDamagePctDoneMods();
[[nodiscard]] float GetTotalStatValue(Stats stat, float additionalValue = 0.0f) const;
void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; }
[[nodiscard]] bool CanModifyStats() const { return m_canModifyStats; }
void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? static_cast<uint16>(UNIT_FIELD_POSSTAT0) + stat : static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + stat), val, apply); }
void ApplyStatPercentBuffMod(Stats stat, float val, bool apply);
void UpdateStatBuffMod(Stats stat);
// Unit level methods
[[nodiscard]] uint8 GetLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); }
@ -1104,7 +1125,6 @@ public:
void SetMaxPower(Powers power, uint32 val);
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker);
@ -1159,13 +1179,9 @@ public:
[[nodiscard]] uint32 GetResistance(SpellSchoolMask mask) const;
[[nodiscard]] uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school); }
static float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim);
[[nodiscard]] float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school); }
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school, val); }
void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val); }
void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
void UpdateResistanceBuffModsMod(SpellSchools school);
//////////// Need triage ////////////////
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : GetLevel()) * 5; }
@ -1319,6 +1335,10 @@ public:
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const;
bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false);
bool IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications = false);
// aura apply/remove helpers - you should better not use these
Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool periodicReset = false);
void _AddAura(UnitAura* aura, Unit* caster);
@ -1328,7 +1348,7 @@ public:
void _UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode);
void _UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode);
void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura);
void _RemoveNoStackAurasDueToAura(Aura* aura);
void _RemoveNoStackAurasDueToAura(Aura* aura, bool owned);
bool _IsNoStackAuraDueToAura(Aura* appliedAura, Aura* existingAura) const;
void _RegisterAuraEffect(AuraEffect* aurEff, bool apply);
@ -1474,15 +1494,19 @@ public:
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, uint8 mode = 0);
[[nodiscard]] uint32 GetDoTsByCaster(ObjectGuid casterGUID) const;
[[nodiscard]] int32 GetTotalAuraModifierAreaExclusive(AuraType auratype) const;
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype) const;
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auratype) const;
int32 GetMaxPositiveAuraModifier(AuraType auratype);
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auratype) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auratype) const;
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
[[nodiscard]] int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
[[nodiscard]] float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const;
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
[[nodiscard]] int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
[[nodiscard]] int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
[[nodiscard]] int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const;
@ -1581,7 +1605,6 @@ public:
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask);
int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask);
float SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype);
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
@ -2132,7 +2155,8 @@ protected:
AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove
uint32 m_interruptMask;
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END];
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END];
float m_weaponDamage[MAX_ATTACK][MAX_WEAPON_DAMAGE_RANGE][MAX_ITEM_PROTO_DAMAGES];
bool m_canModifyStats;
VisibleAuraMap m_visibleAuras;

View file

@ -256,8 +256,8 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem&
}
// now do moves, remove...
_player->RemoveItem(dstbag, dstslot, true, true);
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true, true);
_player->RemoveItem(dstbag, dstslot, true);
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true);
// add to dest
_player->EquipItem(dest, pSrcItem, true);

View file

@ -24,16 +24,6 @@ void ScriptMgr::OnCalcMaxDuration(Aura const* aura, int32& maxDuration)
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CALC_MAX_DURATION, script->OnCalcMaxDuration(aura, maxDuration));
}
bool ScriptMgr::CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
{
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE, !script->CanModAuraEffectDamageDone(auraEff, target, aurApp, mode, apply));
}
bool ScriptMgr::CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
{
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE, !script->CanModAuraEffectModDamagePercentDone(auraEff, target, aurApp, mode, apply));
}
void ScriptMgr::OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res)
{
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_SPELL_CHECK_CAST, script->OnSpellCheckCast(spell, strict, res));

View file

@ -24,8 +24,6 @@
enum AllSpellHook
{
ALLSPELLHOOK_ON_CALC_MAX_DURATION,
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE,
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE,
ALLSPELLHOOK_ON_SPELL_CHECK_CAST,
ALLSPELLHOOK_CAN_PREPARE,
ALLSPELLHOOK_CAN_SCALING_EVERYTHING,
@ -56,10 +54,6 @@ public:
// Calculate max duration in applying aura
virtual void OnCalcMaxDuration(Aura const* /*aura*/, int32& /*maxDuration*/) { }
[[nodiscard]] virtual bool CanModAuraEffectDamageDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
[[nodiscard]] virtual bool CanModAuraEffectModDamagePercentDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
virtual void OnSpellCheckCast(Spell* /*spell*/, bool /*strict*/, SpellCastResult& /*res*/) { }
[[nodiscard]] virtual bool CanPrepare(Spell* /*spell*/, SpellCastTargets const* /*targets*/, AuraEffect const* /*triggeredByAura*/) { return true; }

View file

@ -84,21 +84,6 @@ bool ScriptMgr::IfNormalReaction(Unit const* unit, Unit const* target, Reputatio
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IF_NORMAL_REACTION, !script->IfNormalReaction(unit, target, repRank));
}
bool ScriptMgr::IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT, !script->IsNeedModSpellDamagePercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT, !script->IsNeedModMeleeDamagePercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_HEAL_PERCENT, !script->IsNeedModHealPercent(unit, auraEff, doneTotalMod, spellProto));
}
bool ScriptMgr::CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update)
{
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_CAN_SET_PHASE_MASK, !script->CanSetPhaseMask(unit, newPhaseMask, update));

View file

@ -33,9 +33,6 @@ enum UnitHook
UNITHOOK_ON_AURA_APPLY,
UNITHOOK_ON_AURA_REMOVE,
UNITHOOK_IF_NORMAL_REACTION,
UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT,
UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT,
UNITHOOK_IS_NEEDMOD_HEAL_PERCENT,
UNITHOOK_CAN_SET_PHASE_MASK,
UNITHOOK_IS_CUSTOM_BUILD_VALUES_UPDATE,
UNITHOOK_SHOULD_TRACK_VALUES_UPDATE_POS_BY_INDEX,
@ -89,12 +86,6 @@ public:
[[nodiscard]] virtual bool IfNormalReaction(Unit const* /*unit*/, Unit const* /*target*/, ReputationRank& /*repRank*/) { return true; }
[[nodiscard]] virtual bool IsNeedModSpellDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool IsNeedModMeleeDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool IsNeedModHealPercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
[[nodiscard]] virtual bool CanSetPhaseMask(Unit const* /*unit*/, uint32 /*newPhaseMask*/, bool /*update*/) { return true; }
[[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; }

View file

@ -546,9 +546,6 @@ public: /* UnitScript */
void OnAuraApply(Unit* /*unit*/, Aura* /*aura*/);
void OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode);
bool IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank);
bool IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update);
bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index);
bool ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index);
@ -606,8 +603,6 @@ public: /* Arena Team Script */
public: /* SpellSC */
void OnCalcMaxDuration(Aura const* aura, int32& maxDuration);
bool CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
bool CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
void OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res);
bool CanPrepare(Spell* spell, SpellCastTargets const* targets, AuraEffect const* triggeredByAura);
bool CanScalingEverything(Spell* spell);

View file

@ -212,7 +212,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
&AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
&AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
&AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
&AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
&AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
&AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
&AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAggroRange
&AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
@ -393,7 +393,6 @@ AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32* baseAmount, Unit* cast
m_amount = CalculateAmount(caster);
m_casterLevel = caster ? caster->GetLevel() : 0;
m_applyResilience = caster && caster->CanApplyResilience();
m_auraGroup = sSpellMgr->GetSpellGroup(GetId());
CalculateSpellMod();
@ -3000,14 +2999,17 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
// Handle damage modification, shapeshifted druids are not affected
if (target->IsPlayer() && (!target->IsInFeralForm() || target->GetShapeshiftForm() == FORM_GHOSTWOLF))
{
if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
Player* player = target->ToPlayer();
if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
{
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
WeaponAttackType attackType = Player::GetAttackBySlot(slot);
if (attacktype < MAX_ATTACK)
player->ApplyItemDependentAuras(pItem, !apply);
if (attackType < MAX_ATTACK)
{
target->ToPlayer()->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
target->ToPlayer()->_ApplyWeaponDependentAuraMods(pItem, attacktype, !apply);
player->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
if (!apply) // apply case already handled on item dependent aura removal (if any)
player->UpdateWeaponDependentAuras(attackType);
}
}
}
@ -3439,9 +3441,17 @@ void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool
return;
Unit* target = aurApp->GetTarget();
for (int8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
if (GetMiscValue() & (1 << i))
ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply);
{
if (apply)
AddPct(target->m_threatModifier[i], GetAmount());
else
{
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_THREAT, 1 << i);
target->m_threatModifier[i] = amount;
}
}
}
void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -4318,7 +4328,7 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp,
Unit* target = aurApp->GetTarget();
for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
{
if (GetMiscValue() & int32(1 << x))
{
@ -4326,9 +4336,9 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp,
if (amount < GetAmount())
{
float value = float(GetAmount() - amount);
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
if (target->IsPlayer())
target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), value, apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
if (target->IsPlayer() || target->IsPet())
target->UpdateResistanceBuffModsMod(SpellSchools(x));
}
}
}
@ -4345,9 +4355,9 @@ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mo
{
if (GetMiscValue() & int32(1 << x))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply);
if (target->IsPlayer() || target->IsPet())
target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply);
target->UpdateResistanceBuffModsMod(SpellSchools(x));
}
}
}
@ -4358,32 +4368,39 @@ void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, u
return;
Unit* target = aurApp->GetTarget();
for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
{
if (GetMiscValue() & int32(1 << x))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply);
if (apply)
target->ApplyStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, 1 << x);
target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, amount);
}
}
}
}
void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
{
if (GetMiscValue() & int32(1 << i))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply);
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << i);
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT) == amount)
continue;
target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, amount);
if (target->IsPlayer() || target->IsPet())
{
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply);
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply);
}
target->UpdateResistanceBuffModsMod(SpellSchools(i));
}
}
}
@ -4398,7 +4415,7 @@ void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mo
{
if (GetMiscValue() & (1 << i))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
}
}
}
@ -4430,23 +4447,28 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
if (GetMiscValue() < -2 || GetMiscValue() > 4)
{
LOG_ERROR("spells.aura.effect", "WARNING: Spell {} effect {} has an unsupported misc value ({}) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
return;
}
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue());
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
// -1 or -2 is all stats (misc < -2 checked in function beginning)
if (GetMiscValue() < 0 || GetMiscValue() == i)
{
//target->ApplyStatMod(Stats(i), m_amount, apply);
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
if (spellGroupVal)
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), !apply);
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
if (target->IsPlayer() || target->IsPet())
target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply);
target->UpdateStatBuffMod(Stats(i));
}
}
}
@ -4470,8 +4492,16 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode,
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
if (GetMiscValue() == i || GetMiscValue() == -1)
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply);
if (apply)
target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff)
{
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
});
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount);
}
}
}
@ -4549,7 +4579,7 @@ void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode,
target->ToPlayer()->UpdateSpellDamageAndHealingBonus();
}
void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
@ -4565,39 +4595,22 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
// save current health state
float healthPct = target->GetHealthPct();
bool alive = target->IsAlive();
float value = GetAmount();
if (GetId() == 67480) // xinef: hack fix for blessing of sanctuary stats stack with blessing of kings...
{
if (value) // not turned off
value = 10.0f;
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
if (i == STAT_STRENGTH || i == STAT_STAMINA)
{
if (apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
if (!apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
}
}
return;
}
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
if (GetMiscValue() == i || GetMiscValue() == -1)
{
if (apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff)
{
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
});
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount)
continue;
if (!apply && (target->IsPlayer() || target->IsPet()))
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount);
if (target->IsPlayer() || target->IsPet())
target->UpdateStatBuffMod(Stats(i));
}
}
@ -4693,7 +4706,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
if (apply)
{
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->ModifyHealth(GetAmount());
}
else
@ -4702,7 +4715,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
target->ModifyHealth(-GetAmount());
else
target->SetHealth(1);
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
}
}
@ -4716,7 +4729,7 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
uint32 oldhealth = target->GetHealth();
double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
// refresh percentage
if (oldhealth > 0)
@ -4746,7 +4759,7 @@ void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint
UnitMods unitMod = UnitMods(static_cast<uint16>(UNIT_MOD_POWER_START) + PowerType);
target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply);
}
void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -4765,17 +4778,16 @@ void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurAp
// return;
UnitMods unitMod = UnitMods(static_cast<uint16>(UNIT_MOD_POWER_START) + PowerType);
float amount = float(GetAmount());
if (apply)
{
target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply);
target->ModifyPowerPct(PowerType, amount, apply);
float amount = float(GetAmount());
target->ApplyStatPctModifier(unitMod, TOTAL_PCT, amount);
}
else
{
target->ModifyPowerPct(PowerType, amount, apply);
target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply);
float amount = target->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, GetMiscValue());
target->SetStatPctModifier(unitMod, TOTAL_PCT, amount);
}
}
@ -4788,7 +4800,14 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp
// Unit will keep hp% after MaxHealth being modified if unit is alive.
float percent = target->GetHealthPct();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply);
if (apply)
target->ApplyStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT);
target->SetStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, amount);
}
// Xinef: pct was rounded down and could "kill" creature by setting its health to 0 making npc zombie
if (target->IsAlive())
@ -4803,7 +4822,13 @@ void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurA
Unit* target = aurApp->GetTarget();
target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply);
if (apply)
target->ApplyStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_HEALTH_PCT);
target->SetStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, amount);
}
}
/********************************/
@ -4857,34 +4882,17 @@ void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint
HandleModManaRegen(aurApp, mode, apply);
}
void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target->IsPlayer())
if (!target)
return;
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// GetMiscValue() comparison with item generated damage types
if (GetSpellInfo()->EquippedItemClass == -1)
{
target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
target->UpdateAllWeaponDependentCritAuras();
}
void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -4960,9 +4968,7 @@ void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode,
return;
}
target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
target->ToPlayer()->UpdateAllWeaponDependentCritAuras();
// included in Player::UpdateSpellCritChance calculation
target->ToPlayer()->UpdateAllSpellCritChances();
@ -4986,6 +4992,13 @@ void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode
return;
}
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
target->ApplyCastTimePercentMod((float)GetAmount(), apply);
}
@ -5007,6 +5020,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
return;
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW);
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
}
target->ApplyCastTimePercentMod(float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
@ -5031,7 +5055,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
return;
Unit* target = aurApp->GetTarget();
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE);
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
return;
if (spellGroupVal)
{
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
}
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
}
@ -5105,7 +5137,7 @@ void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 m
Unit* target = aurApp->GetTarget();
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply);
}
void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -5118,7 +5150,7 @@ void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, u
if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0)
return;
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
}
void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -5129,7 +5161,13 @@ void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp,
Unit* target = aurApp->GetTarget();
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply);
if (apply)
target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_ATTACK_POWER_PCT);
target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, amount);
}
}
void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -5143,7 +5181,13 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au
return;
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply);
if (apply)
target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT);
target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, amount);
}
}
void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
@ -5184,85 +5228,25 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
// apply item specific bonuses for already equipped weapon
if (target->IsPlayer())
{
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
target->UpdateAllDamageDoneMods();
// GetMiscValue() is bitmask of spell schools
// 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// GetMiscValue() comparison with item generated damage types
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0 && sScriptMgr->CanModAuraEffectDamageDone(this, target, aurApp, mode, apply))
{
// apply generic physical damage bonuses including wand case
if (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer())
{
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
if (target->IsPlayer())
{
if (GetAmount() > 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply);
else
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply);
}
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
}
// Skip non magic case for Speedup
if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if (GetSpellInfo()->EquippedItemClass != -1 || GetSpellInfo()->EquippedItemInventoryTypeMask != 0)
{
// wand magic case (skip generic to all item spell bonuses)
// done in Player::_ApplyWeaponDependentAuraMods
// Skip item specific requirements for not wand magic damage
return;
}
// Magic damage modifiers implemented in Unit::SpellDamageBonus
// Magic damage modifiers implemented in Unit::SpellBaseDamageBonus
// This information for client side use only
if (target->IsPlayer())
{
if (GetAmount() > 0)
{
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if ((GetMiscValue() & (1 << i)) != 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, GetAmount(), apply);
}
}
else
{
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if ((GetMiscValue() & (1 << i)) != 0)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, GetAmount(), apply);
}
}
uint16 baseField = GetAmount() >= 0 ? PLAYER_FIELD_MOD_DAMAGE_DONE_POS : PLAYER_FIELD_MOD_DAMAGE_DONE_NEG;
for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i)
if (GetMiscValue() & (1 << i))
target->ApplyModUInt32Value(baseField + i, GetAmount(), apply);
if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
pet->UpdateAttackPowerAndDamage();
}
}
void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
@ -5271,39 +5255,32 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
if (!target)
return;
if (!sScriptMgr->CanModAuraEffectModDamagePercentDone(this, target, aurApp, mode, apply))
return;
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
target->UpdateAllDamagePctDoneMods();
if (target->IsPlayer())
{
for (int i = 0; i < MAX_ATTACK; ++i)
if (Item* item = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), false))
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(item, WeaponAttackType(i), this, apply);
}
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer()))
{
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply);
if (target->IsPlayer())
target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods for SPELL_SCHOOL_MASK_NORMAL && EquippedItemClass != -1 and also for wand case
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
{
if (GetMiscValue() & (1 << i))
{
// only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, 1 << i);
target->SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, amount);
}
}
}
}
void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
// also handles spell group stacks
target->UpdateDamagePctDoneMods(OFF_ATTACK);
}
void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const
@ -5311,14 +5288,29 @@ void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mod
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Unit* target = aurApp->GetTarget();
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target)
return;
BaseModType modType = FLAT_MOD;
if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
modType = PCT_MOD;
target->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply);
}
if (target->IsPlayer())
target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply);
void AuraEffect::HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
return;
Player* target = aurApp->GetTarget()->ToPlayer();
if (!target)
return;
if (apply)
target->ApplyBaseModPctValue(SHIELD_BLOCK_VALUE, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT);
target->SetBaseModPctValue(SHIELD_BLOCK_VALUE, amount);
}
}
/********************************/

View file

@ -112,8 +112,6 @@ public:
float GetPctMods() const { return m_pctMods; }
void SetPctMods(float pctMods) { m_pctMods = pctMods; }
// xinef: stacking
uint32 GetAuraGroup() const { return m_auraGroup; }
int32 GetOldAmount() const { return m_oldAmount; }
void SetOldAmount(int32 amount) { m_oldAmount = amount; }
void SetEnabled(bool enabled) { m_isAuraEnabled = enabled; }
@ -131,8 +129,6 @@ private:
float m_critChance;
float m_pctMods;
// xinef: stacking
uint32 m_auraGroup;
int32 m_oldAmount;
bool m_isAuraEnabled;
// xinef: channel information for channel triggering
@ -299,6 +295,7 @@ public:
void HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const;
// power cost
void HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const;

View file

@ -181,67 +181,6 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
// Remove all triggered by aura spells vs unlimited duration
aurEff->CleanupTriggeredSpells(GetTarget());
}
// Stacking!
if (uint32 groupId = aurEff->GetAuraGroup())
{
SpellGroupStackFlags sFlag = sSpellMgr->GetGroupStackFlags(groupId);
if (!aurEff->IsPeriodic() && (sFlag & SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE))
{
AuraApplication* strongestApp = apply ? this : nullptr;
AuraEffect* strongestEff = apply ? aurEff : nullptr;
int32 amount = apply ? std::abs(aurEff->GetAmount()) : 0;
Unit* target = GetTarget();
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType(aurEff->GetAuraType());
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
{
if ((*iter)->GetAuraGroup() != groupId || (*iter) == strongestEff || (*iter)->GetBase()->IsRemoved())
continue;
// xinef: skip different misc values
if (aurEff->GetAuraType() != SPELL_AURA_230 /*SPELL_AURA_MOD_INCREASE_HEALTH_2*/ && aurEff->GetAuraType() != SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK &&
aurEff->GetMiscValue() != (*iter)->GetMiscValue())
continue;
// xinef: should not happen
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
if (!aurApp)
continue;
if (amount < std::abs((*iter)->GetForcedAmount()))
{
// xinef: if we have strongest aura and it is active, turn it off
// xinef: otherwise just save new aura;
if (strongestApp && strongestEff && strongestApp->IsActive(strongestEff->GetEffIndex()))
{
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
if (!strongestEff->GetSpellInfo()->HasAreaAuraEffect())
strongestEff->SetEnabled(false);
strongestApp->SetDisableMask(strongestEff->GetEffIndex());
}
strongestApp = aurApp;
strongestEff = (*iter);
amount = std::abs((*iter)->GetAmount());
}
// xinef: itered aura is weaker, deactivate if active
else if (aurApp->IsActive((*iter)->GetEffIndex()))
{
(*iter)->HandleEffect(aurApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
if (!(*iter)->GetSpellInfo()->HasAreaAuraEffect())
(*iter)->SetEnabled(false);
aurApp->SetDisableMask((*iter)->GetEffIndex());
}
}
// xinef: if we have new strongest aura, and it is not active
if (strongestApp && strongestEff && !strongestApp->IsActive(strongestEff->GetEffIndex()))
{
strongestApp->RemoveDisableMask(strongestEff->GetEffIndex());
strongestEff->SetEnabled(true);
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, true);
}
}
}
SetNeedClientUpdate();
}
@ -661,6 +600,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo()) || !CanBeAppliedOn(itr->first))
addUnit = false;
if (addUnit && !itr->first->IsHighestExclusiveAura(this, true))
addUnit = false;
if (addUnit)
{
// persistent area aura does not hit flying targets
@ -684,7 +626,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
for (Unit::AuraApplicationMap::iterator iter = itr->first->GetAppliedAuras().begin(); iter != itr->first->GetAppliedAuras().end(); ++iter)
{
Aura const* aura = iter->second->GetBase();
if (!CanStackWith(aura, false))
if (!CanStackWith(aura))
{
addUnit = false;
break;
@ -1069,6 +1011,16 @@ void Aura::RefreshSpellMods()
player->RestoreAllSpellMods(0, this);
}
bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const
{
uint32 count = 0;
for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
if (HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.ApplyAuraName == auraType)
++count;
return count > 1;
}
bool Aura::IsArea() const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@ -1589,7 +1541,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// Alchemy: Mixology
if (caster && caster->HasAura(53042) && caster->IsPlayer() && !caster->ToPlayer()->GetSession()->PlayerLoading())
{
if (sSpellMgr->GetSpellGroup(GetId()) == 1) /*Elixirs*/
if (sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
{
if (caster->HasSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell))
{
@ -2018,7 +1970,7 @@ bool Aura::IsAuraStronger(Aura const* newAura) const
return false;
}
bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
bool Aura::CanStackWith(Aura const* existingAura) const
{
// Can stack with self
if (this == existingAura)
@ -2056,47 +2008,19 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
return false;
// check spell group stack rules
// xinef: this assures us that both spells are in same group!
SpellGroupStackFlags stackFlags = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo, remove, IsArea());
if (stackFlags)
switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo))
{
// xinef: same caster rule is bounded by spellfamily
if (sameCaster && m_spellInfo->SpellFamilyName == existingSpellInfo->SpellFamilyName &&
(stackFlags & SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER))
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal
return false;
// xinef: normal exclusive stacking, remove if auras are equal by effects
if (stackFlags & SPELL_GROUP_STACK_FLAG_EXCLUSIVE)
{
if (GetSpellInfo()->IsAuraEffectEqual(existingSpellInfo) || GetSpellInfo()->IsRankOf(existingSpellInfo))
{
if (remove)
return IsAuraStronger(existingAura);
else
return existingAura->IsAuraStronger(this);
}
}
// xinef: check priority before effect mask
SpellGroupSpecialFlags thisAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(GetId());
SpellGroupSpecialFlags existingAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(existingSpellInfo->Id);
if (thisAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && thisAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 &&
existingAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && existingAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
{
if (thisAuraFlag < existingAuraFlag)
{
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
if (sameCaster)
return false;
}
}
// xinef: forced strongest aura in group by flag
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST)
return !remove;
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST)
return remove;
// xinef: forced return, handle all cases using available flags!
return !(stackFlags & SPELL_GROUP_STACK_FLAG_NEVER_STACK);
break;
case SPELL_GROUP_STACK_RULE_DEFAULT:
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT:
default:
break;
}
if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName)

View file

@ -153,6 +153,7 @@ public:
uint8 GetCasterLevel() const { return m_casterLevel; }
bool HasMoreThanOneEffectForType(AuraType auraType) const;
bool IsArea() const;
bool IsPassive() const;
bool IsDeathPersistent() const;
@ -188,7 +189,7 @@ public:
void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply);
bool CanBeAppliedOn(Unit* target);
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* checkAura, bool remove) const;
bool CanStackWith(Aura const* existingAura) const;
bool IsAuraStronger(Aura const* newAura) const;
// Proc system

View file

@ -19,7 +19,6 @@
#include "ArenaSpectator.h"
#include "BattlefieldMgr.h"
#include "Battleground.h"
#include "BattlegroundIC.h"
#include "CharmInfo.h"
#include "CellImpl.h"
#include "Common.h"
@ -33,7 +32,6 @@
#include "InstanceScript.h"
#include "Log.h"
#include "LootMgr.h"
#include "MapMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@ -41,6 +39,7 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "SharedDefines.h"
#include "SpellAuraDefines.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
@ -1240,11 +1239,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
if ((*j)->IsAffectedOnSpell(m_spellInfo))
maxTargets += (*j)->GetAmount();
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Acore::Containers::RandomResize(targets, maxTargets);
}
@ -1327,11 +1322,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
if ((*j)->IsAffectedOnSpell(m_spellInfo))
maxTargets += (*j)->GetAmount();
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
Acore::Containers::RandomResize(targets, maxTargets);
}
@ -6076,6 +6067,8 @@ SpellCastResult Spell::CheckCast(bool strict)
}
}
uint8 approximateAuraEffectMask = 0;
uint8 nonAuraEffectMask = 0;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
// for effects of spells that have only one target
@ -6561,6 +6554,11 @@ SpellCastResult Spell::CheckCast(bool strict)
default:
break;
}
if (m_spellInfo->Effects[i].IsAura())
approximateAuraEffectMask |= 1 << i;
else if (m_spellInfo->Effects[i].IsEffect())
nonAuraEffectMask |= 1 << i;
}
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@ -6723,6 +6721,13 @@ SpellCastResult Spell::CheckCast(bool strict)
default:
break;
}
// check if target already has the same type, but more powerful aura
if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << i)) && !m_spellInfo->IsTargetingArea())
if (Unit* target = m_targets.GetUnitTarget())
if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(m_spellInfo->Effects[i].ApplyAuraName),
m_spellInfo->Effects[i].CalcValue(m_caster, &m_spellValue->EffectBasePoints[i]), approximateAuraEffectMask, false))
return SPELL_FAILED_AURA_BOUNCED;
}
// check trade slot case (last, for allow catch any another cast problems)
@ -6973,26 +6978,35 @@ bool Spell::CanAutoCast(Unit* target)
{
ObjectGuid targetguid = target->GetGUID();
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
{
if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
if (!spellEffectInfo.IsAura())
continue;
AuraType const& auraType = spellEffectInfo.ApplyAuraName;
Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
{
if (m_spellInfo->StackAmount <= 1)
{
if (target->HasAuraEffect(m_spellInfo->Id, j))
return false;
}
else
{
if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j))
if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount)
return false;
}
}
else if (m_spellInfo->Effects[j].IsAreaAuraEffect())
{
if (target->HasAuraEffect(m_spellInfo->Id, j))
if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
return false;
switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
{
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
return false;
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
if (GetCaster() == (*auraIt)->GetCaster())
return false;
break;
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST:
if (abs(spellEffectInfo.BasePoints) <= abs((*auraIt)->GetAmount()))
return false;
break;
case SPELL_GROUP_STACK_RULE_DEFAULT:
default:
break;
}
}
}

View file

@ -1952,13 +1952,10 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
{
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->second->GetBase()->GetId());
if (!guardianFound)
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
guardianFound = true;
if (!battleFound)
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE)
battleFound = true;
if (!guardianFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
guardianFound = true;
if (!battleFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_BATTLE))
battleFound = true;
if (battleFound && guardianFound)
break;
}
@ -1966,9 +1963,9 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
// get all available elixirs by mask and spell level
std::set<uint32> availableElixirs;
if (!guardianFound)
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN, availableElixirs);
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, availableElixirs);
if (!battleFound)
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE, availableElixirs);
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, availableElixirs);
for (std::set<uint32>::iterator itr = availableElixirs.begin(); itr != availableElixirs.end();)
{
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*itr);
@ -3598,7 +3595,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
unitMod = UNIT_MOD_DAMAGE_RANGED;
break;
}
float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
float weapon_total_pct = m_caster->GetPctModifierValue(unitMod, TOTAL_PCT);
fixed_bonus = int32(fixed_bonus * weapon_total_pct);
spell_bonus = int32(spell_bonus * weapon_total_pct);
}

View file

@ -326,9 +326,9 @@ std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplic
SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
{
_spellInfo = spellInfo;
_effIndex = effIndex;
EffectIndex = effIndex;
Effect = spellEntry->Effect[effIndex];
ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex];
ApplyAuraName = AuraType(spellEntry->EffectApplyAuraName[effIndex]);
Amplitude = spellEntry->EffectAmplitude[effIndex];
DieSides = spellEntry->EffectDieSides[effIndex];
RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex];
@ -456,7 +456,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
value += PointsPerComboPoint * comboPoints;
}
value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value);
// amount multiplication based on caster's level
if (!caster->IsControlledByPlayer() &&
@ -501,7 +501,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
break;
}
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
canEffectScale = false;
if (canEffectScale)
@ -1579,122 +1579,6 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
return SPELL_CAST_OK;
}
bool SpellInfo::IsStrongerAuraActive(Unit const* caster, Unit const* target) const
{
if (!target)
return false;
// xinef: check spell group
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
if (!groupId)
return false;
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK)
return false;
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
// xinef: Skip Empty effects
if (!Effects[i].IsEffect())
continue;
// xinef: if non-aura effect is preset - return false
if (!Effects[i].IsAura())
return false;
// xinef: aura is periodic - return false
if (Effects[i].Amplitude)
return false;
// xinef: exclude dummy auras
if (Effects[i].ApplyAuraName == SPELL_AURA_DUMMY)
return false;
}
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
// xinef: skip non-aura efects
if (!Effects[i].IsAura())
return false;
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType((AuraType)Effects[i].ApplyAuraName);
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
{
// xinef: aura is not groupped or in different group
uint32 auraGroup = (*iter)->GetAuraGroup();
if (!auraGroup || auraGroup != groupId)
continue;
if (IsRankOf((*iter)->GetSpellInfo()) && (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL))
{
continue;
}
// xinef: check priority before effect mask
if (sFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
{
SpellGroupSpecialFlags sFlagCurr = sSpellMgr->GetSpellGroupSpecialFlags((*iter)->GetId());
if (sFlagCurr >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlagCurr <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 && sFlagCurr < sFlag)
{
return true;
}
}
// xinef: check aura effect equal auras only, some auras have different effects on different ranks - check rank also
if (!IsAuraEffectEqual((*iter)->GetSpellInfo()) && !IsRankOf((*iter)->GetSpellInfo()))
continue;
// xinef: misc value mismatches
// xinef: commented, checked above
//if (Effects[i].MiscValue != (*iter)->GetMiscValue())
// continue;
// xinef: should not happen, or effect is not active - stronger one is present
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
if (!aurApp || !aurApp->IsActive((*iter)->GetEffIndex()))
continue;
// xinef: assume that all spells are either positive or negative, otherwise they should not be in one group
// xinef: take custom values into account
int32 basePoints = Effects[i].BasePoints;
int32 duration = GetMaxDuration();
// xinef: should have the same id, can be different if spell is triggered
// xinef: have to fix spell mods for triggered spell, turn off current spellmodtakingspell for preparing and restore after
if (Player const* player = caster->GetSpellModOwner())
if (player->m_spellModTakingSpell && player->m_spellModTakingSpell->m_spellInfo->Id == Id)
basePoints = player->m_spellModTakingSpell->GetSpellValue()->EffectBasePoints[i];
int32 curValue = std::abs(Effects[i].CalcValue(caster, &basePoints));
int32 auraValue = (sFlag & SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK) ?
std::abs((*iter)->GetSpellInfo()->Effects[(*iter)->GetEffIndex()].CalcValue((*iter)->GetCaster())) :
std::abs((*iter)->GetAmount());
// xinef: for same spells, divide amount by stack amount
if (Id == (*iter)->GetId())
auraValue /= (*iter)->GetBase()->GetStackAmount();
if (curValue < auraValue)
return true;
// xinef: little hack, if current spell is the same as aura spell, asume it is not stronger
// xinef: if values are the same, duration mods should be taken into account but they are almost always passive
if (curValue == auraValue)
{
if (Id == (*iter)->GetId())
continue;
if (!(*iter)->GetBase()->IsPassive() && duration < (*iter)->GetBase()->GetDuration())
return true;
}
}
}
return false;
}
bool SpellInfo::IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const
{
uint8 matchCount = 0;
@ -1938,10 +1822,6 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW))
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
// xinef: check if stronger aura is active
if (IsStrongerAuraActive(caster, unitTarget))
return SPELL_FAILED_AURA_BOUNCED;
return SPELL_CAST_OK;
}
@ -2316,6 +2196,8 @@ SpellSpecificType SpellInfo::LoadSpellSpecific() const
case SPELL_AURA_TRACK_RESOURCES:
case SPELL_AURA_TRACK_STEALTHED:
return SPELL_SPECIFIC_TRACKER;
default:
break;
}
}
}
@ -2399,6 +2281,8 @@ uint32 SpellInfo::GetMaxTicks() const
if (Effects[x].Amplitude != 0)
return DotDuration / Effects[x].Amplitude;
break;
default:
break;
}
}
@ -2889,50 +2773,3 @@ void SpellInfo::_UnloadImplicitTargetConditionLists()
delete cur;
}
}
bool SpellInfo::CheckElixirStacking(Unit const* caster) const
{
if (!caster)
{
return true;
}
// xinef: check spell group
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
if (groupId != SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS)
{
return true;
}
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!Effects[i].IsAura())
{
continue;
}
Unit::AuraApplicationMap const& Auras = caster->GetAppliedAuras();
for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
{
// xinef: aura is not groupped or in different group
uint32 auraGroup = sSpellMgr->GetSpellGroup(itr->first);
if (auraGroup != groupId)
{
continue;
}
// Cannot apply guardian/battle elixir if flask is present
if (sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE || sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
{
SpellGroupSpecialFlags sAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->first);
if ((sAuraFlag & SPELL_GROUP_SPECIAL_FLAG_FLASK) == SPELL_GROUP_SPECIAL_FLAG_FLASK)
{
return false;
}
}
}
}
return true;
}

View file

@ -248,10 +248,10 @@ private:
class SpellEffectInfo
{
SpellInfo const* _spellInfo;
uint8 _effIndex;
public:
uint8 EffectIndex;
uint32 Effect;
uint32 ApplyAuraName;
AuraType ApplyAuraName;
uint32 Amplitude;
int32 DieSides;
float RealPointsPerLevel;
@ -272,7 +272,7 @@ public:
flag96 SpellClassMask;
std::list<Condition*>* ImplicitTargetConditions;
SpellEffectInfo() : _spellInfo(nullptr), _effIndex(0), Effect(0), ApplyAuraName(0), Amplitude(0), DieSides(0),
SpellEffectInfo() : _spellInfo(nullptr), EffectIndex(0), Effect(0), ApplyAuraName(SPELL_AURA_NONE), Amplitude(0), DieSides(0),
RealPointsPerLevel(0), BasePoints(0), PointsPerComboPoint(0), ValueMultiplier(0), DamageMultiplier(0),
BonusMultiplier(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(nullptr), ChainTarget(0),
ItemType(0), TriggerSpell(0), ImplicitTargetConditions(nullptr) {}
@ -482,8 +482,6 @@ public:
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
bool CheckTargetCreatureType(Unit const* target) const;
// xinef: aura stacking
bool IsStrongerAuraActive(Unit const* caster, Unit const* target) const;
bool IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const;
bool ValidateAttribute6SpellDamageMods(Unit const* caster, const AuraEffect* auraEffect, bool isDot) const;
@ -539,8 +537,6 @@ public:
// unloading helpers
void _UnloadImplicitTargetConditionLists();
bool CheckElixirStacking(Unit const* caster) const;
private:
std::array<SpellEffectInfo, MAX_SPELL_EFFECTS>& _GetEffects() { return Effects; }
SpellEffectInfo& _GetEffect(SpellEffIndex index) { ASSERT(index < Effects.size()); return Effects[index]; }

View file

@ -570,14 +570,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Blessing of sanctuary stats
ApplySpellFix({ 67480 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].MiscValue = -1;
spellInfo->SpellFamilyName = SPELLFAMILY_UNK1; // allows stacking
spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_DUMMY; // just a marker
});
ApplySpellFix({
6940, // Hand of Sacrifice
64205 // Divine Sacrifice

View file

@ -18,12 +18,9 @@
#include "SpellMgr.h"
#include "BattlefieldMgr.h"
#include "BattlegroundIC.h"
#include "BattlegroundMgr.h"
#include "Chat.h"
#include "DBCStores.h"
#include "GameGraveyard.h"
#include "InstanceScript.h"
#include "MapMgr.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
@ -648,82 +645,143 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
return nullptr;
}
SpellGroupStackFlags SpellMgr::GetGroupStackFlags(uint32 groupid) const
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
{
SpellGroupStackMap::const_iterator itr = mSpellGroupStackMap.find(groupid);
if (itr != mSpellGroupStackMap.end())
spell_id = GetFirstSpellInChain(spell_id);
return mSpellSpellGroup.equal_range(spell_id);
}
bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const
{
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spell_id);
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
{
if (itr->second == group_id)
return true;
}
return false;
}
SpellGroupSpellMapBounds SpellMgr::GetSpellGroupSpellMapBounds(SpellGroup group_id) const
{
return mSpellGroupSpell.equal_range(group_id);
}
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
{
std::set<SpellGroup> usedGroups;
GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
}
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
{
if (usedGroups.find(group_id) != usedGroups.end())
return;
usedGroups.insert(group_id);
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(group_id);
for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
{
if (itr->second < 0)
{
SpellGroup currGroup = (SpellGroup)abs(itr->second);
GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
}
else
{
foundSpells.insert(itr->second);
}
}
}
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
{
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
{
SpellGroup group = itr->second;
auto found = mSpellSameEffectStack.find(group);
if (found != mSpellSameEffectStack.end())
{
// check auraTypes
if (!found->second.count(auraType))
continue;
// Put the highest amount in the map
auto groupItr = groups.find(group);
if (groupItr == groups.end())
groups.emplace(group, amount);
else
{
int32 curr_amount = groups[group];
// Take absolute value because this also counts for the highest negative aura
if (std::abs(curr_amount) < std::abs(amount))
groupItr->second = amount;
}
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
return true;
}
}
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
return false;
}
SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const
{
ASSERT(spellInfo1);
ASSERT(spellInfo2);
uint32 spell_id1 = spellInfo1->GetFirstRankSpell()->Id;
uint32 spell_id2 = spellInfo2->GetFirstRankSpell()->Id;
// find SpellGroups which are common for both spells
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spell_id1);
std::set<SpellGroup> groups;
for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
{
if (IsSpellMemberOfSpellGroup(spell_id2, itr->second))
{
bool add = true;
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(itr->second);
for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
{
if (itr2->second < 0)
{
SpellGroup currGroup = (SpellGroup)abs(itr2->second);
if (IsSpellMemberOfSpellGroup(spell_id1, currGroup) && IsSpellMemberOfSpellGroup(spell_id2, currGroup))
{
add = false;
break;
}
}
}
if (add)
groups.insert(itr->second);
}
}
SpellGroupStackRule rule = SPELL_GROUP_STACK_RULE_DEFAULT;
for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
{
SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
if (found != mSpellGroupStack.end())
rule = found->second;
if (rule)
break;
}
return rule;
}
SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
{
SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
if (itr != mSpellGroupStack.end())
return itr->second;
return SPELL_GROUP_STACK_FLAG_NONE;
}
uint32 SpellMgr::GetSpellGroup(uint32 spell_id) const
{
uint32 first_rank = GetFirstSpellInChain(spell_id);
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
if (itr != mSpellGroupMap.end())
return itr->second.groupId;
return 0;
}
SpellGroupSpecialFlags SpellMgr::GetSpellGroupSpecialFlags(uint32 spell_id) const
{
uint32 first_rank = GetFirstSpellInChain(spell_id);
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
if (itr != mSpellGroupMap.end())
return itr->second.specialFlags;
return SPELL_GROUP_SPECIAL_FLAG_NONE;
}
SpellGroupStackFlags SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const
{
uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
uint32 groupId = GetSpellGroup(spellid_1);
SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1);
// xinef: dunno why i added this
if (spellid_1 == spellid_2 && remove && !areaAura)
{
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK)
{
return SPELL_GROUP_STACK_FLAG_EXCLUSIVE;
}
return SPELL_GROUP_STACK_FLAG_NONE;
}
if (groupId > 0 && groupId == GetSpellGroup(spellid_2))
{
SpellGroupSpecialFlags flag2 = GetSpellGroupSpecialFlags(spellid_2);
SpellGroupStackFlags additionFlag = SPELL_GROUP_STACK_FLAG_NONE;
// xinef: first flags are used for elixir stacking rules
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX && flag2 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX)
{
if (flag1 & flag2)
return SPELL_GROUP_STACK_FLAG_NEVER_STACK;
}
// xinef: check only flag1 (new spell)
else if (flag1 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST;
else if (flag2 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST;
return SpellGroupStackFlags(GetGroupStackFlags(groupId) | additionFlag);
}
return SPELL_GROUP_STACK_FLAG_NONE;
}
void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const
{
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
if (itr->second.groupId == group_id && itr->second.specialFlags == flag)
availableElixirs.insert(itr->first); // insert spell id
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
@ -1627,10 +1685,11 @@ void SpellMgr::LoadSpellGroups()
{
uint32 oldMSTime = getMSTime();
mSpellGroupMap.clear(); // need for reload case
mSpellSpellGroup.clear(); // need for reload case
mSpellGroupSpell.clear();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT id, spell_id, special_flag FROM spell_group");
// 0 1
QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
@ -1638,48 +1697,68 @@ void SpellMgr::LoadSpellGroups()
return;
}
std::set<uint32> groups;
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 group_id = fields[0].Get<uint32>();
int32 spell_id = fields[1].Get<uint32>();
SpellGroupSpecialFlags specialFlag = (SpellGroupSpecialFlags)fields[2].Get<uint32>();
SpellInfo const* spellInfo = GetSpellInfo(spell_id);
if (!spellInfo)
if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", spell_id);
continue;
}
else if (spellInfo->GetRank() > 1)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell", spell_id);
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
continue;
}
int32 spell_id = fields[1].Get<int32>();
if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end())
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has more than one group", spell_id);
continue;
}
groups.insert(group_id);
mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has invalid special flag!", spell_id);
continue;
}
SpellStackInfo ssi;
ssi.groupId = group_id;
ssi.specialFlags = specialFlag;
mSpellGroupMap[spell_id] = ssi;
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Spell Group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
{
if (itr->second < 0)
{
if (groups.find(abs(itr->second)) == groups.end())
{
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
}
else
{
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
if (!spellInfo)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", itr->second);
itr = mSpellGroupSpell.erase(itr);
}
else if (spellInfo->GetRank() > 1)
{
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell.", itr->second);
itr = mSpellGroupSpell.erase(itr);
}
else
++itr;
}
}
for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
{
std::set<uint32> spells;
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
{
++count;
mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
}
}
LOG_INFO("server.loading", ">> Loaded {} spell group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@ -1687,7 +1766,10 @@ void SpellMgr::LoadSpellGroupStackRules()
{
uint32 oldMSTime = getMSTime();
mSpellGroupStackMap.clear(); // need for reload case
mSpellGroupStack.clear(); // need for reload case
mSpellSameEffectStack.clear();
std::vector<uint32> sameEffectGroups;
// 0 1
QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
@ -1705,32 +1787,132 @@ void SpellMgr::LoadSpellGroupStackRules()
uint32 group_id = fields[0].Get<uint32>();
uint8 stack_rule = fields[1].Get<int8>();
if (stack_rule >= SPELL_GROUP_STACK_FLAG_MAX)
if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
{
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist", stack_rule);
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
continue;
}
bool present = false;
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
if (itr->second.groupId == group_id)
{
present = true;
break;
}
if (!present)
auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
if (bounds.first == bounds.second)
{
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist", group_id);
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
continue;
}
mSpellGroupStackMap[group_id] = (SpellGroupStackFlags)stack_rule;
mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
// different container for same effect stack rules, need to check effect types
if (stack_rule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
sameEffectGroups.push_back(group_id);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Spell Group Stack Rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
count = 0;
oldMSTime = getMSTime();
for (uint32 group_id : sameEffectGroups)
{
std::set<uint32> spellIds;
GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
std::unordered_set<uint32> auraTypes;
// we have to 'guess' what effect this group corresponds to
{
std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
// only waylay for the moment (shared group)
std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
{
{ SPELL_AURA_MOD_MELEE_HASTE, SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELL_AURA_MOD_RANGED_HASTE }
};
for (uint32 spellId : spellIds)
{
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
{
if (!spellEffectInfo.IsAura())
continue;
uint32 auraName = spellEffectInfo.ApplyAuraName;
for (std::vector<uint32> const& subGroup : SubGroups)
{
if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
{
// count as first aura
auraName = subGroup.front();
break;
}
}
frequencyContainer.insert(auraName);
}
}
uint32 auraType = 0;
size_t auraTypeCount = 0;
for (uint32 auraName : frequencyContainer)
{
size_t currentCount = frequencyContainer.count(auraName);
if (currentCount > auraTypeCount)
{
auraType = auraName;
auraTypeCount = currentCount;
}
}
for (std::vector<uint32> const& subGroup : SubGroups)
{
if (auraType == subGroup.front())
{
auraTypes.insert(subGroup.begin(), subGroup.end());
break;
}
}
if (auraTypes.empty())
auraTypes.insert(auraType);
}
// re-check spells against guessed group
for (uint32 spellId : spellIds)
{
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
bool found = false;
while (spellInfo)
{
for (uint32 auraType : auraTypes)
{
if (spellInfo->HasAura(AuraType(auraType)))
{
found = true;
break;
}
}
if (found)
break;
spellInfo = spellInfo->GetNextRankSpell();
}
// not found either, log error
if (!found)
LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
}
mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
++count;
}
LOG_INFO("server.loading", ">> Loaded {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
@ -2920,6 +3102,8 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_AURA_WATER_BREATHING:
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
default:
break;
}
switch (spellInfo->Effects[j].ApplyAuraName)
@ -3494,6 +3678,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (triggerSpell->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL)
allNonBinary = false;
}
break;
default:
break;
}
}
}

View file

@ -20,7 +20,6 @@
// For static or at-server-startup loaded spell data
#include "Common.h"
#include "Log.h"
#include "SharedDefines.h"
#include "Unit.h"
@ -330,56 +329,49 @@ struct SpellBonusEntry
typedef std::unordered_map<uint32, SpellBonusEntry> SpellBonusMap;
enum SpellGroupSpecialFlags
enum SpellGroup
{
SPELL_GROUP_SPECIAL_FLAG_NONE = 0x000,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE = 0x001,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN = 0x002,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_UNSTABLE = 0x004,
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_SHATTRATH = 0x008,
SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX = 0x00F,
SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST = 0x010, // xinef: specially helpful flag if some spells have different auras, but only one should be present
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK = 0x020,
SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK = 0x040,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 = 0x100,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY2 = 0x200,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY3 = 0x400,
SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 = 0x800,
SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK = 0x1000,
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL = 0x2000,
SPELL_GROUP_SPECIAL_FLAG_MAX = 0x4000,
SPELL_GROUP_SPECIAL_FLAG_FLASK = SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE | SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN
SPELL_GROUP_NONE = 0,
SPELL_GROUP_ELIXIR_BATTLE = 1,
SPELL_GROUP_ELIXIR_GUARDIAN = 2,
SPELL_GROUP_CORE_RANGE_MAX = 3
};
enum SpellGroupStackFlags
namespace std
{
SPELL_GROUP_STACK_FLAG_NONE = 0x00,
SPELL_GROUP_STACK_FLAG_EXCLUSIVE = 0x01,
SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER = 0x02,
SPELL_GROUP_STACK_FLAG_FLAGGED = 0x04, // xinef: just a marker
SPELL_GROUP_STACK_FLAG_NEVER_STACK = 0x08,
SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE = 0x10,
SPELL_GROUP_STACK_FLAG_MAX = 0x20,
template<>
struct hash<SpellGroup>
{
size_t operator()(SpellGroup const& group) const
{
return hash<uint32>()(uint32(group));
}
};
}
// Internal use
SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST = 0x100,
SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST = 0x200,
#define SPELL_GROUP_DB_RANGE_MIN 1000
// spell_id, group_id
typedef std::unordered_multimap<uint32, SpellGroup> SpellSpellGroupMap;
typedef std::pair<SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator> SpellSpellGroupMapBounds;
// group_id, spell_id
typedef std::unordered_multimap<SpellGroup, int32> SpellGroupSpellMap;
typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator> SpellGroupSpellMapBounds;
enum SpellGroupStackRule
{
SPELL_GROUP_STACK_RULE_DEFAULT,
SPELL_GROUP_STACK_RULE_EXCLUSIVE,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT,
SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST,
SPELL_GROUP_STACK_RULE_MAX
};
enum SpellGroupIDs
{
SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS = 1
};
typedef std::unordered_map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
struct SpellStackInfo
{
uint32 groupId;
SpellGroupSpecialFlags specialFlags;
};
// spell_id, group_id
typedef std::map<uint32, SpellStackInfo> SpellGroupMap;
typedef std::map<uint32, SpellGroupStackFlags> SpellGroupStackMap;
typedef std::unordered_map<SpellGroup, std::unordered_set<uint32 /*auraName*/>> SameEffectStackMap;
struct SpellThreatEntry
{
@ -679,12 +671,18 @@ public:
// Spell target coordinates
[[nodiscard]] SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
// Spell Groups
[[nodiscard]] uint32 GetSpellGroup(uint32 spellid) const;
[[nodiscard]] SpellGroupSpecialFlags GetSpellGroupSpecialFlags(uint32 spell_id) const;
[[nodiscard]] SpellGroupStackFlags GetGroupStackFlags(uint32 groupid) const;
SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const;
void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const;
// Spell Groups table
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;
bool IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const;
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const;
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const;
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const;
// Spell Group Stack Rules table
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const;
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup group_id) const;
// Spell proc event table
[[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
@ -798,8 +796,10 @@ private:
SpellRequiredMap mSpellReq;
SpellLearnSkillMap mSpellLearnSkills;
SpellTargetPositionMap mSpellTargetPositions;
SpellGroupMap mSpellGroupMap;
SpellGroupStackMap mSpellGroupStackMap;
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
SameEffectStackMap mSpellSameEffectStack;
SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;

View file

@ -78,6 +78,10 @@ Position const PosMoveOnSpawn[1] =
{ -11561.9f, -1627.868f, 41.29941f, 0.0f }
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
class boss_arlokk : public CreatureScript
{
public:
@ -90,7 +94,7 @@ public:
void Reset() override
{
if (events.IsInPhase(PHASE_TWO))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
_Reset();
_summonCountA = 0;
_summonCountB = 0;
@ -253,7 +257,7 @@ public:
events.ScheduleEvent(EVENT_RAVAGE, 10s, 14s, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 30s, 40s, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease); // hack
break;
case EVENT_RAVAGE:
DoCastVictim(SPELL_RAVAGE, true);
@ -265,7 +269,7 @@ public:
DoCast(me, SPELL_VANISH_VISUAL);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 4s, 7s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, 12s, 15s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, 30s, 0, PHASE_ONE);

View file

@ -73,6 +73,10 @@ enum Misc
GO_SPIDER_EGGS = 179985,
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
// High Priestess Mar'li (14510)
struct boss_marli : public BossAI
{
@ -84,7 +88,7 @@ public:
if (_phase == PHASE_SPIDER)
{
me->RemoveAura(SPELL_SPIDER_FORM);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
_phase = PHASE_TROLL;
}
@ -143,7 +147,7 @@ private:
me->RemoveAura(SPELL_SPIDER_FORM);
DoCastSelf(SPELL_TRANSFORM_BACK, true);
Talk(SAY_TRANSFORM_BACK);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
scheduler.CancelGroup(PHASE_SPIDER);
}
@ -186,7 +190,7 @@ private:
Talk(SAY_TRANSFORM);
DoCastSelf(SPELL_SPIDER_FORM, true);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease);
scheduler.Schedule(5s, PHASE_SPIDER, [this](TaskContext context)
{

View file

@ -2037,7 +2037,7 @@ public:
npc_toc_enh_shamanAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE)
{
SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE);
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->UpdateDamagePhysical(OFF_ATTACK);
events.Reset();

View file

@ -109,7 +109,7 @@ struct boss_twin_valkyrAI : public ScriptedAI
{
pInstance = pCreature->GetInstanceScript();
me->SetReactState(REACT_PASSIVE);
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
me->UpdateDamagePhysical(OFF_ATTACK);
LastSynchroHP = (int32)me->GetMaxHealth();
SpecialMask = 0;

View file

@ -271,12 +271,12 @@ class spell_astromancer_solarian_transform : public AuraScript
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, true);
GetUnitOwner()->ApplyStatPctModifier(UNIT_MOD_ARMOR, TOTAL_PCT, 400.0f);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, false);
GetUnitOwner()->ApplyStatPctModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, -80.0f);
}
void Register() override

View file

@ -99,7 +99,7 @@ struct npc_pet_hunter_snake_trap : public ScriptedAI
uint32 health = uint32(107 * (me->GetLevel() - 40) * 0.025f);
me->SetCreateHealth(health);
me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
me->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
me->SetMaxHealth(health);
//Add delta to make them not all hit the same time

View file

@ -174,8 +174,8 @@ class spell_dk_raise_ally : public SpellScript
if (pInfo) // exist in DB
{
ghoul->SetCreateHealth(pInfo->health);
ghoul->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
ghoul->SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
ghoul->SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
ghoul->SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
}
@ -194,9 +194,9 @@ class spell_dk_raise_ally : public SpellScript
// DK Ghoul haste refresh
float val = (GetCaster()->m_modAttackSpeedPct[BASE_ATTACK] - 1.0f) * 100.0f;
val *= 2000.0f + 2000.0f * ((100.0f + val) / 100.0f);
ghoul->m_modAttackSpeedPct[BASE_ATTACK] = GetCaster()->m_modAttackSpeedPct[BASE_ATTACK];
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f);
ghoul->ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME, val, true); // we want to reduce attack time
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, val);
// Strength + Stamina
for (uint8 i = STAT_STRENGTH; i <= STAT_STAMINA; ++i)
@ -223,20 +223,20 @@ class spell_dk_raise_ally : public SpellScript
value = float(GetCaster()->GetStat(stat)) * mod;
value = ghoul->GetTotalStatValue(stat, value);
ghoul->SetStat(stat, int32(value));
ghoul->ApplyStatBuffMod(stat, value, true);
ghoul->UpdateStatBuffMod(stat);
}
// Attack Power
ghoul->SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
ghoul->SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
// Health
ghoul->SetModifierValue(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
// Power Energy
ghoul->SetModifierValue(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
ghoul->SetStatFlatModifier(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
ghoul->UpdateAllStats();
ghoul->SetFullHealth();

View file

@ -473,11 +473,7 @@ class spell_pal_blessing_of_sanctuary : public AuraScript
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
// xinef: hack
int32 value = 9;
caster->CastCustomSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, &value, &value, 0, true);
}
caster->CastSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, true);
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)

View file

@ -18,6 +18,7 @@
#include "AreaDefines.h"
#include "CreatureScript.h"
#include "Pet.h"
#include "PetDefines.h"
#include "Player.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
@ -25,6 +26,8 @@
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "TemporarySummon.h"
#include "Unit.h"
#include "Util.h"
/*
* Scripts for spells with SPELLFAMILY_WARLOCK and SPELLFAMILY_GENERIC spells used by warlock players.
* Ordered alphabetically using scriptname.
@ -73,6 +76,7 @@ enum WarlockSpells
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
SPELL_WARLOCK_GLYPH_OF_VOIDWALKER = 56247,
};
enum WarlockSpellIcons
@ -292,7 +296,7 @@ class spell_warl_generic_scaling : public AuraScript
void CalculateResistanceAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: pet inherits 40% of resistance from owner and 35% of armor
// pet inherits 40% of resistance from owner and 35% of armor
if (Unit* owner = GetUnitOwner()->GetOwner())
{
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
@ -308,7 +312,7 @@ class spell_warl_generic_scaling : public AuraScript
void CalculateStatAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 75% of stamina and 30% of intellect
// by default warlock pet inherits 75% of stamina and 30% of intellect
if (Unit* owner = GetUnitOwner()->GetOwner())
{
Stats stat = Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
@ -317,21 +321,33 @@ class spell_warl_generic_scaling : public AuraScript
}
}
void CalculateAPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
void CalculateAPAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
if (Unit* owner = GetUnitOwner()->GetOwner())
if (Unit* pet = GetUnitOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 57);
// by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
if (Unit* owner = pet->GetOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 57);
// Glyph of felguard, 99% sure this is a HACK
if (pet->GetEntry() == NPC_FELGUARD)
{
if (AuraEffect* glyph = owner->GetAuraEffect(SPELL_GLYPH_OF_FELGUARD, EFFECT_0))
{
amount += CalculatePct(pet->GetTotalAuraModValue(UNIT_MOD_ATTACK_POWER) - aurEff->GetAmount() + amount, glyph->GetAmount());
}
}
}
}
}
void CalculateSPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
// xinef: by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
// by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
if (Unit* owner = GetUnitOwner()->GetOwner())
{
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
@ -339,7 +355,7 @@ class spell_warl_generic_scaling : public AuraScript
int32 maximum = (fire > shadow) ? fire : shadow;
amount = CalculatePct(std::max<int32>(0, maximum), 15);
// xinef: Update appropriate player field
// Update appropriate player field
if (owner->IsPlayer())
owner->SetUInt32Value(PLAYER_PET_SPELL_POWER, (uint32)amount);
}
@ -1370,81 +1386,27 @@ class spell_warl_shadowburn : public AuraScript
}
};
class spell_warl_glyph_of_felguard : public AuraScript
class spell_warl_voidwalker_pet_passive : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_felguard);
PrepareAuraScript(spell_warl_voidwalker_pet_passive);
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
}
}
}
return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_VOIDWALKER });
}
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
void CalculateAmount(AuraEffect const* /* aurEff */, int32& amount, bool& /*canBeRecalculated*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), false);
}
}
}
if (Unit* pet = GetUnitOwner())
if (pet->IsPet())
if (Unit* owner = pet->ToPet()->GetOwner())
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_VOIDWALKER, EFFECT_0))
amount += aurEff->GetAmount();
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_felguard::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_felguard::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_warl_glyph_of_voidwalker : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_voidwalker);
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_VOIDWALKER)
{
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
}
}
}
}
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_VOIDWALKER)
{
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), false);
}
}
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_voidwalker::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_voidwalker::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_voidwalker_pet_passive::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
}
};
@ -1529,7 +1491,6 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_shadowburn);
RegisterSpellScript(spell_warl_glyph_of_felguard);
RegisterSpellScript(spell_warl_glyph_of_voidwalker);
RegisterSpellScript(spell_warl_voidwalker_pet_passive);
RegisterSpellScript(spell_warl_demonic_pact_aura);
}

View file

@ -1208,8 +1208,7 @@ struct ItemRandomPropertiesEntry
{
uint32 ID; // 0
//char const* InternalName; // 1
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-4
//std::array<uint32, 2> UnusedEnchantment; // 5-6
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-6
std::array<char const*, 16> Name; // 7-22
//uint32 Name_lang_mask; // 23
};
@ -1220,10 +1219,8 @@ struct ItemRandomSuffixEntry
std::array<char const*, 16> Name; // 1-16
//uint32 Name_lang_mask; // 17
//char const* InternalName; // 18
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-21
//std::array<uint32, 2> UnusedEnchantment; // 22-23
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-26
//std::array<uint32, 2> UnusedAllocationPct; // 27-28
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-23
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-28
};
#define MAX_ITEM_SET_ITEMS 10