From 0c036ef4db076db0812aa74fb495a959691aec10 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 10 Sep 2020 19:53:09 -0400 Subject: [PATCH] Core/Spells: Implemented using base weapon damage in spell attack power formulas Port From (https://github.com/TrinityCore/TrinityCore/commit/dd21e7ff404aed1d449b09db2b7fcbe2be8536c3) --- Source/Game/Entities/Item/Item.cs | 2 -- Source/Game/Entities/Item/ItemTemplate.cs | 29 ++++++++++++-------- Source/Game/Entities/Player/Player.Combat.cs | 19 ++++++++++++- Source/Game/Entities/Player/Player.Items.cs | 15 ++-------- Source/Game/Entities/StatSystem.cs | 7 +++-- Source/Game/Entities/TemporarySummon.cs | 2 +- Source/Game/Entities/Unit/Unit.Combat.cs | 18 ++++++++++-- Source/Game/Entities/Unit/Unit.Spells.cs | 10 +++++-- 8 files changed, 67 insertions(+), 35 deletions(-) diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index a2192245b..9a92612d5 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -2514,8 +2514,6 @@ namespace Game.Entities } public uint GetAppearanceModId() { return m_itemData.ItemAppearanceModID; } public void SetAppearanceModId(uint appearanceModId) { SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemAppearanceModID), (byte)appearanceModId); } - public uint GetArmor(Player owner) { return GetTemplate().GetArmor(GetItemLevel(owner)); } - public void GetDamage(Player owner, out float minDamage, out float maxDamage) { GetTemplate().GetDamage(GetItemLevel(owner), out minDamage, out maxDamage); } public float GetRepairCostMultiplier() { return _bonusData.RepairCostMultiplier; } public uint GetScalingStatDistribution() { return _bonusData.ScalingStatDistribution; } diff --git a/Source/Game/Entities/Item/ItemTemplate.cs b/Source/Game/Entities/Item/ItemTemplate.cs index f2cb1b469..e8e928792 100644 --- a/Source/Game/Entities/Item/ItemTemplate.cs +++ b/Source/Game/Entities/Item/ItemTemplate.cs @@ -158,16 +158,11 @@ namespace Game.Entities return (uint)(shield.Quality[(int)quality] + 0.5f); } - public void GetDamage(uint itemLevel, out float minDamage, out float maxDamage) + public float GetDPS(uint itemLevel) { - minDamage = maxDamage = 0.0f; ItemQuality quality = GetQuality() != ItemQuality.Heirloom ? GetQuality() : ItemQuality.Rare; if (GetClass() != ItemClass.Weapon || quality > ItemQuality.Artifact) - return; - - // get the right store here - if (GetInventoryType() > InventoryType.RangedRight) - return; + return 0.0f; float dps = 0.0f; switch (GetInventoryType()) @@ -198,7 +193,7 @@ namespace Game.Entities dps = CliDB.ItemDamageTwoHandStorage.LookupByKey(itemLevel).Quality[(int)quality]; break; default: - return; + break; } break; case InventoryType.Weapon: @@ -210,12 +205,22 @@ namespace Game.Entities dps = CliDB.ItemDamageOneHandStorage.LookupByKey(itemLevel).Quality[(int)quality]; break; default: - return; + break; } - float avgDamage = dps * GetDelay() * 0.001f; - minDamage = (GetDmgVariance() * -0.5f + 1.0f) * avgDamage; - maxDamage = (float)Math.Floor(avgDamage * (GetDmgVariance() * 0.5f + 1.0f) + 0.5f); + return dps; + } + + public void GetDamage(uint itemLevel, out float minDamage, out float maxDamage) + { + minDamage = maxDamage = 0.0f; + float dps = GetDPS(itemLevel); + if (dps > 0.0f) + { + float avgDamage = dps * GetDelay() * 0.001f; + minDamage = (GetDmgVariance() * -0.5f + 1.0f) * avgDamage; + maxDamage = (float)Math.Floor(avgDamage * (GetDmgVariance() * 0.5f + 1.0f) + 0.5f); + } } public bool IsUsableByLootSpecialization(Player player, bool alwaysAllowBoundToAccount) diff --git a/Source/Game/Entities/Player/Player.Combat.cs b/Source/Game/Entities/Player/Player.Combat.cs index 923e451ad..26e2982b2 100644 --- a/Source/Game/Entities/Player/Player.Combat.cs +++ b/Source/Game/Entities/Player/Player.Combat.cs @@ -251,8 +251,9 @@ namespace Game.Entities else if (slot == EquipmentSlot.OffHand) attType = WeaponAttackType.OffAttack; + uint itemLevel = item.GetItemLevel(this); float minDamage, maxDamage; - item.GetDamage(this, out minDamage, out maxDamage); + proto.GetDamage(itemLevel, out minDamage, out maxDamage); if (minDamage > 0) { @@ -270,6 +271,22 @@ namespace Game.Entities if (proto.GetDelay() != 0 && !(shapeshift != null && shapeshift.CombatRoundTime != 0)) SetBaseAttackTime(attType, apply ? proto.GetDelay() : SharedConst.BaseAttackTime); + int weaponBasedAttackPower = apply ? (int)(proto.GetDPS(itemLevel) * 6.0f) : 0; + switch (attType) + { + case WeaponAttackType.BaseAttack: + SetMainHandWeaponAttackPower(weaponBasedAttackPower); + break; + case WeaponAttackType.OffAttack: + SetOffHandWeaponAttackPower(weaponBasedAttackPower); + break; + case WeaponAttackType.RangedAttack: + SetRangedWeaponAttackPower(weaponBasedAttackPower); + break; + default: + break; + } + if (CanModifyStats() && (damage != 0 || proto.GetDelay() != 0)) UpdateDamagePhysical(attType); } diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 7f7d32d3e..6c83d8356 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -4230,21 +4230,12 @@ namespace Game.Entities } } - uint armor = item.GetArmor(this); + uint armor = proto.GetArmor(itemLevel); if (armor != 0) HandleStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, (float)armor, apply); - WeaponAttackType attType = WeaponAttackType.BaseAttack; - if (slot == EquipmentSlot.MainHand && (proto.GetInventoryType() == InventoryType.Ranged || proto.GetInventoryType() == InventoryType.RangedRight)) - { - attType = WeaponAttackType.RangedAttack; - } - else if (slot == EquipmentSlot.OffHand) - { - attType = WeaponAttackType.OffAttack; - } - - if (CanUseAttackType(attType)) + WeaponAttackType attType = GetAttackBySlot(slot, proto.GetInventoryType()); + if (attType != WeaponAttackType.Max && CanUseAttackType(attType)) _ApplyWeaponDamage(slot, item, apply); } diff --git a/Source/Game/Entities/StatSystem.cs b/Source/Game/Entities/StatSystem.cs index 7b6d9a4b0..d80e13299 100644 --- a/Source/Game/Entities/StatSystem.cs +++ b/Source/Game/Entities/StatSystem.cs @@ -709,6 +709,9 @@ namespace Game.Entities public void SetRangedAttackPowerModPos(int attackPowerMod) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedAttackPowerModPos), attackPowerMod); } public void SetRangedAttackPowerModNeg(int attackPowerMod) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedAttackPowerModNeg), attackPowerMod); } public void SetRangedAttackPowerMultiplier(float attackPowerMult) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedAttackPowerMultiplier), attackPowerMult); } + public void SetMainHandWeaponAttackPower(int attackPower) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.MainHandWeaponAttackPower), attackPower); } + public void SetOffHandWeaponAttackPower(int attackPower) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.OffHandWeaponAttackPower), attackPower); } + public void SetRangedWeaponAttackPower(int attackPower) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.RangedWeaponAttackPower), attackPower); } //Chances float MeleeSpellMissChance(Unit victim, WeaponAttackType attType, uint spellId) @@ -1076,7 +1079,7 @@ namespace Game.Entities float attackPowerMod = Math.Max(GetAPMultiplier(attType, normalized), 0.25f); - float baseValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType) / 3.5f * attackPowerMod; + float baseValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType, false) / 3.5f * attackPowerMod; float basePct = GetPctModifierValue(unitMod, UnitModifierPctType.Base); float totalValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total); float totalPct = addTotalPct ? GetPctModifierValue(unitMod, UnitModifierPctType.Total) : 1.0f; @@ -2040,7 +2043,7 @@ namespace Game.Entities weaponMaxDamage = 0.0f; } - float attackPower = GetTotalAttackPowerValue(attType); + float attackPower = GetTotalAttackPowerValue(attType, false); float attackSpeedMulti = Math.Max(GetAPMultiplier(attType, normalized), 0.25f); float baseValue = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + (attackPower / 3.5f) * variance; diff --git a/Source/Game/Entities/TemporarySummon.cs b/Source/Game/Entities/TemporarySummon.cs index 89cdc559c..e86e5b627 100644 --- a/Source/Game/Entities/TemporarySummon.cs +++ b/Source/Game/Entities/TemporarySummon.cs @@ -929,7 +929,7 @@ namespace Game.Entities float att_speed = GetBaseAttackTime(WeaponAttackType.BaseAttack) / 1000.0f; - float base_value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType) / 3.5f * att_speed + bonusDamage; + float base_value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Base) + GetTotalAttackPowerValue(attType, false) / 3.5f * att_speed + bonusDamage; float base_pct = GetPctModifierValue(unitMod, UnitModifierPctType.Base); float total_value = GetFlatModifierValue(unitMod, UnitModifierFlatType.Total); float total_pct = GetPctModifierValue(unitMod, UnitModifierPctType.Total); diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index adaec067d..6ed338eb7 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -2253,18 +2253,30 @@ namespace Game.Entities return weapon.GetTemplate().GetDelay() / 1000.0f; } } - public float GetTotalAttackPowerValue(WeaponAttackType attType) + public float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon = true) { if (attType == WeaponAttackType.RangedAttack) { - int ap = m_unitData.RangedAttackPower; + float ap = m_unitData.RangedAttackPower + m_unitData.RangedAttackPowerModPos + m_unitData.RangedAttackPowerModNeg; + if (includeWeapon) + ap += Math.Max(m_unitData.MainHandWeaponAttackPower, m_unitData.RangedWeaponAttackPower); if (ap < 0) return 0.0f; return ap * (1.0f + m_unitData.RangedAttackPowerMultiplier); } else { - int ap = m_unitData.AttackPower; + float ap = m_unitData.AttackPower + m_unitData.AttackPowerModPos + m_unitData.AttackPowerModNeg; + if (includeWeapon) + { + if (attType == WeaponAttackType.BaseAttack) + ap += Math.Max(m_unitData.MainHandWeaponAttackPower, m_unitData.RangedWeaponAttackPower); + else + { + ap += m_unitData.OffHandWeaponAttackPower; + ap /= 2; + } + } if (ap < 0) return 0.0f; return ap * (1.0f + m_unitData.AttackPowerMultiplier); diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 232eedf00..8e91b9fba 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -128,8 +128,14 @@ namespace Game.Entities ApCoeffMod /= 100.0f; } - WeaponAttackType attType = (spellProto.IsRangedWeaponSpell() && spellProto.DmgClass != SpellDmgClass.Melee) ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack; - float APbonus = victim.GetTotalAuraModifier(attType == WeaponAttackType.BaseAttack ? AuraType.MeleeAttackPowerAttackerBonus : AuraType.RangedAttackPowerAttackerBonus); + WeaponAttackType attType = WeaponAttackType.BaseAttack; + if ((spellProto.IsRangedWeaponSpell() && spellProto.DmgClass != SpellDmgClass.Melee)) + attType = WeaponAttackType.RangedAttack; + + if (spellProto.HasAttribute(SpellAttr3.ReqOffhand) && !spellProto.HasAttribute(SpellAttr3.MainHand)) + attType = WeaponAttackType.OffAttack; + + float APbonus = (float)(victim.GetTotalAuraModifier(attType != WeaponAttackType.RangedAttack ? AuraType.MeleeAttackPowerAttackerBonus : AuraType.RangedAttackPowerAttackerBonus)); APbonus += GetTotalAttackPowerValue(attType); DoneTotal += (int)(stack * ApCoeffMod * APbonus); }