diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index 04c934e72..914ba0a6e 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -793,6 +793,16 @@ namespace Framework.Constants CorruptedLoot = 19 } + public enum AvgItemLevelCategory + { + Base = 0, + EquippedBase = 1, + EquippedEffective = 2, + Pvp = 3, + PvpWeighted = 4, + EquippedEffectiveWeighted = 5 + } + [Flags] public enum CurrencyDbFlags { diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 7af141495..13b2ea30e 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -2915,11 +2915,11 @@ namespace Game.Entities int scalingLevelMax = m_unitData.ScalingLevelMax; int scalingLevelDelta = m_unitData.ScalingLevelDelta; int scalingFactionGroup = m_unitData.ScalingFactionGroup; - int targetLevel = unitTarget.m_unitData.EffectiveLevel; + uint targetLevel = unitTarget.m_unitData.EffectiveLevel; if (targetLevel == 0) - targetLevel = (int)unitTarget.GetLevel(); + targetLevel = unitTarget.GetLevel(); - int targetLevelDelta = 0; + uint targetLevelDelta = 0; Player playerTarget = target.ToPlayer(); if (playerTarget != null) @@ -2928,10 +2928,10 @@ namespace Game.Entities scalingLevelMin = scalingLevelMax; int maxCreatureScalingLevel = playerTarget.m_activePlayerData.MaxCreatureScalingLevel; - targetLevelDelta = Math.Min(maxCreatureScalingLevel > 0 ? maxCreatureScalingLevel - targetLevel : 0, playerTarget.m_activePlayerData.ScalingPlayerLevelDelta); + targetLevelDelta = (uint)Math.Min(maxCreatureScalingLevel > 0 ? maxCreatureScalingLevel - targetLevel : 0, playerTarget.m_activePlayerData.ScalingPlayerLevelDelta); } - int levelWithDelta = targetLevel + targetLevelDelta; + int levelWithDelta = (int)(targetLevel + targetLevelDelta); int level = MathFunctions.RoundToInterval(ref levelWithDelta, scalingLevelMin, scalingLevelMax) + scalingLevelDelta; return (uint)MathFunctions.RoundToInterval(ref level, 1, SharedConst.MaxLevel + 3); } diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 4f2ca0e88..2eb0dcc77 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -1791,8 +1791,8 @@ namespace Game.Entities ItemTemplate itemTemplate = GetTemplate(); uint minItemLevel = owner.m_unitData.MinItemLevel; uint minItemLevelCutoff = owner.m_unitData.MinItemLevelCutoff; - uint maxItemLevel = itemTemplate.HasFlag(ItemFlags3.IgnoreItemLevelCapInPvp) ? 0u : owner.m_unitData.MaxItemLevel; bool pvpBonus = owner.IsUsingPvpItemLevels(); + uint maxItemLevel = pvpBonus && itemTemplate.HasFlag(ItemFlags3.IgnoreItemLevelCapInPvp) ? 0u : owner.m_unitData.MaxItemLevel; uint azeriteLevel = 0; AzeriteItem azeriteItem = ToAzeriteItem(); diff --git a/Source/Game/Entities/Object/Update/UpdateFields.cs b/Source/Game/Entities/Object/Update/UpdateFields.cs index b74177bd5..0d505bce1 100644 --- a/Source/Game/Entities/Object/Update/UpdateFields.cs +++ b/Source/Game/Entities/Object/Update/UpdateFields.cs @@ -1165,7 +1165,7 @@ namespace Game.Entities public UpdateField Health = new(0, 31); public UpdateField MaxHealth = new(32, 33); public UpdateField Level = new(32, 34); - public UpdateField EffectiveLevel = new(32, 35); + public UpdateField EffectiveLevel = new(32, 35); public UpdateField ContentTuningID = new(32, 36); public UpdateField ScalingLevelMin = new(32, 37); public UpdateField ScalingLevelMax = new(32, 38); @@ -1325,7 +1325,7 @@ namespace Game.Entities } data.WriteUInt64(MaxHealth); data.WriteUInt32(Level); - data.WriteInt32(EffectiveLevel); + data.WriteUInt32(EffectiveLevel); data.WriteUInt32(ContentTuningID); data.WriteInt32(ScalingLevelMin); data.WriteInt32(ScalingLevelMax); @@ -1691,7 +1691,7 @@ namespace Game.Entities } if (changesMask[35]) { - data.WriteInt32(EffectiveLevel); + data.WriteUInt32(EffectiveLevel); } if (changesMask[36]) { diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 05e76f0f3..620846c36 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -6551,7 +6551,7 @@ namespace Game.Entities public void UpdateAverageItemLevelTotal() { - (InventoryType inventoryType, uint itemLevel, ObjectGuid guid)[] bestItemLevels = new (InventoryType inventoryType, uint itemLevel, ObjectGuid guid)[EquipmentSlot.End]; + var bestItemLevels = new (InventoryType inventoryType, uint itemLevel, ObjectGuid guid)[EquipmentSlot.End]; float sum = 0; ForEachItem(ItemSearchLocation.Everywhere, item => @@ -6602,26 +6602,40 @@ namespace Game.Entities sum += mainHand.itemLevel; sum /= 16.0f; - SetAverageItemLevelTotal(sum); + SetAverageItemLevel(sum, AvgItemLevelCategory.Base); } public void UpdateAverageItemLevelEquipped() { float totalItemLevel = 0; + float totalItemLevelEffective = 0; for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; i++) { Item item = GetItemByPos(InventorySlots.Bag0, i); if (item != null) { - uint itemLevel = item.GetItemLevel(this); + uint azeriteLevel = 0; + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + azeriteLevel = azeriteItem.GetEffectiveLevel(); + + uint itemLevel = Item.GetItemLevel(item.GetTemplate(), item.GetBonus(), GetLevel(), item.GetModifier(ItemModifier.TimewalkerLevel), 0, 0, 0, false, azeriteLevel); + uint itemLevelEffective = Item.GetItemLevel(item.GetTemplate(), item.GetBonus(), GetEffectiveLevel(), item.GetModifier(ItemModifier.TimewalkerLevel), m_unitData.MinItemLevel, + m_unitData.MinItemLevelCutoff, IsUsingPvpItemLevels() && item.GetTemplate().HasFlag(ItemFlags3.IgnoreItemLevelCapInPvp) ? 0 : m_unitData.MaxItemLevel, IsUsingPvpItemLevels(), azeriteLevel); totalItemLevel += itemLevel; + totalItemLevelEffective += itemLevelEffective; if (!m_canTitanGrip && i == EquipmentSlot.MainHand && item.GetTemplate().GetInventoryType() == InventoryType.Weapon2Hand) // 2h weapon counts twice + { totalItemLevel += itemLevel; + totalItemLevelEffective += itemLevelEffective; + } } } totalItemLevel /= 16.0f; - SetAverageItemLevelEquipped(totalItemLevel); + totalItemLevelEffective /= 16.0f; + SetAverageItemLevel(totalItemLevel, AvgItemLevelCategory.EquippedBase); + SetAverageItemLevel(totalItemLevelEffective, AvgItemLevelCategory.EquippedEffective); } } } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 85294077f..f9b268ced 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -7670,8 +7670,7 @@ namespace Game.Entities public void RemovePlayerFlagEx(PlayerFlagsEx flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.PlayerFlagsEx), (uint)flags); } public void ReplaceAllPlayerFlagsEx(PlayerFlagsEx flags) { SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.PlayerFlagsEx), (uint)flags); } - public void SetAverageItemLevelTotal(float newItemLevel) { SetUpdateFieldValue(ref m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.AvgItemLevel, 0), newItemLevel); } - public void SetAverageItemLevelEquipped(float newItemLevel) { SetUpdateFieldValue(ref m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.AvgItemLevel, 1), newItemLevel); } + public void SetAverageItemLevel(float newItemLevel, AvgItemLevelCategory category) { SetUpdateFieldValue(ref m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.AvgItemLevel, (int)category), newItemLevel); } public uint GetCustomizationChoice(uint chrCustomizationOptionId) { diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 8daae10b7..8d1a7b658 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1921,7 +1921,11 @@ namespace Game.Entities Global.CharacterCacheStorage.UpdateCharacterLevel(ToPlayer().GetGUID(), (byte)lvl); } } + public uint GetLevel() { return m_unitData.Level; } + + public byte GetEffectiveLevel() { return (byte)(m_unitData.EffectiveLevel != 0 ? m_unitData.EffectiveLevel : m_unitData.Level); } + public override uint GetLevelForTarget(WorldObject target) { return GetLevel(); } public Race GetRace() { return (Race)(byte)m_unitData.Race; }