Core/Spells: ported spellMod handling from master branch
This commit is contained in:
1 parent
b390f0fec9
commit
83958342d9
16 files changed
+374
-177
No files matched your search
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
#include "WorldSession.h"
|
||||
#include "WorldStateMgr.h"
|
||||
#include "WorldStatePackets.h"
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
#include <G3D/g3dmath.h>
|
||||
|
||||
// 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 <class T>
|
||||
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<SpellModifier*>::const_iterator const& itr) const
|
||||
{
|
||||
return itr == end || (*itr)->op != op || (*itr)->type != type;
|
||||
}
|
||||
|
||||
std::vector<SpellModifier*>::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<SpellModifierByClassMask*>(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<SpellModifierByClassMask*>(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<SpellModifierByClassMask*>(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<SpellModifierByClassMask*>(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 <class T>
|
||||
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<uint32> mask;
|
||||
mask.resize(96);
|
||||
|
||||
boost::from_block_range(
|
||||
&static_cast<SpellModifierByClassMask const*>(mod)->mask[0],
|
||||
&static_cast<SpellModifierByClassMask const*>(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<SpellModifierByClassMask const*>(*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<SpellModifierByClassMask const*>(*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<WorldPackets::Spells::SpellModifierData>& 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<uint32> 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<SpellModifierByClassMask const*>(mod)->mask[0], &static_cast<SpellModifierByClassMask const*>(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<SpellModifierByClassMask const*>(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<SpellModifierByClassMask const*>(mod)->mask[0], &static_cast<SpellModifierByClassMask const*>(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<SpellModifierByClassMask const*>(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())
|
||||
|
||||
@@ -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<uint32, PlayerTalent*> PlayerTalentMap;
|
||||
typedef std::unordered_map<uint32, PlayerSpell> PlayerSpellMap;
|
||||
typedef std::unordered_set<SpellModifier*> SpellModContainer;
|
||||
typedef Trinity::Containers::FlatSet<SpellModifier*, SpellModifierCompare> SpellModContainer;
|
||||
typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap;
|
||||
|
||||
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
|
||||
@@ -1649,9 +1672,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
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 <class T>
|
||||
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 <class T>
|
||||
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<Player>
|
||||
uint32 m_baseHealthRegen;
|
||||
int32 m_spellPenetrationItemMod;
|
||||
|
||||
SpellModContainer m_spellMods[MAX_SPELLMOD][SPELLMOD_END];
|
||||
SpellModContainer m_spellMods;
|
||||
|
||||
EnchantDurationList m_enchantDuration;
|
||||
ItemDurationList m_itemDuration;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Spell*>(this));
|
||||
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runeCost[i], const_cast<Spell*>(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<Spell*>(this));
|
||||
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runeCost[i], const_cast<Spell*>(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<Spell*>(this));
|
||||
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCost0, runicPowerGain, const_cast<Spell*>(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<float, float> 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<Spell*>(this));
|
||||
modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, maxRange, const_cast<Spell*>(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 &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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<SpellModifierByClassMask const*>(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())
|
||||
{
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(spellModifier)->value = aurEff->GetAmount() / 7;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(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
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(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
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(spellModifier)->value = aurEff->GetAmount() * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -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<SpellModifierByClassMask*>(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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user