mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-22 10:05:32 +01:00
Core/Items: reworked item weapon damage and armor calculations based on what client does internally
This commit is contained in:
@@ -75,8 +75,8 @@ struct ItemSparseEntry
|
||||
uint32 ContainerSlots; // 20
|
||||
int32 ItemStatType[MAX_ITEM_PROTO_STATS]; // 21 - 30
|
||||
uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]; // 31 - 40
|
||||
int32 ItemStatUnk1[MAX_ITEM_PROTO_STATS]; // 41 - 50
|
||||
int32 ItemStatUnk2[MAX_ITEM_PROTO_STATS]; // 51 - 60
|
||||
int32 ItemStatAllocation[MAX_ITEM_PROTO_STATS]; // 41 - 50
|
||||
int32 ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]; // 51 - 60
|
||||
uint32 ScalingStatDistribution; // 61
|
||||
uint32 DamageType; // 62
|
||||
uint32 Delay; // 63
|
||||
|
||||
@@ -87,10 +87,10 @@ void DB2Utilities::WriteItemSparseDbReply(DB2Storage<ItemSparseEntry> const& /*s
|
||||
buffer << int32(proto->ItemStat[x].ItemStatValue);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << int32(proto->ItemStat[x].ItemStatUnk1);
|
||||
buffer << int32(proto->ItemStat[x].ItemStatAllocation);
|
||||
|
||||
for (uint32 x = 0; x < MAX_ITEM_PROTO_STATS; ++x)
|
||||
buffer << int32(proto->ItemStat[x].ItemStatUnk2);
|
||||
buffer << int32(proto->ItemStat[x].ItemStatSocketCostMultiplier);
|
||||
|
||||
buffer << uint32(proto->ScalingStatDistribution);
|
||||
buffer << uint32(proto->DamageType);
|
||||
|
||||
@@ -1338,3 +1338,254 @@ bool IsInArea(uint32 objectAreaId, uint32 areaId)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 ItemTemplate::GetEffectiveArmor(Player* owner) const
|
||||
{
|
||||
if (Quality > ITEM_QUALITY_ARTIFACT)
|
||||
return 0;
|
||||
|
||||
uint32 level = ItemLevel;
|
||||
if (owner != nullptr)
|
||||
{
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
if (maxItemLevel != 0 && level > maxItemLevel)
|
||||
level = maxItemLevel;
|
||||
}
|
||||
|
||||
if (Class != ITEM_CLASS_ARMOR || SubClass != ITEM_SUBCLASS_ARMOR_SHIELD)
|
||||
{
|
||||
ItemArmorQualityEntry const* armorQuality = sItemArmorQualityStore.LookupEntry(level);
|
||||
ItemArmorTotalEntry const* armorTotal = sItemArmorTotalStore.LookupEntry(level);
|
||||
if (!armorQuality || !armorTotal)
|
||||
return 0;
|
||||
|
||||
uint32 invType = InventoryType;
|
||||
if (invType == INVTYPE_ROBE)
|
||||
invType = INVTYPE_CHEST;
|
||||
|
||||
ArmorLocationEntry const* location = sArmorLocationStore.LookupEntry(invType);
|
||||
if (!location)
|
||||
return 0;
|
||||
|
||||
if (SubClass < ITEM_SUBCLASS_ARMOR_CLOTH || SubClass > ITEM_SUBCLASS_ARMOR_PLATE)
|
||||
return 0;
|
||||
|
||||
return uint32(armorQuality->Value[Quality] * armorTotal->Value[SubClass - ITEM_SUBCLASS_ARMOR_CLOTH] * location->Value[SubClass - ITEM_SUBCLASS_ARMOR_CLOTH] + 0.5f);
|
||||
}
|
||||
|
||||
ItemArmorShieldEntry const* shield = sItemArmorShieldStore.LookupEntry(level);
|
||||
if (!shield)
|
||||
return 0;
|
||||
|
||||
return uint32(shield->Value[Quality] + 0.5f);
|
||||
}
|
||||
|
||||
bool ItemTemplate::GetWeaponDamage(Player* owner, float& minValue, float& maxValue, float& dps) const
|
||||
{
|
||||
minValue = maxValue = 0.0f;
|
||||
if (Class != ITEM_CLASS_WEAPON || Quality > ITEM_QUALITY_ARTIFACT)
|
||||
return false;
|
||||
|
||||
uint32 level = ItemLevel;
|
||||
if (owner != nullptr)
|
||||
{
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
if (maxItemLevel != 0 && level > maxItemLevel)
|
||||
level = maxItemLevel;
|
||||
}
|
||||
|
||||
DBCStorage<ItemDamageEntry>* store = nullptr;
|
||||
|
||||
switch (InventoryType)
|
||||
{
|
||||
case INVTYPE_AMMO:
|
||||
store = &sItemDamageAmmoStore;
|
||||
break;
|
||||
case INVTYPE_2HWEAPON:
|
||||
if (Flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageTwoHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageTwoHandStore;
|
||||
break;
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
switch (SubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_WAND:
|
||||
store = &sItemDamageWandStore;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
store = &sItemDamageThrownStore;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
store = &sItemDamageRangedStore;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
if (Flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageOneHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageOneHandStore;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!store)
|
||||
return false;
|
||||
|
||||
ItemDamageEntry const* damageInfo = store->LookupEntry(level);
|
||||
if (!damageInfo)
|
||||
return false;
|
||||
|
||||
dps = damageInfo->DPS[Quality];
|
||||
|
||||
float avgDamage = Delay * damageInfo->DPS[Quality] * 0.001f;
|
||||
float scaled_stat = std::floor((StatScalingFactor * 0.5f + 1.0f) * avgDamage + 0.5f);
|
||||
if (Delay != 0 && ArmorDamageModifier != 0.0f)
|
||||
{
|
||||
float invMsDelay = 1000.0f / float(Delay);
|
||||
|
||||
float v16 = (invMsDelay * ((1.0f - (StatScalingFactor * 0.5f)) * avgDamage)) + ArmorDamageModifier;
|
||||
v16 = std::max(v16, 1.0f);
|
||||
|
||||
minValue = (1.0f / invMsDelay) * v16;
|
||||
|
||||
maxValue = (1.0f / invMsDelay) * (((1000.0f / float(Delay)) * scaled_stat) + ArmorDamageModifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxValue = scaled_stat;
|
||||
minValue = (1.0f - (StatScalingFactor * 0.5f)) * avgDamage;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 GetItemScalingModifier(uint32 maxIlvl, ItemQualities quality, InventoryType invType)
|
||||
{
|
||||
// Believe it or not, yes
|
||||
uint32 suffixFactor = -1;
|
||||
switch (invType)
|
||||
{
|
||||
// Items of that type don`t have points
|
||||
case INVTYPE_NON_EQUIP:
|
||||
case INVTYPE_BAG:
|
||||
case INVTYPE_TABARD:
|
||||
case INVTYPE_AMMO:
|
||||
case INVTYPE_QUIVER:
|
||||
case INVTYPE_RELIC:
|
||||
break;
|
||||
// Select point coefficient
|
||||
case INVTYPE_HEAD:
|
||||
case INVTYPE_BODY:
|
||||
case INVTYPE_CHEST:
|
||||
case INVTYPE_LEGS:
|
||||
case INVTYPE_2HWEAPON:
|
||||
case INVTYPE_ROBE:
|
||||
suffixFactor = 0;
|
||||
break;
|
||||
case INVTYPE_SHOULDERS:
|
||||
case INVTYPE_WAIST:
|
||||
case INVTYPE_FEET:
|
||||
case INVTYPE_HANDS:
|
||||
case INVTYPE_TRINKET:
|
||||
suffixFactor = 1;
|
||||
break;
|
||||
case INVTYPE_NECK:
|
||||
case INVTYPE_WRISTS:
|
||||
case INVTYPE_FINGER:
|
||||
case INVTYPE_SHIELD:
|
||||
case INVTYPE_CLOAK:
|
||||
case INVTYPE_HOLDABLE:
|
||||
suffixFactor = 2;
|
||||
break;
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
suffixFactor = 3;
|
||||
break;
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
suffixFactor = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (suffixFactor > 4)
|
||||
return 0;
|
||||
|
||||
RandomPropertiesPointsEntry const* randPropEntry = sRandomPropertiesPointsStore.LookupEntry(maxIlvl);
|
||||
if (!randPropEntry)
|
||||
return 0;
|
||||
|
||||
switch (quality)
|
||||
{
|
||||
case ITEM_QUALITY_UNCOMMON:
|
||||
return randPropEntry->UncommonPropertiesPoints[suffixFactor];
|
||||
case ITEM_QUALITY_RARE:
|
||||
return randPropEntry->RarePropertiesPoints[suffixFactor];
|
||||
case ITEM_QUALITY_EPIC:
|
||||
case ITEM_QUALITY_LEGENDARY:
|
||||
return randPropEntry->EpicPropertiesPoints[suffixFactor];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32 ItemTemplate::GetStatValue(uint32 index, Player* owner /* = nullptr*/) const
|
||||
{
|
||||
if (owner == nullptr)
|
||||
return ItemStat[index].ItemStatValue;
|
||||
|
||||
ScalingStatDistributionEntry const* ssd = ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(ScalingStatDistribution) : nullptr;
|
||||
// req. check at equip, but allow use for extended range if range limit max level, set proper level
|
||||
uint32 ssdLevel = owner->getLevel();
|
||||
|
||||
if (ssd && ssdLevel > ssd->MaxLevel)
|
||||
ssdLevel = ssd->MaxLevel;
|
||||
if (ssd && ssdLevel < ssd->MinLevel)
|
||||
ssdLevel = ssd->MinLevel;
|
||||
if (ssdLevel < 1)
|
||||
ssdLevel = 1;
|
||||
|
||||
ScalingStatValuesEntry const* ssv = ssd ? sScalingStatValuesStore.LookupEntry(ssdLevel) : nullptr;
|
||||
|
||||
uint32 statBaseValue = 0;
|
||||
if (ssd != nullptr && ssv != nullptr)
|
||||
{
|
||||
if (ssd->StatMod[index] < 0)
|
||||
return 0; // What do we do ?
|
||||
|
||||
statBaseValue = ssv->GetStatMultiplier(InventoryType) * ssd->Modifier[index] / 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
statBaseValue = ItemStat[index].ItemStatValue;
|
||||
|
||||
uint32 itemLevel = ItemLevel;
|
||||
uint32 maxItemLevel = owner->GetUInt32Value(UNIT_FIELD_MAXITEMLEVEL);
|
||||
if (!maxItemLevel || maxItemLevel >= itemLevel) // TODO: This might work if >=. Check.
|
||||
return statBaseValue;
|
||||
|
||||
float minScaler = GetItemScalingModifier(ItemLevel, ItemQualities(Quality), ::InventoryType(InventoryType));
|
||||
float maxScaler = GetItemScalingModifier(maxItemLevel, ItemQualities(Quality), ::InventoryType(InventoryType));
|
||||
|
||||
if (maxScaler != 0.0f && minScaler != 0.0f)
|
||||
{
|
||||
float statAllocation = ItemStat[index].ItemStatAllocation * maxScaler * 0.0001f;
|
||||
return std::ceil(statAllocation - ((maxScaler / minScaler) * ItemStat[index].ItemStatSocketCostMultiplier));
|
||||
}
|
||||
}
|
||||
|
||||
return statBaseValue;
|
||||
}
|
||||
|
||||
@@ -1899,7 +1899,7 @@ struct ScalingStatDistributionEntry
|
||||
uint32 Id; // 0
|
||||
int32 StatMod[10]; // 1-10
|
||||
uint32 Modifier[10]; // 11-20
|
||||
//uint32 unk1; // 21
|
||||
uint32 MinLevel; // 21
|
||||
uint32 MaxLevel; // 22 m_maxlevel
|
||||
};
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ char const ResearchBranchEntryfmt[] = "nsiisi";
|
||||
char const ResearchFieldEntryfmt[] = "nsi";
|
||||
char const ResearchProjectEntryfmt[] = "nssiiiisi";
|
||||
char const ResearchSiteEntryfmt[] = "niiss";
|
||||
char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiixi";
|
||||
char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiiii";
|
||||
char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
|
||||
char const SkillLinefmt[] = "nisxixi";
|
||||
char const SkillLineAbilityfmt[] = "niiiixxiiiiiii";
|
||||
|
||||
@@ -613,8 +613,8 @@ struct _ItemStat
|
||||
{
|
||||
uint32 ItemStatType;
|
||||
int32 ItemStatValue;
|
||||
int32 ItemStatUnk1;
|
||||
int32 ItemStatUnk2;
|
||||
int32 ItemStatAllocation;
|
||||
int32 ItemStatSocketCostMultiplier;
|
||||
};
|
||||
|
||||
struct _Spell
|
||||
@@ -706,10 +706,6 @@ struct ItemTemplate
|
||||
uint32 CurrencySubstitutionCount;
|
||||
|
||||
// extra fields, not part of db2 files
|
||||
float DamageMin;
|
||||
float DamageMax;
|
||||
float DPS;
|
||||
uint32 Armor;
|
||||
float SpellPPMRate;
|
||||
uint32 ScriptId;
|
||||
uint32 DisenchantID;
|
||||
@@ -744,6 +740,10 @@ struct ItemTemplate
|
||||
SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
|
||||
SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW;
|
||||
}
|
||||
|
||||
uint32 GetStatValue(uint32 index, Player* owner = nullptr) const;
|
||||
uint32 GetEffectiveArmor(Player * owner) const;
|
||||
bool GetWeaponDamage(Player * owner, float& minValue, float& maxValue, float& dps) const;
|
||||
};
|
||||
|
||||
struct ItemLocale
|
||||
|
||||
@@ -7878,21 +7878,12 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
{
|
||||
uint32 statType = 0;
|
||||
int32 val = 0;
|
||||
int32 val = proto->GetStatValue(i, this);
|
||||
// If set ScalingStatDistribution need get stats and values from it
|
||||
if (ssd && ssv)
|
||||
{
|
||||
if (ssd->StatMod[i] < 0)
|
||||
continue;
|
||||
statType = ssd->StatMod[i];
|
||||
val = (ssv->GetStatMultiplier(proto->InventoryType) * ssd->Modifier[i]) / 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
statType = proto->ItemStat[i].ItemStatType;
|
||||
val = proto->ItemStat[i].ItemStatValue;
|
||||
}
|
||||
if (ssd && ssd->StatMod[i] < 0)
|
||||
continue;
|
||||
|
||||
uint32 statType = proto->ItemStat[i].ItemStatType;
|
||||
|
||||
if (val == 0)
|
||||
continue;
|
||||
@@ -8065,11 +8056,9 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
ApplySpellPowerBonus(spellbonus, apply);
|
||||
|
||||
// If set ScalingStatValue armor get it or use item armor
|
||||
uint32 armor = proto->Armor;
|
||||
uint32 armor = proto->GetEffectiveArmor(this);
|
||||
if (ssv && proto->Class == ITEM_CLASS_ARMOR)
|
||||
armor = ssv->GetArmor(proto->InventoryType, proto->SubClass - 1);
|
||||
else if (armor && proto->ArmorDamageModifier)
|
||||
armor -= uint32(proto->ArmorDamageModifier);
|
||||
|
||||
if (armor)
|
||||
{
|
||||
@@ -8127,8 +8116,8 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt
|
||||
attType = OFF_ATTACK;
|
||||
}
|
||||
|
||||
float minDamage = proto->DamageMin;
|
||||
float maxDamage = proto->DamageMax;
|
||||
float minDamage, maxDamage, dps;
|
||||
proto->GetWeaponDamage(this, minDamage, maxDamage, dps);
|
||||
|
||||
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
|
||||
int32 extraDPS = 0;
|
||||
|
||||
@@ -2795,107 +2795,6 @@ void ObjectMgr::LoadItemLocales()
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u Item locale strings in %u ms", uint32(_itemLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void FillItemDamageFields(float* minDamage, float* maxDamage, float* dps, uint32 itemLevel, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32 delay, float statScalingFactor, uint32 inventoryType, uint32 flags2)
|
||||
{
|
||||
*minDamage = *maxDamage = *dps = 0.0f;
|
||||
if (itemClass != ITEM_CLASS_WEAPON || quality > ITEM_QUALITY_ARTIFACT)
|
||||
return;
|
||||
|
||||
DBCStorage<ItemDamageEntry>* store = nullptr;
|
||||
// get the right store here
|
||||
if (inventoryType > 0xD + 13)
|
||||
return;
|
||||
|
||||
switch (inventoryType)
|
||||
{
|
||||
case INVTYPE_AMMO:
|
||||
store = &sItemDamageAmmoStore;
|
||||
break;
|
||||
case INVTYPE_2HWEAPON:
|
||||
if (flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageTwoHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageTwoHandStore;
|
||||
break;
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
switch (itemSubClass)
|
||||
{
|
||||
case ITEM_SUBCLASS_WEAPON_WAND:
|
||||
store = &sItemDamageWandStore;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_THROWN:
|
||||
store = &sItemDamageThrownStore;
|
||||
break;
|
||||
case ITEM_SUBCLASS_WEAPON_BOW:
|
||||
case ITEM_SUBCLASS_WEAPON_GUN:
|
||||
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
|
||||
store = &sItemDamageRangedStore;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
if (flags2 & ITEM_FLAG2_CASTER_WEAPON)
|
||||
store = &sItemDamageOneHandCasterStore;
|
||||
else
|
||||
store = &sItemDamageOneHandStore;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!store)
|
||||
return;
|
||||
|
||||
ItemDamageEntry const* damageInfo = store->LookupEntry(itemLevel);
|
||||
if (!damageInfo)
|
||||
return;
|
||||
|
||||
*dps = damageInfo->DPS[quality];
|
||||
float avgDamage = *dps * delay * 0.001f;
|
||||
*minDamage = (statScalingFactor * -0.5f + 1.0f) * avgDamage;
|
||||
*maxDamage = floor(float(avgDamage* (statScalingFactor * 0.5f + 1.0f) + 0.5f));
|
||||
}
|
||||
|
||||
uint32 FillItemArmor(uint32 itemlevel, uint32 itemClass, uint32 itemSubclass, uint32 quality, uint32 inventoryType)
|
||||
{
|
||||
if (quality > ITEM_QUALITY_ARTIFACT)
|
||||
return 0;
|
||||
|
||||
// all items but shields
|
||||
if (itemClass != ITEM_CLASS_ARMOR || itemSubclass != ITEM_SUBCLASS_ARMOR_SHIELD)
|
||||
{
|
||||
ItemArmorQualityEntry const* armorQuality = sItemArmorQualityStore.LookupEntry(itemlevel);
|
||||
ItemArmorTotalEntry const* armorTotal = sItemArmorTotalStore.LookupEntry(itemlevel);
|
||||
if (!armorQuality || !armorTotal)
|
||||
return 0;
|
||||
|
||||
if (inventoryType == INVTYPE_ROBE)
|
||||
inventoryType = INVTYPE_CHEST;
|
||||
|
||||
ArmorLocationEntry const* location = sArmorLocationStore.LookupEntry(inventoryType);
|
||||
if (!location)
|
||||
return 0;
|
||||
|
||||
if (itemSubclass < ITEM_SUBCLASS_ARMOR_CLOTH || itemSubclass > ITEM_SUBCLASS_ARMOR_PLATE)
|
||||
return 0;
|
||||
|
||||
return uint32(armorQuality->Value[quality] * armorTotal->Value[itemSubclass - 1] * location->Value[itemSubclass - 1] + 0.5f);
|
||||
}
|
||||
|
||||
// shields
|
||||
ItemArmorShieldEntry const* shield = sItemArmorShieldStore.LookupEntry(itemlevel);
|
||||
if (!shield)
|
||||
return 0;
|
||||
|
||||
return uint32(shield->Value[quality] + 0.5f);
|
||||
}
|
||||
|
||||
uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel)
|
||||
{
|
||||
if (itemClass != ITEM_CLASS_ARMOR && itemClass != ITEM_CLASS_WEAPON)
|
||||
@@ -3068,19 +2967,14 @@ void ObjectMgr::LoadItemTemplates()
|
||||
{
|
||||
itemTemplate.ItemStat[i].ItemStatType = sparse->ItemStatType[i];
|
||||
itemTemplate.ItemStat[i].ItemStatValue = sparse->ItemStatValue[i];
|
||||
itemTemplate.ItemStat[i].ItemStatUnk1 = sparse->ItemStatUnk1[i];
|
||||
itemTemplate.ItemStat[i].ItemStatUnk2 = sparse->ItemStatUnk2[i];
|
||||
itemTemplate.ItemStat[i].ItemStatAllocation = sparse->ItemStatAllocation[i];
|
||||
itemTemplate.ItemStat[i].ItemStatSocketCostMultiplier = sparse->ItemStatSocketCostMultiplier[i];
|
||||
}
|
||||
|
||||
itemTemplate.ScalingStatDistribution = sparse->ScalingStatDistribution;
|
||||
|
||||
// cache item damage
|
||||
FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, sparse->ItemLevel,
|
||||
db2Data->Class, db2Data->SubClass, sparse->Quality, sparse->Delay, sparse->StatScalingFactor,
|
||||
sparse->InventoryType, sparse->Flags2);
|
||||
|
||||
itemTemplate.DamageType = sparse->DamageType;
|
||||
itemTemplate.Armor = FillItemArmor(sparse->ItemLevel, db2Data->Class, db2Data->SubClass, sparse->Quality, sparse->InventoryType);
|
||||
itemTemplate.Delay = sparse->Delay;
|
||||
itemTemplate.RangedModRange = sparse->RangedModRange;
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
@@ -3221,21 +3115,12 @@ void ObjectMgr::LoadItemTemplates()
|
||||
{
|
||||
itemTemplate.ItemStat[i].ItemStatType = uint32(fields[29 + i * 4 + 0].GetUInt8());
|
||||
itemTemplate.ItemStat[i].ItemStatValue = int32(fields[29 + i * 4 + 1].GetInt16());
|
||||
itemTemplate.ItemStat[i].ItemStatUnk1 = fields[29 + i * 4 + 2].GetInt32();
|
||||
itemTemplate.ItemStat[i].ItemStatUnk2 = fields[29 + i * 4 + 3].GetInt32();
|
||||
itemTemplate.ItemStat[i].ItemStatAllocation = fields[29 + i * 4 + 2].GetInt32();
|
||||
itemTemplate.ItemStat[i].ItemStatSocketCostMultiplier = fields[29 + i * 4 + 3].GetInt32();
|
||||
}
|
||||
|
||||
itemTemplate.ScalingStatDistribution = uint32(fields[69].GetUInt16());
|
||||
|
||||
// cache item damage
|
||||
FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, itemTemplate.ItemLevel,
|
||||
itemTemplate.Class, itemTemplate.SubClass, itemTemplate.Quality, fields[71].GetUInt16(),
|
||||
fields[131].GetFloat(), itemTemplate.InventoryType, itemTemplate.Flags2);
|
||||
|
||||
itemTemplate.DamageType = fields[70].GetUInt8();
|
||||
itemTemplate.Armor = FillItemArmor(itemTemplate.ItemLevel, itemTemplate.Class,
|
||||
itemTemplate.SubClass, itemTemplate.Quality,
|
||||
itemTemplate.InventoryType);
|
||||
|
||||
itemTemplate.Delay = fields[71].GetUInt16();
|
||||
itemTemplate.RangedModRange = fields[72].GetFloat();
|
||||
|
||||
Reference in New Issue
Block a user