diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 263436076..2109d1372 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9598,6 +9598,137 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod return spellInfo->IsAffectedBySpellMod(mod); } +template +void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell, bool temporaryPet) +{ + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + { + return; + } + + float totalmul = 1.0f; + int32 totalflat = 0; + + auto calculateSpellMod = [&](SpellModifier* mod) + { + // xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras + if (temporaryPet && mod->charges != 0) + { + return; + } + + if (mod->type == SPELLMOD_FLAT) + { + // xinef: do not allow to consume more than one 100% crit increasing spell + if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100) + { + return; + } + + int32 flatValue = mod->value; + + // SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100) + if (mod->op == SPELLMOD_THREAT) + { + flatValue /= 100; + } + + totalflat += flatValue; + } + else if (mod->type == SPELLMOD_PCT) + { + // skip percent mods for null basevalue (most important for spell mods with charges) + if (basevalue == T(0) || totalmul == 0.0f) + { + return; + } + + // special case (skip > 10sec spell casts for instant cast setting) + if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) + { + return; + } + // xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied + else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) + { + return; + } + // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied + else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) + { + return; + } + + // xinef: those two mods should be multiplicative (Glyph of Renew) + if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) + { + totalmul *= CalculatePct(1.0f, 100.0f + mod->value); + } + else + { + totalmul += CalculatePct(1.0f, mod->value); + } + } + + DropModCharge(mod, spell); + }; + + // Drop charges for triggering spells instead of triggered ones + if (m_spellModTakingSpell) + { + spell = m_spellModTakingSpell; + } + + SpellModifier* chargedMod = nullptr; + for (auto mod : m_spellMods[op]) + { + // Charges can be set only for mods with auras + if (!mod->ownerAura) + { + ASSERT(!mod->charges); + } + + if (!IsAffectedBySpellmod(spellInfo, mod, spell)) + { + continue; + } + + if (mod->ownerAura->IsUsingCharges()) + { + if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority)) + { + chargedMod = mod; + } + + continue; + } + + calculateSpellMod(mod); + } + + if (chargedMod) + { + calculateSpellMod(chargedMod); + } + + float diff = 0.0f; + if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION) + { + diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat; + } + else + { + diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat; + } + + basevalue = T((float)basevalue + diff); +} + +template AC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, int32& basevalue, Spell* spell, bool temporaryPet); +template AC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, uint32& basevalue, Spell* spell, bool temporaryPet); +template AC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, float& basevalue, Spell* spell, bool temporaryPet); + // Binary predicate for sorting SpellModifiers class SpellModPred { @@ -9765,6 +9896,13 @@ void Player::RemoveSpellMods(Spell* spell) SpellModifier* mod = *itr; ++itr; + // don't handle spells with proc_event entry defined + // this is a temporary workaround, because all spellmods should be handled like that + if (sSpellMgr->GetSpellProcEvent(mod->spellId)) + { + continue; + } + // spellmods without aura set cannot be charged if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges()) continue; @@ -9800,11 +9938,6 @@ void Player::RemoveSpellMods(Spell* spell) void Player::DropModCharge(SpellModifier* mod, Spell* spell) { - // don't handle spells with proc_event entry defined - // this is a temporary workaround, because all spellmods should be handled like that - if (sSpellMgr->GetSpellProcEvent(mod->spellId)) - return; - if (spell && mod->ownerAura && mod->charges > 0) { if (--mod->charges == 0) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e68e4b1c5..2951bb669 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1732,7 +1732,8 @@ public: void AddSpellMod(SpellModifier* mod, bool apply); bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); bool HasSpellMod(SpellModifier* mod, Spell* spell); - template T ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr, bool temporaryPet = false); + template + void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr, bool temporaryPet = false); void RemoveSpellMods(Spell* spell); void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr); void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr); @@ -2941,131 +2942,4 @@ private: void AddItemsSetItem(Player* player, Item* item); void RemoveItemsSetItem(Player* player, ItemTemplate const* proto); -// "the bodies of template functions must be made available in a header file" -template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell, bool temporaryPet) -{ - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) - { - return 0; - } - - float totalmul = 1.0f; - int32 totalflat = 0; - - auto calculateSpellMod = [&](SpellModifier* mod) - { - // xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras - if (temporaryPet && mod->charges != 0) - { - return; - } - - if (mod->type == SPELLMOD_FLAT) - { - // xinef: do not allow to consume more than one 100% crit increasing spell - if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100) - { - return; - } - - int32 flatValue = mod->value; - - // SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100) - if (mod->op == SPELLMOD_THREAT) - { - flatValue /= 100; - } - - totalflat += flatValue; - } - else if (mod->type == SPELLMOD_PCT) - { - // skip percent mods for null basevalue (most important for spell mods with charges) - if (basevalue == T(0) || totalmul == 0.0f) - { - return; - } - - // special case (skip > 10sec spell casts for instant cast setting) - if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100) - { - return; - } - // xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied - else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell)) - { - return; - } - // xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied - else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell)) - { - return; - } - - // xinef: those two mods should be multiplicative (Glyph of Renew) - if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT) - { - totalmul *= CalculatePct(1.0f, 100.0f + mod->value); - } - else - { - totalmul += CalculatePct(1.0f, mod->value); - } - } - - DropModCharge(mod, spell); - }; - - // Drop charges for triggering spells instead of triggered ones - if (m_spellModTakingSpell) - { - spell = m_spellModTakingSpell; - } - - SpellModifier* chargedMod = nullptr; - for (auto mod : m_spellMods[op]) - { - // Charges can be set only for mods with auras - if (!mod->ownerAura) - { - ASSERT(!mod->charges); - } - - if (!IsAffectedBySpellmod(spellInfo, mod, spell)) - { - continue; - } - - if (mod->ownerAura->IsUsingCharges()) - { - if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority)) - { - chargedMod = mod; - } - - continue; - } - - calculateSpellMod(mod); - } - - if (chargedMod) - { - calculateSpellMod(chargedMod); - } - - float diff = 0.0f; - if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION) - { - diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat; - } - else - { - diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat; - } - - basevalue = T((float)basevalue + diff); - return T(diff); -} #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 59624677f..b9e004722 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -16590,18 +16590,14 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u case SPELL_AURA_ADD_FLAT_MODIFIER: case SPELL_AURA_ADD_PCT_MODIFIER: { - if (SpellModifier* mod = triggeredByAura->GetSpellModifier()) + if (triggeredByAura->GetSpellModifier()) { - if (mod->op == SPELLMOD_CASTING_TIME && mod->value < 0 && procSpell) + // Do proc if mod is consumed by spell + if (!procSpell || procSpell->m_appliedMods.find(i->aura) != procSpell->m_appliedMods.end()) { - // Skip instant spells - if (procSpellInfo->CalcCastTime() <= 0 || (procSpell->GetTriggeredCastFlags() & TRIGGERED_CAST_DIRECTLY) != 0) - { - break; - } + takeCharges = true; } } - takeCharges = true; break; } default: