Core/Auras: reworked multiplicative AuraEffects calculation

- Splitted containers for flat modifiers and pct modifiers, as they now have different handling
- Amount is now multiplied only on apply; on unapply, iterate through auras and reset the counter
- Fixes many cases of rounding error due to applying/unapplying of small factors
- Allows amounts to be zeroed (ie with an AuraEffect of amount -100)
- Do a partial revert of 6dc37a9add631888fe5fbcd43d19c2b07bed8a57, auras should update amounts only for items allowed (ie no more giving crit to a sword while having an axe in the other hand and being Poleaxe spec'd)
- SPELL_AURA_MOD_SCALE now scales additively, rather than multiplicatively (checked in sniffs)

Closes #18687

(cherry picked from commit c69a7d1223b2ce108a221e5cc70f76cd80ae6675)
This commit is contained in:
ariel-
2020-04-24 17:18:47 +02:00
committed by funjoker
parent 73ea9ecec1
commit ebc06b1d04
15 changed files with 812 additions and 387 deletions
+62 -62
View File
@@ -200,7 +200,7 @@ void Player::UpdateSpellDamageAndHealingBonus()
bool Player::UpdateAllStats()
{
for (int8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
float value = GetTotalStatValue(Stats(i));
SetStat(Stats(i), int32(value));
@@ -254,10 +254,10 @@ void Player::UpdateArmor()
{
UnitMods unitMod = UNIT_MOD_ARMOR;
float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
float baseValue = value;
value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
@@ -267,7 +267,7 @@ void Player::UpdateArmor()
value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount());
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetArmor(int32(baseValue), int32(value - baseValue));
@@ -294,10 +294,10 @@ void Player::UpdateMaxHealth()
{
UnitMods unitMod = UNIT_MOD_HEALTH;
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
@@ -315,10 +315,10 @@ void Player::UpdateMaxPower(Powers power)
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, (int32)std::lroundf(value));
}
@@ -357,11 +357,11 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
val2 = CalculatePct(float(minSpellPower), *m_activePlayerData->OverrideAPBySpellPowerPercent);
}
SetModifierValue(unitMod, BASE_VALUE, val2);
SetStatFlatModifier(unitMod, BASE_VALUE, val2);
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
if (ranged)
{
@@ -405,7 +405,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
}
}
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const
{
UnitMods unitMod;
@@ -425,10 +425,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
float attackPowerMod = std::max(GetAPMultiplier(attType, normalized), 0.25f);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod;
float basePct = GetModifierValue(unitMod, BASE_PCT);
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod;
float basePct = GetPctModifierValue(unitMod, BASE_PCT);
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
@@ -492,16 +492,16 @@ void Player::UpdateCritPercentage(WeaponAttackType attType)
{
case OFF_ATTACK:
SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::OffhandCritPercentage),
applyCritLimit(GetTotalPercentageModValue(OFFHAND_CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_MELEE)));
applyCritLimit(GetBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_MELEE)));
break;
case RANGED_ATTACK:
SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::RangedCritPercentage),
applyCritLimit(GetTotalPercentageModValue(RANGED_CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_RANGED)));
applyCritLimit(GetBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_RANGED)));
break;
case BASE_ATTACK:
default:
SetUpdateFieldStatValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CritPercentage),
applyCritLimit(GetTotalPercentageModValue(CRIT_PERCENTAGE) + GetRatingBonusValue(CR_CRIT_MELEE)));
applyCritLimit(GetBaseModValue(CRIT_PERCENTAGE, FLAT_MOD) + GetBaseModValue(CRIT_PERCENTAGE, PCT_MOD) + GetRatingBonusValue(CR_CRIT_MELEE)));
break;
}
}
@@ -510,9 +510,9 @@ void Player::UpdateAllCritPercentages()
{
float value = 5.0f;
SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
SetBaseModPctValue(CRIT_PERCENTAGE, value);
SetBaseModPctValue(OFFHAND_CRIT_PERCENTAGE, value);
SetBaseModPctValue(RANGED_CRIT_PERCENTAGE, value);
UpdateCritPercentage(BASE_ATTACK);
UpdateCritPercentage(OFF_ATTACK);
@@ -835,7 +835,7 @@ bool Creature::UpdateAllStats()
void Creature::UpdateArmor()
{
float baseValue = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
float baseValue = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
float value = GetTotalAuraModValue(UNIT_MOD_ARMOR);
SetArmor(int32(baseValue), int32(value - baseValue));
}
@@ -864,10 +864,10 @@ void Creature::UpdateMaxPower(Powers power)
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, (int32)std::lroundf(value));
}
@@ -876,8 +876,8 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
{
UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
if (ranged)
{
@@ -900,7 +900,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
}
}
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const
{
float variance = 1.0f;
UnitMods unitMod;
@@ -939,10 +939,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
float attackPower = GetTotalAttackPowerValue(attType);
float attackSpeedMulti = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 3.5f) * variance;
float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 3.5f) * variance;
float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float dmgMultiplier = GetCreatureTemplate()->ModDamage; // = ModDamage * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
@@ -970,7 +970,7 @@ bool Guardian::UpdateStats(Stats stat)
{
// value = ((base_value * base_pct) + total_value) * total_pct
float value = GetTotalStatValue(stat);
ApplyStatBuffMod(stat, m_statFromOwner[stat], false);
UpdateStatBuffMod(stat);
float ownersBonus = 0.0f;
Unit* owner = GetOwner();
@@ -1010,7 +1010,7 @@ bool Guardian::UpdateStats(Stats stat)
SetStat(stat, int32(value));
m_statFromOwner[stat] = ownersBonus;
ApplyStatBuffMod(stat, m_statFromOwner[stat], true);
UpdateStatBuffMod(stat);
switch (stat)
{
@@ -1044,7 +1044,7 @@ void Guardian::UpdateResistances(uint32 school)
{
if (school > SPELL_SCHOOL_NORMAL)
{
float baseValue = GetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + school), BASE_VALUE);
float baseValue = GetFlatModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + school), BASE_VALUE);
float bonusValue = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)) - baseValue;
// hunter and warlock pets gain 40% of owner's resistance
@@ -1074,11 +1074,11 @@ void Guardian::UpdateArmor()
else if (IsPet())
bonus_armor = m_owner->GetArmor();
value = GetModifierValue(unitMod, BASE_VALUE);
value = GetFlatModifierValue(unitMod, BASE_VALUE);
baseValue = value;
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonus_armor;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetArmor(int32(baseValue), int32(value - baseValue));
}
@@ -1100,10 +1100,10 @@ void Guardian::UpdateMaxHealth()
default: multiplicator = 10.0f; break;
}
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
@@ -1115,10 +1115,10 @@ void Guardian::UpdateMaxPower(Powers power)
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, int32(value));
}
@@ -1178,11 +1178,11 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
}
}
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP);
//in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
SetAttackPower(int32(base_attPower));
SetAttackPowerMultiplier(attPowerMultiplier);
@@ -1219,10 +1219,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
float att_speed = float(GetBaseAttackTime(BASE_ATTACK))/1000.0f;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 3.5f * att_speed + bonusDamage;
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 3.5f * att_speed + bonusDamage;
float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT);
float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);