aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Player/Player.cpp45
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp22
-rw-r--r--src/server/game/Spells/SpellInfo.h2
5 files changed, 43 insertions, 30 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 45d85dbcc89..1d596c017c7 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -20944,45 +20944,45 @@ void Player::SendRemoveControlBar() const
SendDirectMessage(packet.Write());
}
-bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell* spell)
+uint32 Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell const* spell)
{
if (!mod || !spellInfo)
- return false;
+ return 0;
// First time this aura applies a mod to us and is out of charges
- if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
- return false;
+ if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.contains(mod->ownerAura))
+ return 0;
switch (mod->op)
{
case SpellModOp::Duration: // +duration to infinite duration spells making them limited
if (spellInfo->GetDuration() == -1)
- return false;
+ return 0;
break;
case SpellModOp::CritChance: // mod crit to spells that can't crit
if (!spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
- return false;
+ return 0;
break;
case SpellModOp::PointsIndex0: // check if spell has any effect at that index
case SpellModOp::Points:
if (spellInfo->GetEffects().size() <= EFFECT_0)
- return false;
+ return 0;
break;
case SpellModOp::PointsIndex1: // check if spell has any effect at that index
if (spellInfo->GetEffects().size() <= EFFECT_1)
- return false;
+ return 0;
break;
case SpellModOp::PointsIndex2: // check if spell has any effect at that index
if (spellInfo->GetEffects().size() <= EFFECT_2)
- return false;
+ return 0;
break;
case SpellModOp::PointsIndex3: // check if spell has any effect at that index
if (spellInfo->GetEffects().size() <= EFFECT_3)
- return false;
+ return 0;
break;
case SpellModOp::PointsIndex4: // check if spell has any effect at that index
if (spellInfo->GetEffects().size() <= EFFECT_4)
- return false;
+ return 0;
break;
default:
break;
@@ -20999,6 +20999,9 @@ void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell*
*flat = 0;
*pct = 1.0f;
+ if (!spellInfo->IsAffectedBySpellMods())
+ return;
+
auto spellModOpBegin = std::ranges::lower_bound(m_spellMods, op, std::ranges::less(), &SpellModifier::op);
if (spellModOpBegin == m_spellMods.end() || (*spellModOpBegin)->op != op)
return;
@@ -21128,33 +21131,36 @@ void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell*
for (SpellModifier* mod : spellModTypeRange(SPELLMOD_FLAT))
{
- if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ uint32 applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
+ if (!applyCount)
continue;
int32 value = static_cast<SpellModifierByClassMask*>(mod)->value;
if (value == 0)
continue;
- *flat += value;
+ *flat += value * applyCount;
Player::ApplyModToSpell(mod, spell);
}
for (SpellModifier* mod : spellModTypeRange(SPELLMOD_LABEL_FLAT))
{
- if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ uint32 applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
+ if (!applyCount)
continue;
int32 value = static_cast<SpellFlatModifierByLabel*>(mod)->value.ModifierValue;
if (value == 0)
continue;
- *flat += value;
+ *flat += value * applyCount;
Player::ApplyModToSpell(mod, spell);
}
for (SpellModifier* mod : spellModTypeRange(SPELLMOD_PCT))
{
- if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ uint32 applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
+ if (!applyCount)
continue;
// skip percent mods for null basevalue (most important for spell mods with charges)
@@ -21172,13 +21178,14 @@ void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell*
continue;
}
- *pct += CalculatePct(1.0f, value);
+ *pct += std::pow(CalculatePct(1.0f, value), applyCount);
Player::ApplyModToSpell(mod, spell);
}
for (SpellModifier* mod : spellModTypeRange(SPELLMOD_LABEL_PCT))
{
- if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ uint32 applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
+ if (!applyCount)
continue;
// skip percent mods for null basevalue (most important for spell mods with charges)
@@ -21196,7 +21203,7 @@ void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell*
continue;
}
- *pct *= value;
+ *pct *= std::pow(value, applyCount);
Player::ApplyModToSpell(mod, spell);
}
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 668eea417aa..b5033940eba 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1861,7 +1861,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
PlayerSpellMap & GetSpellMap() { return m_spells; }
void AddSpellMod(SpellModifier* mod, bool apply);
- static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell* spell = nullptr);
+ static uint32 IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell const* spell = nullptr);
template <class T>
void GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, T base, int32* flat, float* pct) const;
template <class T>
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 00209b04caf..f08b1e872e1 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1189,7 +1189,7 @@ void AuraEffect::ApplySpellMod(Unit* target, bool apply, AuraEffect const* trigg
// only passive and permament auras-active auras should have amount set on spellcast and not be affected
// if aura is cast by others, it will not be affected
if ((!aura->IsPassive() && !aura->IsPermanent() && !GetSpellInfo()->IsUpdatingTemporaryAuraValuesBySpellMod())
- || aura->GetCasterGUID() != guid || !aura->GetSpellInfo()->IsAffectedBySpellMod(m_spellmod))
+ || aura->GetCasterGUID() != guid || !aura->GetSpellInfo()->IsAffectedBySpellMods() || !aura->GetSpellInfo()->IsAffectedBySpellMod(m_spellmod))
continue;
if (recalculateEffectIndex)
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index ec495532d4e..378c89eee45 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -37,6 +37,7 @@
#include "SpellMgr.h"
#include "Vehicle.h"
#include <G3D/g3dmath.h>
+#include <bit>
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
{
@@ -1839,11 +1840,8 @@ bool SpellInfo::IsAffectedBySpellMods() const
return !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS);
}
-bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
+uint32 SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
{
- if (!IsAffectedBySpellMods())
- return false;
-
SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId, Difficulty);
if (!affectSpell)
return false;
@@ -1852,13 +1850,21 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
{
case SPELLMOD_FLAT:
case SPELLMOD_PCT:
+ {
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
- return affectSpell->SpellFamilyName == SpellFamilyName && static_cast<SpellModifierByClassMask const*>(mod)->mask & SpellFamilyFlags;
+ if (affectSpell->SpellFamilyName != SpellFamilyName)
+ return false;
+
+ // spell modifiers should apply as many times as number of matched SpellFamilyFlags bits (verified with spell 1218116 with modifier 384451 in patch 11.1.0 and client tooltip code since at least 3.3.5)
+ // unknown if this is a bug or strange design choice...
+ FlagsArray<uint32, 4> matched = static_cast<SpellModifierByClassMask const*>(mod)->mask & SpellFamilyFlags;
+ return std::popcount(matched[0]) + std::popcount(matched[1]) + std::popcount(matched[2]) + std::popcount(matched[3]);
+ }
case SPELLMOD_LABEL_FLAT:
- return HasLabel(static_cast<SpellFlatModifierByLabel const*>(mod)->value.LabelID);
+ return HasLabel(static_cast<SpellFlatModifierByLabel const*>(mod)->value.LabelID) ? 1 : 0;
case SPELLMOD_LABEL_PCT:
- return HasLabel(static_cast<SpellPctModifierByLabel const*>(mod)->value.LabelID);
+ return HasLabel(static_cast<SpellPctModifierByLabel const*>(mod)->value.LabelID) ? 1 : 0;
default:
break;
}
@@ -4975,5 +4981,5 @@ bool SpellInfo::MeetsFutureSpellPlayerCondition(Player const* player) const
bool SpellInfo::HasLabel(uint32 labelId) const
{
- return Labels.find(labelId) != Labels.end();
+ return Labels.contains(labelId);
}
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 6eab18b0633..304cdf0c968 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -518,7 +518,7 @@ class TC_GAME_API SpellInfo
bool IsAffected(uint32 familyName, flag128 const& familyFlags) const;
bool IsAffectedBySpellMods() const;
- bool IsAffectedBySpellMod(SpellModifier const* mod) const;
+ uint32 IsAffectedBySpellMod(SpellModifier const* mod) const;
bool IsUpdatingTemporaryAuraValuesBySpellMod() const;
bool CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const;