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