Core/Unit: simplified and arranged spell bonus calculation

- Remove duplicated SPELLMOD_BONUS_MULTIPLIER handling (both on done and taken)
- Handle properly bonus data, don't apply bonus by default, only player spells should take into account spell power
- Moved Earthliving Weapon coefficient to DB
- Refactored Avenging Wrath handling

Closes #13287
Closes #21230
This commit is contained in:
ariel-
2018-01-13 19:57:20 -03:00
parent a305661785
commit d570e2af3e
2 changed files with 78 additions and 99 deletions

View File

@@ -0,0 +1,8 @@
DELETE FROM `spell_bonus_data` WHERE `entry` IN (51945, 51990, 51997, 51998, 51999, 52000);
INSERT INTO `spell_bonus_data` (`entry`, `direct_bonus`, `dot_bonus`, `ap_bonus`, `ap_dot_bonus`, `comments`) VALUES
(51945, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 1)'),
(51990, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 2)'),
(51997, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 3)'),
(51998, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 4)'),
(51999, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 5)'),
(52000, 0, 0.1692, 0, 0, 'Shaman - Earthliving Weapon (Rank 6)');

View File

@@ -6771,8 +6771,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
// Check for table values
float coeff = 0.f;
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
if (bonus)
if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
{
WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS));
@@ -6793,19 +6792,16 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
}
// Default calculation
if (DoneAdvertisedBenefit)
if (coeff && DoneAdvertisedBenefit)
{
if (!bonus || coeff < 0)
coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack);
float factorMod = CalculateLevelPenalty(spellProto) * stack;
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
coeff /= 100.0f;
}
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
@@ -7134,7 +7130,6 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
int32 TakenTotal = 0;
float TakenTotalMod = 1.0f;
float TakenTotalCasterMod = 0.0f;
// Mod damage from spell mechanic
if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
@@ -7166,67 +7161,64 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
break;
}
}
// Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
// Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
// get all auras from caster that allow the spell to ignore resistance (sanctified wrath)
TakenTotalCasterMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, spellProto->GetSchoolMask());
// from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
// multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, spellProto->GetSchoolMask());
// From caster spells
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
if (caster)
{
if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectedOnSpell(spellProto))
return true;
return false;
});
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
{
if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectedOnSpell(spellProto))
return true;
return false;
});
}
int32 TakenAdvertisedBenefit = SpellBaseDamageBonusTaken(spellProto->GetSchoolMask());
// Check for table values
float coeff = 0;
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
if (bonus)
float coeff = 0.f;
if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
coeff = (damagetype == DOT) ? bonus->dot_damage : bonus->direct_damage;
// Default calculation
if (TakenAdvertisedBenefit)
{
if (!bonus || coeff < 0)
coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack);
float factorMod = CalculateLevelPenalty(spellProto) * stack;
// level penalty still applied on Taken bonus - is it blizzlike?
if (Player* modOwner = GetSpellModOwner())
if (coeff < 0.f)
{
coeff *= 100.0f;
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
coeff /= 100.0f;
Unit const* calc = caster ? caster : this;
coeff = calc->CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack);
}
// level penalty still applied on Taken bonus - is it blizzlike?
float factorMod = CalculateLevelPenalty(spellProto) * stack;
TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod);
}
}
float tmpDamage = 0.0f;
if (TakenTotalCasterMod)
// Sanctified Wrath (bypass damage reduction)
if (caster && TakenTotalMod < 1.0f)
{
if (TakenTotal < 0)
float damageReduction = 1.0f - TakenTotalMod;
Unit::AuraEffectList const& casterIgnoreResist = caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
for (AuraEffect const* aurEff : casterIgnoreResist)
{
if (TakenTotalMod < 1)
tmpDamage = ((float(CalculatePct(pdamage, TakenTotalCasterMod) + TakenTotal) * TakenTotalMod) + CalculatePct(pdamage, TakenTotalCasterMod));
else
tmpDamage = ((float(CalculatePct(pdamage, TakenTotalCasterMod) + TakenTotal) + CalculatePct(pdamage, TakenTotalCasterMod)) * TakenTotalMod);
}
else if (TakenTotalMod < 1)
tmpDamage = ((CalculatePct(float(pdamage) + TakenTotal, TakenTotalCasterMod) * TakenTotalMod) + CalculatePct(float(pdamage) + TakenTotal, TakenTotalCasterMod));
}
if (!tmpDamage)
tmpDamage = (float(pdamage) + TakenTotal) * TakenTotalMod;
if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
continue;
ApplyPct(damageReduction, aurEff->GetAmount());
}
TakenTotalMod = 1.0f - damageReduction;
}
float tmpDamage = float(pdamage + TakenTotal) * TakenTotalMod;
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -7641,10 +7633,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
// Check for table values
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
float coeff = 0;
float factorMod = 1.0f;
if (bonus)
float coeff = 0.f;
if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
{
if (damagetype == DOT)
{
@@ -7669,13 +7659,9 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
}
// Default calculation
if (DoneAdvertisedBenefit)
if (coeff && DoneAdvertisedBenefit)
{
if (!bonus || coeff < 0)
coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
factorMod *= CalculateLevelPenalty(spellProto) * stack;
float factorMod = CalculateLevelPenalty(spellProto) * stack;
if (Player* modOwner = GetSpellModOwner())
{
coeff *= 100.0f;
@@ -7683,10 +7669,6 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
coeff /= 100.0f;
}
// Earthliving - 0.45% of normal hot coeff
if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000)
factorMod *= 0.45f;
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
@@ -7838,10 +7820,8 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
}
// Check for table values
SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
float coeff = 0;
float factorMod = 1.0f;
if (bonus)
if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
coeff = (damagetype == DOT) ? bonus->dot_damage : bonus->direct_damage;
else
{
@@ -7856,30 +7836,26 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
// Default calculation
if (TakenAdvertisedBenefit)
{
if (!bonus || coeff < 0)
coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
factorMod *= CalculateLevelPenalty(spellProto) * int32(stack);
if (Player* modOwner = GetSpellModOwner())
if (coeff < 0.f)
{
coeff *= 100.0f;
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
coeff /= 100.0f;
Unit const* calc = caster ? caster : this;
coeff = calc->CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
}
// Earthliving - 0.45% of normal hot coeff
if (spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000)
factorMod *= 0.45f;
// level penalty still applied on Taken bonus - is it blizzlike?
float factorMod = CalculateLevelPenalty(spellProto) * int32(stack);
TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod);
}
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff) -> bool
if (caster)
{
if (caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectedOnSpell(spellProto))
return true;
return false;
});
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff) -> bool
{
if (caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectedOnSpell(spellProto))
return true;
return false;
});
}
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
@@ -8299,11 +8275,6 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
return 0;
int32 TakenFlatBenefit = 0;
float TakenTotalCasterMod = 0.0f;
// get all auras from caster that allow the spell to ignore resistance (sanctified wrath)
SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL;
TakenTotalCasterMod += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, attackSchoolMask);
// ..taken
TakenFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, attacker->GetMeleeDamageSchoolMask());
@@ -8382,24 +8353,25 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
else
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
float tmpDamage = 0.0f;
if (TakenTotalCasterMod)
// Sanctified Wrath (bypass damage reduction)
if (attacker && TakenTotalMod < 1.0f)
{
if (TakenFlatBenefit < 0)
{
if (TakenTotalMod < 1)
tmpDamage = ((float(CalculatePct(pdamage, TakenTotalCasterMod) + TakenFlatBenefit) * TakenTotalMod) + CalculatePct(pdamage, TakenTotalCasterMod));
else
tmpDamage = ((float(CalculatePct(pdamage, TakenTotalCasterMod) + TakenFlatBenefit) + CalculatePct(pdamage, TakenTotalCasterMod)) * TakenTotalMod);
}
else if (TakenTotalMod < 1)
tmpDamage = ((CalculatePct(float(pdamage) + TakenFlatBenefit, TakenTotalCasterMod) * TakenTotalMod) + CalculatePct(float(pdamage) + TakenFlatBenefit, TakenTotalCasterMod));
}
if (!tmpDamage)
tmpDamage = (float(pdamage) + TakenFlatBenefit) * TakenTotalMod;
SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL;
// bonus result can be negative
float damageReduction = 1.0f - TakenTotalMod;
Unit::AuraEffectList const& casterIgnoreResist = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
for (AuraEffect const* aurEff : casterIgnoreResist)
{
if (!(aurEff->GetMiscValue() & attackSchoolMask))
continue;
ApplyPct(damageReduction, aurEff->GetAmount());
}
TakenTotalMod = 1.0f - damageReduction;
}
float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -11505,7 +11477,6 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect
float DotFactor = 1.0f;
if (damagetype == DOT)
{
int32 DotDuration = spellInfo->GetDuration();
if (!spellInfo->IsChanneled() && DotDuration > 0)
DotFactor = DotDuration / 15000.0f;