Core/Items: Fixed item level and stat calculation

This commit is contained in:
Shauren
2026-05-22 01:19:04 +02:00
parent 9c738b17ff
commit 84261ff286
2 changed files with 74 additions and 40 deletions
+6 -6
View File
@@ -2295,13 +2295,13 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon
else if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(bonusData.ContentTuningId, {}, true))
level = std::min(std::max(int16(level), levels->MinLevel), levels->MaxLevel);
itemLevel = uint32(sDB2Manager.GetCurveValueAt(bonusData.PlayerLevelToItemLevelCurveId, level));
itemLevel = uint32(std::round(sDB2Manager.GetCurveValueAt(bonusData.PlayerLevelToItemLevelCurveId, level)));
}
itemLevel += bonusData.ItemLevelBonus;
}
else
itemLevel = bonusData.ItemLevelOffset + uint32(sDB2Manager.GetCurveValueAt(bonusData.ItemLevelOffsetCurveId, bonusData.ItemLevelOffsetItemLevel));
itemLevel = bonusData.ItemLevelOffset + uint32(std::round(sDB2Manager.GetCurveValueAt(bonusData.ItemLevelOffsetCurveId, bonusData.ItemLevelOffsetItemLevel)));
for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
itemLevel += bonusData.GemItemLevelBonus[i];
@@ -2323,17 +2323,17 @@ uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bon
int32 currentBuild = ClientBuild::GetMinorMajorBugfixVersionForBuild(currentRealm->Build);
// apply all squishes between items_squish and server_squish
for (uint32 squishId = bonusData.ItemSquishEraID; squishId < sItemSquishEraStore.GetNumRows(); ++squishId)
for (uint32 squishId = bonusData.ItemSquishEraID + 1; squishId < sItemSquishEraStore.GetNumRows(); ++squishId)
{
ItemSquishEraEntry const* squish = sItemSquishEraStore.LookupEntry(squishId);
if (!squish)
if (!squish || squish->Flags & 0x1)
continue;
if (squish->Patch > currentBuild)
break;
if (squish->CurveID)
itemLevel = uint32(sDB2Manager.GetCurveValueAt(squish->CurveID, itemLevel));
itemLevel = uint32(std::round(sDB2Manager.GetCurveValueAt(squish->CurveID, itemLevel)));
}
}
}
@@ -2367,7 +2367,7 @@ float Item::GetItemStatValue(uint32 index, Player const* owner) const
{
float statValue = float(_bonusData.StatPercentEditor[index] * randomPropPoints) * 0.0001f;
if (GtItemSocketCostPerLevelEntry const* gtCost = sItemSocketCostPerLevelGameTable.GetRow(itemLevel))
statValue -= float(int32(_bonusData.ItemStatSocketCostMultiplier[index] * gtCost->SocketCost));
statValue -= float(_bonusData.ItemStatSocketCostMultiplier[index] * gtCost->SocketCost);
return statValue;
}
+68 -34
View File
@@ -7970,6 +7970,44 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
if (val == 0)
continue;
// apply stat multiplier
switch (statType)
{
case ITEM_MOD_STAMINA:
if (GtStaminaMultByILvl const* staminaMult = sStaminaMultByILvlGameTable.GetRow(itemLevel))
val *= GetIlvlStatMultiplier(staminaMult, proto->GetInventoryType());
break;
case ITEM_MOD_DEFENSE_SKILL_RATING:
case ITEM_MOD_DODGE_RATING:
case ITEM_MOD_PARRY_RATING:
case ITEM_MOD_BLOCK_RATING:
case ITEM_MOD_HIT_MELEE_RATING:
case ITEM_MOD_HIT_RANGED_RATING:
case ITEM_MOD_HIT_SPELL_RATING:
case ITEM_MOD_CRIT_MELEE_RATING:
case ITEM_MOD_CRIT_RANGED_RATING:
case ITEM_MOD_CRIT_SPELL_RATING:
case ITEM_MOD_HIT_RATING:
case ITEM_MOD_CRIT_RATING:
case ITEM_MOD_HIT_TAKEN_RATING:
case ITEM_MOD_CRIT_TAKEN_RATING:
case ITEM_MOD_RESILIENCE_RATING:
case ITEM_MOD_HASTE_RATING:
case ITEM_MOD_EXPERTISE_RATING:
case ITEM_MOD_VERSATILITY:
case ITEM_MOD_MASTERY_RATING:
case ITEM_MOD_CR_SPEED:
case ITEM_MOD_CR_LIFESTEAL:
case ITEM_MOD_CR_AVOIDANCE:
case ITEM_MOD_CR_STURDINESS:
val *= combatRatingMultiplier;
break;
default:
break;
}
val = std::round(val);
switch (statType)
{
case ITEM_MOD_MANA:
@@ -7995,42 +8033,38 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
UpdateStatBuffMod(STAT_SPIRIT);
break;
case ITEM_MOD_STAMINA: //modify stamina
{
if (GtStaminaMultByILvl const* staminaMult = sStaminaMultByILvlGameTable.GetRow(itemLevel))
val = int32(val * GetIlvlStatMultiplier(staminaMult, proto->GetInventoryType()));
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
UpdateStatBuffMod(STAT_STAMINA);
break;
}
case ITEM_MOD_DEFENSE_SKILL_RATING:
ApplyRatingMod(CR_DEFENSE_SKILL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply);
break;
case ITEM_MOD_DODGE_RATING:
ApplyRatingMod(CR_DODGE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_DODGE, int32(val), apply);
break;
case ITEM_MOD_PARRY_RATING:
ApplyRatingMod(CR_PARRY, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_PARRY, int32(val), apply);
break;
case ITEM_MOD_BLOCK_RATING:
ApplyRatingMod(CR_BLOCK, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_BLOCK, int32(val), apply);
break;
case ITEM_MOD_HIT_MELEE_RATING:
ApplyRatingMod(CR_HIT_MELEE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_MELEE, int32(val), apply);
break;
case ITEM_MOD_HIT_RANGED_RATING:
ApplyRatingMod(CR_HIT_RANGED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_RANGED, int32(val), apply);
break;
case ITEM_MOD_HIT_SPELL_RATING:
ApplyRatingMod(CR_HIT_SPELL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_SPELL, int32(val), apply);
break;
case ITEM_MOD_CRIT_MELEE_RATING:
ApplyRatingMod(CR_CRIT_MELEE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply);
break;
case ITEM_MOD_CRIT_RANGED_RATING:
ApplyRatingMod(CR_CRIT_RANGED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply);
break;
case ITEM_MOD_CRIT_SPELL_RATING:
ApplyRatingMod(CR_CRIT_SPELL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply);
break;
// case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
// ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
@@ -8060,14 +8094,14 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply);
break;
case ITEM_MOD_HIT_RATING:
ApplyRatingMod(CR_HIT_MELEE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_RANGED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_SPELL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HIT_MELEE, int32(val), apply);
ApplyRatingMod(CR_HIT_RANGED, int32(val), apply);
ApplyRatingMod(CR_HIT_SPELL, int32(val), apply);
break;
case ITEM_MOD_CRIT_RATING:
ApplyRatingMod(CR_CRIT_MELEE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_RANGED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_SPELL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply);
ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply);
ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply);
break;
// case ITEM_MOD_HIT_TAKEN_RATING: // Unused since 3.3.5
// ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
@@ -8080,15 +8114,15 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
// ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
// break;
case ITEM_MOD_RESILIENCE_RATING:
ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE, int32(val), apply);
break;
case ITEM_MOD_HASTE_RATING:
ApplyRatingMod(CR_HASTE_MELEE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HASTE_RANGED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HASTE_SPELL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply);
ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply);
ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply);
break;
case ITEM_MOD_EXPERTISE_RATING:
ApplyRatingMod(CR_EXPERTISE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_EXPERTISE, int32(val), apply);
break;
case ITEM_MOD_ATTACK_POWER:
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
@@ -8098,9 +8132,9 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
break;
case ITEM_MOD_VERSATILITY:
ApplyRatingMod(CR_VERSATILITY_DAMAGE_DONE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_VERSATILITY_DAMAGE_TAKEN, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_VERSATILITY_HEALING_DONE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_VERSATILITY_DAMAGE_DONE, int32(val), apply);
ApplyRatingMod(CR_VERSATILITY_DAMAGE_TAKEN, int32(val), apply);
ApplyRatingMod(CR_VERSATILITY_HEALING_DONE, int32(val), apply);
break;
case ITEM_MOD_MANA_REGENERATION:
ApplyManaRegenBonus(int32(val), apply);
@@ -8115,10 +8149,10 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
ApplyHealthRegenBonus(int32(val), apply);
break;
case ITEM_MOD_SPELL_PENETRATION:
ApplySpellPenetrationBonus(val, apply);
ApplySpellPenetrationBonus(int32(val), apply);
break;
case ITEM_MOD_MASTERY_RATING:
ApplyRatingMod(CR_MASTERY, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_MASTERY, int32(val), apply);
break;
case ITEM_MOD_EXTRA_ARMOR:
HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(val), apply);
@@ -8151,16 +8185,16 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply)
ApplyRatingMod(CR_CORRUPTION_RESISTANCE, int32(val), apply);
break;
case ITEM_MOD_CR_SPEED:
ApplyRatingMod(CR_SPEED, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_SPEED, int32(val), apply);
break;
case ITEM_MOD_CR_LIFESTEAL:
ApplyRatingMod(CR_LIFESTEAL, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_LIFESTEAL, int32(val), apply);
break;
case ITEM_MOD_CR_AVOIDANCE:
ApplyRatingMod(CR_AVOIDANCE, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_AVOIDANCE, int32(val), apply);
break;
case ITEM_MOD_CR_STURDINESS:
ApplyRatingMod(CR_STURDINESS, int32(val * combatRatingMultiplier), apply);
ApplyRatingMod(CR_STURDINESS, int32(val), apply);
break;
case ITEM_MOD_AGI_STR_INT:
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);