diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index e9a722fd14..5f83c58f8e 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -679,7 +679,7 @@ void ThreatManager::ProcessAIUpdates() threat *= threatEntry->pctMod; if (Player* modOwner = victim->GetSpellModOwner()) - modOwner->ApplySpellMod(spell->Id, SpellModOp::Hate, threat); + modOwner->ApplySpellMod(spell, SpellModOp::Hate, threat); } // modifiers by effect school diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 72d205c2c0..5a009a6c16 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2449,17 +2449,19 @@ float WorldObject::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effec { if (Player* modOwner = GetSpellModOwner()) { - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::Points, value); + modOwner->ApplySpellMod(spellProto, SpellModOp::Points, value); switch (effect_index) { case EFFECT_0: - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::PointsIndex0, value); + modOwner->ApplySpellMod(spellProto, SpellModOp::PointsIndex0, value); break; case EFFECT_1: - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::PointsIndex1, value); + modOwner->ApplySpellMod(spellProto, SpellModOp::PointsIndex1, value); break; case EFFECT_2: - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::PointsIndex2, value); + modOwner->ApplySpellMod(spellProto, SpellModOp::PointsIndex2, value); + break; + default: break; } } @@ -2556,12 +2558,14 @@ void WorldObject::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime, // called from caster if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::ChangeCastTime, castTime, spell); + modOwner->ApplySpellMod(spellInfo, SpellModOp::ChangeCastTime, castTime, spell); Unit const* unitCaster = ToUnit(); if (!unitCaster) return; + if (unitCaster->IsPlayer() && unitCaster->ToPlayer()->GetCommandStatus(CHEAT_CASTTIME)) + castTime = 0; if (!(spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY) || spellInfo->HasAttribute(SPELL_ATTR0_IS_TRADESKILL) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS)) && ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT)) castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED)); @@ -2625,7 +2629,7 @@ SpellMissInfo WorldObject::MagicSpellHitResult(Unit* victim, SpellInfo const* sp // Spellmod from SpellModOp::HitChance if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::HitChance, modHitChance); + modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, modHitChance); // Spells with SPELL_ATTR3_ALWAYS_HIT will ignore target's avoidance effects if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT)) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1053c01d4b..60288232f6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -116,6 +116,7 @@ #include "WorldSession.h" #include "WorldStateMgr.h" #include "WorldStatePackets.h" +#include #include // corpse reclaim times @@ -7973,7 +7974,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT } // Apply spell mods - ApplySpellMod(pEnchant->EffectArg[s], SpellModOp::ProcChance, chance); + ApplySpellMod(spellInfo, SpellModOp::ProcChance, chance); // Shiv has 100% chance to apply the poison if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT) @@ -20728,7 +20729,7 @@ void Player::SendRemoveControlBar() const SendDirectMessage(&data); } -bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell) +bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell* spell) { if (!mod || !spellInfo) return false; @@ -20737,38 +20738,99 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura)) return false; - // +duration to infinite duration spells making them limited - if (mod->op == SpellModOp::Duration && spellInfo->GetDuration() == -1) - return false; + switch (mod->op) + { + case SpellModOp::Duration: // +duration to infinite duration spells making them limited + if (spellInfo->GetDuration() == -1) + return false; + break; + case SpellModOp::CritChance: // mod crit to spells that can't crit + if (!spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT)) + return false; + break; + case SpellModOp::PointsIndex0: // check if spell has any effect at that index + case SpellModOp::Points: + if (!spellInfo->Effects[EFFECT_0].IsEffect()) + return false; + break; + case SpellModOp::PointsIndex1: // check if spell has any effect at that index + if (!spellInfo->Effects[EFFECT_1].IsEffect()) + return false; + break; + case SpellModOp::PointsIndex2: // check if spell has any effect at that index + if (!spellInfo->Effects[EFFECT_2].IsEffect()) + return false; + break; + default: + break; + } return spellInfo->IsAffectedBySpellMod(mod); } template -void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/) const +void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, T base, int32* flat, float* pct) const { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) + ASSERT(flat && pct); + + *flat = 0; + *pct = 1.0f; + + auto spellModOpBegin = std::ranges::lower_bound(m_spellMods, op, std::ranges::less(), &SpellModifier::op); + if (spellModOpBegin == m_spellMods.end() || (*spellModOpBegin)->op != op) return; - float totalmul = 1.0f; - int32 totalflat = 0; // Drop charges for triggering spells instead of triggered ones if (m_spellModTakingSpell) spell = m_spellModTakingSpell; + auto spellModTypeBegin = [&](SpellModType type) + { + auto typeBegin = spellModOpBegin; + auto end = m_spellMods.end(); + while (typeBegin != end && (*typeBegin)->op == op) + { + if ((*typeBegin)->type == type) + return typeBegin; + + ++typeBegin; + } + + return end; + }; + + // end of our iterable range will be when we reach a spellmod with different op or type than expected + // we can do this because m_spellMods is sorted by op and type + auto spellModTypeEnd = [&](SpellModType type) + { + struct EndSentinel + { + bool operator==(std::vector::const_iterator const& itr) const + { + return itr == end || (*itr)->op != op || (*itr)->type != type; + } + + std::vector::const_iterator end; + SpellModOp op; + SpellModType type; + }; + return EndSentinel{ .end = m_spellMods.end(), .op = op, .type = type }; + }; + + auto spellModTypeRange = [&](SpellModType type) { return Trinity::IteratorPair(spellModTypeBegin(type), spellModTypeEnd(type)); }; + switch (op) { // special case, if a mod makes spell instant, only consume that mod case SpellModOp::ChangeCastTime: { SpellModifier* modInstantSpell = nullptr; - for (SpellModifier* mod : m_spellMods[AsUnderlyingType(op)][SPELLMOD_PCT]) + for (SpellModifier* mod : spellModTypeRange(SPELLMOD_PCT)) { if (!IsAffectedBySpellmod(spellInfo, mod, spell)) continue; - if (mod->type == SPELLMOD_PCT && basevalue < T(10000) && mod->value <= -100) + if (base < T(10000) && static_cast(mod)->value <= -100) { modInstantSpell = mod; break; @@ -20778,7 +20840,7 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s if (modInstantSpell) { Player::ApplyModToSpell(modInstantSpell, spell); - basevalue = T(0); + *pct = 0.0f; return; } break; @@ -20787,12 +20849,12 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s case SpellModOp::CritChance: { SpellModifier* modCritical = nullptr; - for (SpellModifier* mod : m_spellMods[AsUnderlyingType(op)][SPELLMOD_FLAT]) + for (SpellModifier* mod : spellModTypeRange(SPELLMOD_FLAT)) { if (!IsAffectedBySpellmod(spellInfo, mod, spell)) continue; - if (mod->type == SPELLMOD_FLAT && mod->value >= 100) + if (static_cast(mod)->value >= 100) { modCritical = mod; break; @@ -20802,7 +20864,7 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s if (modCritical) { Player::ApplyModToSpell(modCritical, spell); - basevalue = T(100); + *flat = 100; return; } break; @@ -20811,44 +20873,64 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s break; } - for (SpellModifier* mod : m_spellMods[AsUnderlyingType(op)][SPELLMOD_FLAT]) + for (SpellModifier* mod : spellModTypeRange(SPELLMOD_FLAT)) { if (!IsAffectedBySpellmod(spellInfo, mod, spell)) continue; - if (mod->value == 0) + int32 value = static_cast(mod)->value; + if (value == 0) continue; - totalflat += mod->value; + *flat += value; Player::ApplyModToSpell(mod, spell); } - for (SpellModifier* mod : m_spellMods[AsUnderlyingType(op)][SPELLMOD_PCT]) + for (SpellModifier* mod : spellModTypeRange(SPELLMOD_PCT)) { if (!IsAffectedBySpellmod(spellInfo, mod, spell)) continue; // skip percent mods for null basevalue (most important for spell mods with charges) - if (basevalue + totalflat == T(0)) + if (base + *flat == T(0)) continue; - if (mod->value == 0) + int32 value = static_cast(mod)->value; + if (value == 0) continue; // special case (skip > 10sec spell casts for instant cast setting) - if (mod->op == SpellModOp::ChangeCastTime && basevalue >= T(10000) && mod->value <= -100) - continue; + if (op == SpellModOp::ChangeCastTime) + { + if (base >= T(10000) && value <= -100) + continue; + } - totalmul *= 1.0f + CalculatePct(1.0f, mod->value); + *pct += CalculatePct(1.0f, value); Player::ApplyModToSpell(mod, spell); } - - basevalue = T(float(basevalue + totalflat) * totalmul); } -template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, int32& basevalue, Spell* spell) const; -template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, uint32& basevalue, Spell* spell) const; -template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, float& basevalue, Spell* spell) const; +template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, int32 base, int32* flat, float* pct) const; +template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, uint32 base, int32* flat, float* pct) const; +template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, float base, int32* flat, float* pct) const; +template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, double base, int32* flat, float* pct) const; + +template +void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/) const +{ + float totalmul = 1.0f; + int32 totalflat = 0; + + GetSpellModValues(spellInfo, op, spell, basevalue, &totalflat, &totalmul); + + basevalue = T(double(basevalue + totalflat) * totalmul); +} + +template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, int32& basevalue, Spell* spell) const; +template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, uint32& basevalue, Spell* spell) const; +template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, float& basevalue, Spell* spell) const; +template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, double& basevalue, Spell* spell) const; void Player::AddSpellMod(SpellModifier* mod, bool apply) { @@ -20856,43 +20938,69 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) /// First, manipulate our spellmodifier container if (apply) - m_spellMods[AsUnderlyingType(mod->op)][mod->type].insert(mod); + m_spellMods.insert(mod); else - m_spellMods[AsUnderlyingType(mod->op)][mod->type].erase(mod); + m_spellMods.erase(mod); /// Now, send spellmodifier packet - if (!IsLoading()) + switch (mod->type) { - OpcodeServer opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; - - WorldPackets::Spells::SetSpellModifier packet(opcode); - - /// @todo Implement sending of bulk modifiers instead of single - packet.Modifiers.resize(1); - WorldPackets::Spells::SpellModifier& spellMod = packet.Modifiers[0]; - - spellMod.ModIndex = AsUnderlyingType(mod->op); - - for (uint8 eff = 0; eff < 96; ++eff) - { - flag96 mask; - mask[eff / 32] = 1u << (eff % 32); - if (mod->mask & mask) + case SPELLMOD_FLAT: + case SPELLMOD_PCT: + if (!IsLoading()) { - WorldPackets::Spells::SpellModifierData modData; + OpcodeServer opcode = (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; - modData.ModifierValue = 0.0f; - for (SpellModifier* spellMod : m_spellMods[AsUnderlyingType(mod->op)][AsUnderlyingType(mod->type)]) - if (spellMod->mask & mask) - modData.ModifierValue += spellMod->value; + WorldPackets::Spells::SetSpellModifier packet(opcode); - modData.ClassIndex = eff; + /// @todo Implement sending of bulk modifiers instead of single + packet.Modifiers.resize(1); + WorldPackets::Spells::SpellModifier& spellModifier = packet.Modifiers[0]; - spellMod.ModifierData.push_back(modData); + spellModifier.ModIndex = AsUnderlyingType(mod->op); + + boost::dynamic_bitset mask; + mask.resize(96); + + boost::from_block_range( + &static_cast(mod)->mask[0], + &static_cast(mod)->mask[0] + 3, + mask); + + for (std::size_t classIndex = mask.find_first(); classIndex != decltype(mask)::npos; classIndex = mask.find_next(classIndex)) + { + WorldPackets::Spells::SpellModifierData& modData = spellModifier.ModifierData.emplace_back(); + if (mod->type == SPELLMOD_FLAT) + { + modData.ModifierValue = 0; + auto itr = std::ranges::lower_bound(m_spellMods, std::make_pair(mod->op, SPELLMOD_FLAT), std::ranges::less(), [](SpellModifier const* sm) { return std::make_pair(sm->op, sm->type); }); + while (itr != m_spellMods.end() && (*itr)->op == mod->op && (*itr)->type == SPELLMOD_FLAT) + { + SpellModifierByClassMask const* spellMod = static_cast(*itr++); + if (spellMod->mask[classIndex / 32] & (1u << (classIndex % 32))) + modData.ModifierValue += spellMod->value; + } + } + else + { + modData.ModifierValue = 0; + auto itr = std::ranges::lower_bound(m_spellMods, std::make_pair(mod->op, SPELLMOD_PCT), std::ranges::less(), [](SpellModifier const* sm) { return std::make_pair(sm->op, sm->type); }); + while (itr != m_spellMods.end() && (*itr)->op == mod->op && (*itr)->type == SPELLMOD_PCT) + { + SpellModifierByClassMask const* spellMod = static_cast(*itr++); + if (spellMod->mask[classIndex / 32] & (1u << (classIndex % 32))) + modData.ModifierValue += spellMod->value; + } + } + + modData.ClassIndex = classIndex; + } + + SendDirectMessage(packet.Write()); } - } - - SendDirectMessage(packet.Write()); + break; + default: + break; } } @@ -20922,46 +21030,63 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply) void Player::SendSpellModifiers() const { + auto getOrCreateModifierData = [](std::vector& datas, uint8 classIndex, float defaultValue) -> float& + { + auto itr = std::ranges::find(datas, classIndex, &WorldPackets::Spells::SpellModifierData::ClassIndex); + if (itr != datas.end()) + return itr->ModifierValue; + + WorldPackets::Spells::SpellModifierData& data = datas.emplace_back(); + data.ModifierValue = defaultValue; + data.ClassIndex = classIndex; + return data.ModifierValue; + }; + + boost::dynamic_bitset mask; + mask.resize(96); + WorldPackets::Spells::SetSpellModifier flatMods(SMSG_SET_FLAT_SPELL_MODIFIER); WorldPackets::Spells::SetSpellModifier pctMods(SMSG_SET_PCT_SPELL_MODIFIER); - for (uint8 i = 0; i < MAX_SPELLMOD; ++i) + + WorldPackets::Spells::SpellModifier* flatModifier = nullptr; + WorldPackets::Spells::SpellModifier* pctModifier = nullptr; + + for (SpellModifier const* mod : m_spellMods) { - WorldPackets::Spells::SpellModifier flatMod; - flatMod.ModifierData.resize(96); - WorldPackets::Spells::SpellModifier pctMod; - pctMod.ModifierData.resize(96); - flatMod.ModIndex = pctMod.ModIndex = i; - for (uint8 j = 0; j < 96; ++j) + if (mod->type != SPELLMOD_FLAT && mod->type != SPELLMOD_PCT) + continue; + + switch (mod->type) { - flag96 mask; - mask[j / 32] = 1u << (j % 32); - - flatMod.ModifierData[j].ClassIndex = j; - flatMod.ModifierData[j].ModifierValue = 0.0f; - pctMod.ModifierData[j].ClassIndex = j; - pctMod.ModifierData[j].ModifierValue = 1.0f; - - for (SpellModifier* mod : m_spellMods[i][SPELLMOD_FLAT]) - if (mod->mask & mask) - flatMod.ModifierData[j].ModifierValue += mod->value; - - for (SpellModifier* mod : m_spellMods[i][SPELLMOD_PCT]) - if (mod->mask & mask) - pctMod.ModifierData[j].ModifierValue *= 1.0f + CalculatePct(1.0f, mod->value); + case SPELLMOD_FLAT: + if (!flatModifier || flatModifier->ModIndex != uint8(mod->op)) + { + flatModifier = &flatMods.Modifiers.emplace_back(); + flatModifier->ModIndex = uint8(mod->op); + } + boost::from_block_range(&static_cast(mod)->mask[0], &static_cast(mod)->mask[0] + 3, mask); + for (std::size_t classIndex = mask.find_first(); classIndex != decltype(mask)::npos; classIndex = mask.find_next(classIndex)) + { + float& modifierValue = getOrCreateModifierData(flatModifier->ModifierData, classIndex, 0); + modifierValue += static_cast(mod)->value; + } + break; + case SPELLMOD_PCT: + if (!pctModifier || pctModifier->ModIndex != uint8(mod->op)) + { + pctModifier = &pctMods.Modifiers.emplace_back(); + pctModifier->ModIndex = uint8(mod->op); + } + boost::from_block_range(&static_cast(mod)->mask[0], &static_cast(mod)->mask[0] + 3, mask); + for (std::size_t classIndex = mask.find_first(); classIndex != decltype(mask)::npos; classIndex = mask.find_next(classIndex)) + { + float& modifierValue = getOrCreateModifierData(pctModifier->ModifierData, classIndex, 0); + modifierValue += static_cast(mod)->value; + } + break; + default: + break; } - - flatMod.ModifierData.erase(std::remove_if(flatMod.ModifierData.begin(), flatMod.ModifierData.end(), [](WorldPackets::Spells::SpellModifierData const& mod) - { - return G3D::fuzzyEq(mod.ModifierValue, 0.0f); - }), flatMod.ModifierData.end()); - - pctMod.ModifierData.erase(std::remove_if(pctMod.ModifierData.begin(), pctMod.ModifierData.end(), [](WorldPackets::Spells::SpellModifierData const& mod) - { - return G3D::fuzzyEq(mod.ModifierValue, 1.0f); - }), pctMod.ModifierData.end()); - - flatMods.Modifiers.emplace_back(std::move(flatMod)); - pctMods.Modifiers.emplace_back(std::move(pctMod)); } if (!flatMods.Modifiers.empty()) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 311078d8d7..f45a49e733 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -185,18 +185,41 @@ uint32 const ArmorSpecializationIds[MAX_ARMOR_SPECIALIZATION_IDS] = { 86530, 865 // Spell modifier (used for modify other spells) struct SpellModifier { - SpellModifier(Aura* _ownerAura) : op(SpellModOp::HealingAndDamage), type(SPELLMOD_FLAT), value(0), mask(), spellId(0), ownerAura(_ownerAura) { } + SpellModifier(Aura* _ownerAura) : op(SpellModOp::HealingAndDamage), type(SPELLMOD_FLAT), spellId(0), ownerAura(_ownerAura) { } virtual ~SpellModifier() = default; SpellModOp op; SpellModType type; - int32 value; - flag96 mask; uint32 spellId; Aura* const ownerAura; }; +struct SpellModifierByClassMask : SpellModifier +{ + SpellModifierByClassMask(Aura* _ownerAura) : SpellModifier(_ownerAura), value(0), mask() { } + + int32 value; + flag96 mask; +}; + +struct SpellModifierCompare +{ + bool operator()(SpellModifier const* left, SpellModifier const* right) const + { + // first sort by SpellModOp + if (left->op != right->op) + return left->op < right->op; + + // then by type (flat/pct) + if (left->type != right->type) + return left->type < right->type; + + return left < right; + } +}; + + enum PlayerCurrencyState { PLAYERCURRENCY_UNCHANGED = 0, @@ -218,7 +241,7 @@ struct PlayerCurrency typedef std::unordered_map PlayerTalentMap; typedef std::unordered_map PlayerSpellMap; -typedef std::unordered_set SpellModContainer; +typedef Trinity::Containers::FlatSet SpellModContainer; typedef std::unordered_map PlayerCurrenciesMap; typedef std::unordered_map InstanceTimeMap; @@ -1649,9 +1672,11 @@ class TC_GAME_API Player : public Unit, public GridObject PlayerSpellMap & GetSpellMap() { return m_spells; } void AddSpellMod(SpellModifier* mod, bool apply); - static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr); + static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell* spell = nullptr); template - void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr) const; + void GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, T base, int32* flat, float* pct) const; + template + void ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, T& basevalue, Spell* spell = nullptr) const; static void ApplyModToSpell(SpellModifier* mod, Spell* spell); void SetSpellModTakingSpell(Spell* spell, bool apply); void SendSpellModifiers() const; @@ -2592,7 +2617,7 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 m_baseHealthRegen; int32 m_spellPenetrationItemMod; - SpellModContainer m_spellMods[MAX_SPELLMOD][SPELLMOD_END]; + SpellModContainer m_spellMods; EnchantDurationList m_enchantDuration; ItemDurationList m_itemDuration; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index cbdcacb03e..9fbe2e8699 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1043,7 +1043,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama uint32 crit_bonus = damage; // Apply crit_damage bonus for melee spells if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::CritDamageAndHealing, crit_bonus); + modOwner->ApplySpellMod(spellInfo, SpellModOp::CritDamageAndHealing, crit_bonus); damage += crit_bonus; // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE @@ -1527,7 +1527,7 @@ static float GetArmorReduction(float armor, uint8 attackerLevel) if (spellInfo) if (Player* modOwner = attacker->GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::TargetResistance, armor); + modOwner->ApplySpellMod(spellInfo, SpellModOp::TargetResistance, armor); for (AuraEffect const* aurEff : attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST)) { @@ -6394,7 +6394,7 @@ int32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, int3 if (Player* modOwner = GetSpellModOwner()) { spellPowerCoeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::BonusCoefficient, spellPowerCoeff); + modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, spellPowerCoeff); spellPowerCoeff /= 100.0f; } @@ -6406,7 +6406,7 @@ int32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, int3 // apply spellmod to Done damage (flat and pct) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage); + modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage); return int32(std::max(tmpDamage, 0.0f)); } @@ -6762,7 +6762,7 @@ float Unit::SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask scho // percent done // only players use intelligence for critical chance computations if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::CritChance, crit_chance); + modOwner->ApplySpellMod(spellInfo, SpellModOp::CritChance, crit_chance); return std::max(crit_chance, 0.0f); } @@ -7003,7 +7003,7 @@ float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, { // adds additional damage to critBonus (from talents) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::CritDamageAndHealing, crit_bonus); + modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus); } crit_bonus += damage; @@ -7102,7 +7102,7 @@ int32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::BonusCoefficient, coeff); + modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff); coeff /= 100.0f; } @@ -7133,7 +7133,7 @@ int32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int // apply spellmod to Done amount if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal); + modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal); return int32(std::max(heal, 0.0f)); } @@ -7665,7 +7665,7 @@ int32 Unit::MeleeDamageBonusDone(Unit* victim, int32 damage, WeaponAttackType at // apply spellmod to Done damage if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF); + modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF); // bonus result can be negative return int32(std::max(damageF, 0.0f)); @@ -7848,7 +7848,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spe // Apply chance modifer aura if (spellProto) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SpellModOp::ProcFrequency, PPM); + modOwner->ApplySpellMod(spellProto, SpellModOp::ProcFrequency, PPM); return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } @@ -12109,7 +12109,7 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, S float resistMissChance = 100.0f; if (spellInfo) if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::HitChance, resistMissChance); + modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, resistMissChance); missChance -= resistMissChance - 100.0f; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 64b74bfde3..39b2049f4a 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -39,6 +39,7 @@ #include "Spell.h" #include "SpellHistory.h" #include "SpellMgr.h" +#include "SpellScript.h" #include "ThreatManager.h" #include "Unit.h" #include "Util.h" @@ -716,19 +717,46 @@ void AuraEffect::CalculateSpellMod() case SPELL_AURA_ADD_PCT_MODIFIER: if (!m_spellmod) { - m_spellmod = new SpellModifier(GetBase()); - m_spellmod->op = SpellModOp(GetMiscValue()); + SpellModifierByClassMask* spellmod = new SpellModifierByClassMask(GetBase()); + spellmod->op = SpellModOp(GetMiscValue()); - m_spellmod->type = GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER ? SPELLMOD_PCT : SPELLMOD_FLAT; - m_spellmod->spellId = GetId(); - m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; + spellmod->type = GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER ? SPELLMOD_PCT : SPELLMOD_FLAT; + spellmod->spellId = GetId(); + spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; + m_spellmod = spellmod; } - m_spellmod->value = GetAmount(); + static_cast(m_spellmod)->value = GetAmount(); break; default: break; } GetBase()->CallScriptEffectCalcSpellModHandlers(this, m_spellmod); + + // validate modifier + if (m_spellmod) + { + bool isValid = true; + auto logErrors = [&] { return std::ranges::any_of(GetBase()->m_loadedScripts, [](AuraScript const* script) { return script->DoEffectCalcSpellMod.size() > 0; }); }; + if (AsUnderlyingType(m_spellmod->op) >= MAX_SPELLMOD) + { + isValid = false; + if (logErrors()) + TC_LOG_ERROR("spells.aura.effect", "Aura script for spell id {} created invalid spell modifier op {}", GetId(), AsUnderlyingType(m_spellmod->op)); + } + + if (m_spellmod->type >= SPELLMOD_END) + { + isValid = false; + if (logErrors()) + TC_LOG_ERROR("spells.aura.effect", "Aura script for spell id {} created invalid spell modifier type {}", GetId(), AsUnderlyingType(m_spellmod->type)); + } + + if (!isValid) + { + delete m_spellmod; + m_spellmod = nullptr; + } + } } void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply) diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index ed34562aee..e29d74e969 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -894,7 +894,7 @@ void Aura::SetDuration(int32 duration, bool withMods) if (withMods) if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SpellModOp::Duration, duration); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Duration, duration); m_duration = duration; SetNeedClientUpdateForTargets(); @@ -960,7 +960,7 @@ uint8 Aura::CalcMaxCharges(Unit* caster) const if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SpellModOp::ProcCharges, maxProcCharges); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ProcCharges, maxProcCharges); return uint8(maxProcCharges); } @@ -1182,7 +1182,7 @@ int32 Aura::CalcDispelChance(Unit const* auraTarget, bool offensive) const // Apply dispel mod from aura caster if (Unit* caster = GetCaster()) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SpellModOp::DispelResistance, resistChance); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::DispelResistance, resistChance); // Dispel resistance from target SPELL_AURA_MOD_DISPEL_RESIST // Only affects offensive dispels @@ -1966,7 +1966,7 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event } // apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SpellModOp::ProcChance, chance); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ProcChance, chance); } // proc chance is reduced by an additional 3.333% per level past 60 diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 7153c0787d..12e7c17805 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1754,7 +1754,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg { uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::ChainTargets, maxTargets, this); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainTargets, maxTargets, this); if (maxTargets > 1) { @@ -3225,7 +3225,7 @@ bool Spell::UpdateChanneledTargetList() { range = m_spellInfo->GetMaxRange(IsPositive()); if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::Range, range, this); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, range, this); // add little tolerance level range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE @@ -5241,7 +5241,7 @@ void Spell::TakePower() { //lower spell cost on fail (by talent aura) if (Player* modOwner = unitCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::PowerCostOnMiss, m_powerCost); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCostOnMiss, m_powerCost); } } } @@ -5307,7 +5307,7 @@ SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) const { runeCost[i] = src->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::PowerCost0, runeCost[i], const_cast(this)); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runeCost[i], const_cast(this)); } runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later @@ -5349,7 +5349,7 @@ void Spell::TakeRunePower(SpellMissInfo hitInfo) { runeCost[i] = runeCostData->RuneCost[i]; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::PowerCost0, runeCost[i], const_cast(this)); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runeCost[i], const_cast(this)); } bool consumeRunes = false; @@ -5432,7 +5432,7 @@ void Spell::TakeRunePower(SpellMissInfo hitInfo) // Apply runic power gain modifiers if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::PowerCost0, runicPowerGain, const_cast(this)); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runicPowerGain, const_cast(this)); player->ModifyPower(POWER_RUNIC_POWER, std::max(0, runicPowerGain)); } @@ -5568,7 +5568,7 @@ void Spell::HandleHolyPower(Player* caster) // The spell did hit the target, apply aura cost mods if there are any. if (hit) { - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::PowerCost0, m_powerCost, this); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, m_powerCost, this); caster->ModifyPower(POWER_HOLY_POWER, -m_powerCost); } } @@ -7032,7 +7032,7 @@ std::pair Spell::GetMinMaxRange(bool strict) const maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f; if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::Range, maxRange, const_cast(this)); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, maxRange, const_cast(this)); maxRange += rangeMod; @@ -7599,7 +7599,7 @@ void Spell::Delayed() // only called in DealDamage() int32 delayReduce = 100; // must be initialized to 100 for percent modifiers if (Player* player = unitCaster->GetSpellModOwner()) - player->ApplySpellMod(m_spellInfo->Id, SpellModOp::ResistPushback, delayReduce, this); + player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this); delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -7640,7 +7640,7 @@ void Spell::DelayedChannel() int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit int32 delayReduce = 100; // must be initialized to 100 for percent modifiers if (Player* player = playerCaster->GetSpellModOwner()) - player->ApplySpellMod(m_spellInfo->Id, SpellModOp::ResistPushback, delayReduce, this); + player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this); delayReduce += playerCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100; if (delayReduce >= 100) return; @@ -8641,7 +8641,7 @@ void Spell::TriggerGlobalCooldown() // gcd modifier auras are applied only to own spells and only players have such mods if (Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::StartCooldown, gcd, this); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::StartCooldown, gcd, this); // Apply haste rating if (m_spellInfo->StartRecoveryCategory == 133 && m_spellInfo->StartRecoveryTime == 1500 && diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c63c9ee16c..ed99978beb 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1957,7 +1957,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) int32 duration = m_spellInfo->GetDuration(); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SpellModOp::Duration, duration); + modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Duration, duration); SummonCreatureExtraArgs extraArgs; extraArgs.SummonProperties = properties; diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index 61ee3ad4d8..1e64f92840 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -298,10 +298,10 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel if (Player* modOwner = _owner->GetSpellModOwner()) { if (cooldown >= 0) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::Cooldown, cooldown, spell); + modOwner->ApplySpellMod(spellInfo, SpellModOp::Cooldown, cooldown, spell); if (categoryCooldown >= 0 && !spellInfo->HasAttribute(SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS)) - modOwner->ApplySpellMod(spellInfo->Id, SpellModOp::Cooldown, categoryCooldown, spell); + modOwner->ApplySpellMod(spellInfo, SpellModOp::Cooldown, categoryCooldown, spell); } if (_owner->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE, spellInfo)) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 54461c018d..48db736090 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -609,7 +609,7 @@ float SpellEffectInfo::CalcValueMultiplier(WorldObject* caster, Spell* spell) co { float multiplier = Amplitude; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, SpellModOp::Amplitude, multiplier, spell); + modOwner->ApplySpellMod(_spellInfo, SpellModOp::Amplitude, multiplier, spell); return multiplier; } @@ -617,7 +617,7 @@ float SpellEffectInfo::CalcDamageMultiplier(WorldObject* caster, Spell* spell) c { float multiplierPercent = DamageMultiplier * 100.0f; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : nullptr)) - modOwner->ApplySpellMod(_spellInfo->Id, SpellModOp::ChainAmplitude, multiplierPercent, spell); + modOwner->ApplySpellMod(_spellInfo, SpellModOp::ChainAmplitude, multiplierPercent, spell); return multiplierPercent / 100.0f; } @@ -669,7 +669,7 @@ float SpellEffectInfo::CalcRadius(WorldObject* caster /*= nullptr*/, SpellTarget radius = std::min(radius, entry->RadiusMax); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(_spellInfo->Id, SpellModOp::Radius, radius, spell); + modOwner->ApplySpellMod(_spellInfo, SpellModOp::Radius, radius, spell); } return radius; @@ -1571,9 +1571,18 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const if (!affectSpell) return false; - // 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 && mod->mask & SpellFamilyFlags; + switch (mod->type) + { + 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(mod)->mask & SpellFamilyFlags; + default: + break; + } + + return false; } bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const @@ -3411,7 +3420,7 @@ float SpellInfo::GetMaxRange(bool positive, WorldObject* caster, Spell* spell) c range = RangeEntry->RangeMax[0]; if (caster) if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SpellModOp::Range, range, spell); + modOwner->ApplySpellMod(this, SpellModOp::Range, range, spell); return range; } @@ -3476,7 +3485,7 @@ int32 SpellInfo::CalcDuration(WorldObject const* caster /*= nullptr*/) const } if (Player const* modOwner = unitCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SpellModOp::Duration, duration); + modOwner->ApplySpellMod(this, SpellModOp::Duration, duration); if (HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION) || HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) { @@ -3529,7 +3538,7 @@ int32 SpellInfo::CalcPeriod(WorldObject const* caster, SpellEffIndex effIndex, O return period; if (Player const* modOwner = unitCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SpellModOp::Period, period); + modOwner->ApplySpellMod(this, SpellModOp::Period, period); if (!HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS) && (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) || HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))) { @@ -3723,7 +3732,7 @@ int32 SpellInfo::CalcPowerCost(WorldObject const* caster, SpellSchoolMask school // Apply cost mod by spell if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SpellModOp::PowerCost0, powerCost, spell); + modOwner->ApplySpellMod(this, SpellModOp::PowerCost0, powerCost, spell); if (!unitCaster->IsControlledByPlayer()) { diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index c0a57e08f2..9efbfc1972 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -552,17 +552,17 @@ private: // 60779 - Idol of Lush Moss class spell_dru_idol_lifebloom : public AuraScript { - void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellModifier) { - if (!spellMod) + if (!spellModifier) { - spellMod = new SpellModifier(GetAura()); + SpellModifierByClassMask* spellMod = new SpellModifierByClassMask(GetAura()); spellMod->op = SpellModOp::PeriodicHealingAndDamage; spellMod->type = SPELLMOD_FLAT; spellMod->spellId = GetId(); spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask; } - spellMod->value = aurEff->GetAmount() / 7; + static_cast(spellModifier)->value = aurEff->GetAmount() / 7; } void Register() override diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 1794663fbf..aad19345fe 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -426,18 +426,19 @@ private: // 33695 - Exorcism and Holy Wrath Damage class spell_pal_exorcism_and_holy_wrath_damage : public AuraScript { - void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellModifier) { - if (!spellMod) + if (!spellModifier) { - spellMod = new SpellModifier(aurEff->GetBase()); + SpellModifierByClassMask* spellMod = new SpellModifierByClassMask(aurEff->GetBase()); spellMod->op = SpellModOp::HealingAndDamage; spellMod->type = SPELLMOD_FLAT; spellMod->spellId = GetId(); spellMod->mask[1] = 0x200002; + spellModifier = spellMod; } - spellMod->value = aurEff->GetAmount(); + static_cast(spellModifier)->value = aurEff->GetAmount(); } void Register() override @@ -1400,7 +1401,7 @@ class spell_pal_guardian_of_ancient_kings : public SpellScript class spell_pal_ancient_healer : public AuraScript { bool Load() override - { + { _procCount = 0; return true; } @@ -1815,7 +1816,7 @@ class spell_pal_speed_of_light : public AuraScript } }; -// -53695 - Judgements of the Just +// -53695 - Judgements of the Just class spell_pal_judgements_of_the_just : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 722d8aa71c..0ee36d68c6 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -367,18 +367,20 @@ class spell_pri_glyph_of_prayer_of_healing : public AuraScript class spell_pri_improved_power_word_shield : public AuraScript { - void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellModifier) { - if (!spellMod) + if (!spellModifier) { - spellMod = new SpellModifier(GetAura()); + SpellModifierByClassMask* spellMod = new SpellModifierByClassMask(GetAura()); spellMod->op = SpellModOp(aurEff->GetMiscValue()); spellMod->type = SPELLMOD_PCT; spellMod->spellId = GetId(); spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask; + + spellModifier = spellMod; } - spellMod->value = aurEff->GetAmount(); + static_cast(spellModifier)->value = aurEff->GetAmount(); } void Register() override @@ -1780,7 +1782,7 @@ class spell_pri_harnessed_shadows : public AuraScript } }; -// 2944 - Devouring Plague +// 2944 - Devouring Plague class spell_pri_devouring_plague : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 96229cd375..cb73560b36 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -619,7 +619,7 @@ class spell_warl_health_funnel : public AuraScript uint32 damage = caster->CountPctFromMaxHealth(aurEff->GetBaseAmount()); if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(GetId(), SpellModOp::PowerCost0, damage); + modOwner->ApplySpellMod(GetSpellInfo(), SpellModOp::PowerCost0, damage); SpellNonMeleeDamage damageInfo(caster, caster, GetSpellInfo()->Id, GetSpellInfo()->SchoolMask); damageInfo.damage = damage; @@ -1684,17 +1684,19 @@ class spell_warl_fear : public SpellScript // 56244 - Glyph of Fear class spell_warl_glyph_of_fear : public AuraScript { - void HandleCooldownMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleCooldownMod(AuraEffect const* aurEff, SpellModifier*& spellModifier) { - if (!spellMod) + if (!spellModifier) { - spellMod = new SpellModifier(GetAura()); + SpellModifierByClassMask* spellMod = new SpellModifierByClassMask(GetAura()); spellMod->op = SpellModOp::Cooldown; spellMod->type = SPELLMOD_FLAT; spellMod->spellId = GetId(); spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask; + spellModifier = spellMod; } - spellMod->value = aurEff->GetAmount() * IN_MILLISECONDS; + + static_cast(spellModifier)->value = aurEff->GetAmount() * IN_MILLISECONDS; } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 730711fe4f..4edec63236 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -279,18 +279,19 @@ class spell_warr_execute : public SpellScript // 58387 - Glyph of Sunder Armor class spell_warr_glyph_of_sunder_armor : public AuraScript { - void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellModifier) { - if (!spellMod) + if (!spellModifier) { - spellMod = new SpellModifier(aurEff->GetBase()); + SpellModifierByClassMask* spellMod = new SpellModifierByClassMask(aurEff->GetBase()); spellMod->op = SpellModOp(aurEff->GetMiscValue()); spellMod->type = SPELLMOD_FLAT; spellMod->spellId = GetId(); spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask; + spellModifier = spellMod; } - spellMod->value = aurEff->GetAmount(); + static_cast(spellModifier)->value = aurEff->GetAmount(); } void Register() override @@ -734,7 +735,7 @@ class spell_warr_victory_rush : public SpellScript // Glyph: Victory Rush if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_scriptSpellId, SpellModOp::PointsIndex2, damage); + modOwner->ApplySpellMod(GetSpellInfo(), SpellModOp::PointsIndex2, damage); SetEffectValue(damage); }