fix(Core/Spells): Implement TrinityCore spell_group and spell_group_stack_rules (#23346)

Co-authored-by: treeston <treeston.mmoc@gmail.com>
Co-authored-by: Trisjdc <trisjdc@gmail.com>
Co-authored-by: QAston <none@none>
Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Jelle Meeus <sogladev@gmail.com>
This commit is contained in:
Tereneckla
2025-11-28 19:01:25 +00:00
committed by GitHub
parent 55989205e7
commit 2f7f9bd72f
42 changed files with 1976 additions and 1705 deletions
+63 -67
View File
@@ -204,7 +204,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));
@@ -247,9 +247,9 @@ void Player::UpdateResistances(uint32 school)
float value = 0.0f;
UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
value = GetModifierValue(unitMod, BASE_VALUE);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value = GetFlatModifierValue(unitMod, BASE_VALUE);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
for(AuraEffectList::const_iterator i = mResbyIntellect.begin(); i != mResbyIntellect.end(); ++i)
@@ -258,7 +258,7 @@ void Player::UpdateResistances(uint32 school)
value += int32(GetStat(Stats((*i)->GetMiscValueB())) * (*i)->GetAmount() / 100.0f);
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetResistance(SpellSchools(school), int32(value));
}
@@ -270,10 +270,10 @@ void Player::UpdateArmor()
{
UnitMods unitMod = UNIT_MOD_ARMOR;
float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
value += GetModifierValue(unitMod, TOTAL_VALUE);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
@@ -283,7 +283,7 @@ void Player::UpdateArmor()
value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount());
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetArmor(int32(value));
@@ -314,10 +314,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);
sScriptMgr->OnPlayerAfterUpdateMaxHealth(this, value);
SetMaxHealth((uint32)value);
@@ -329,10 +329,10 @@ void Player::UpdateMaxPower(Powers power)
float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0;
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
sScriptMgr->OnPlayerAfterUpdateMaxPower(this, power, value);
SetMaxPower(power, uint32(value));
@@ -487,10 +487,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
}
}
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 base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
//add dynamic flat mods
if (ranged)
@@ -514,7 +514,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
attPowerMod += int32(GetArmor() / (*iter)->GetAmount());
}
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
sScriptMgr->OnPlayerAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
@@ -576,10 +576,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
float attackSpeedMod = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
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) / 14.0f * attackSpeedMod;
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);
@@ -681,7 +681,8 @@ void Player::UpdateCritPercentage(WeaponAttackType attType)
break;
}
float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
// flat = bonus from crit auras, pct = bonus from agility, combat rating = mods from items
float value = GetBaseModValue(modGroup, FLAT_MOD) + GetBaseModValue(modGroup, PCT_MOD) + GetRatingBonusValue(cr);
// Modify crit from weapon skill and maximized defense skill of same level victim difference
value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
@@ -698,9 +699,9 @@ void Player::UpdateAllCritPercentages()
{
float value = GetMeleeCritFromAgility();
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);
@@ -849,7 +850,7 @@ void Player::UpdateSpellCritChance(uint32 school)
// Crit from Intellect
crit += GetSpellCritFromIntellect();
// Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
crit += GetTotalAuraModifierAreaExclusive(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
// Increase crit from SPELL_AURA_MOD_CRIT_PCT
crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
// Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@@ -900,16 +901,11 @@ void Player::UpdateExpertise(WeaponAttackType attack)
Item* weapon = GetWeaponForAttack(attack, true);
AuraEffectList const& expAuras = GetAuraEffectsByType(SPELL_AURA_MOD_EXPERTISE);
for (AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
expertise += GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE, [weapon](AuraEffect const* aurEff)
{
// item neutral spell
if ((*itr)->GetSpellInfo()->EquippedItemClass == -1)
expertise += (*itr)->GetAmount();
// item dependent spell
else if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
expertise += (*itr)->GetAmount();
}
return aurEff->GetSpellInfo()->EquippedItemClass == -1 || // item neutral spell
(weapon && weapon->IsFitToSpellRequirements(aurEff->GetSpellInfo())); // item dependent spell
});
if (expertise < 0)
expertise = 0;
@@ -1100,9 +1096,9 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
}
float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
float attackPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER
SetInt32Value(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS
@@ -1166,10 +1162,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
float attackPower = GetTotalAttackPowerValue(attType);
float attackSpeedMulti = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * 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 / 14.0f) * 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()->DamageModifier; // = DamageModifier * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
@@ -1233,11 +1229,11 @@ bool Guardian::UpdateAllStats()
void Guardian::UpdateArmor()
{
float value = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
float value = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
value += std::max<float>(GetStat(STAT_AGILITY) - GetCreateStat(STAT_AGILITY), 0.0f) * 2.0f;
value += GetModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
value += GetFlatModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
value *= GetPctModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
SetArmor(int32(value));
}
@@ -1278,10 +1274,10 @@ void Guardian::UpdateMaxHealth()
break;
}
float value = GetModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
float value = GetFlatModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxHealth((uint32)value);
}
@@ -1311,11 +1307,11 @@ void Guardian::UpdateMaxPower(Powers power)
break;
}
// xinef: Do NOT add base mana TWICE
float value = GetModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetModifierValue(unitMod, TOTAL_PCT);
// Do NOT add base mana TWICE
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
value *= GetPctModifierValue(unitMod, BASE_PCT);
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
SetMaxPower(power, uint32(value));
}
@@ -1335,12 +1331,12 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
else
val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
SetModifierValue(unitMod, BASE_VALUE, val);
SetStatFlatModifier(unitMod, BASE_VALUE, val);
//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 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;
//UNIT_FIELD_(RANGED)_ATTACK_POWER field
SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
@@ -1362,10 +1358,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
float att_speed = float(GetAttackTime(BASE_ATTACK)) / 1000.0f;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed;
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) / 14.0f * att_speed;
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);