Skip to content

Commit a6b976b

Browse files
authored
Add basic support to show skill PvP scaling (#4664)
* initial HoGM scaling implementation * move totaldps breakdown * spelling fix
1 parent f63f9d4 commit a6b976b

File tree

5 files changed

+138
-0
lines changed

5 files changed

+138
-0
lines changed

src/Modules/Build.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild)
267267
self.displayStats = {
268268
{ stat = "ActiveMinionLimit", label = "Active Minion Limit", fmt = "d" },
269269
{ stat = "AverageHit", label = "Average Hit", fmt = ".1f", compPercent = true },
270+
{ stat = "PvpAverageHit", label = "PvP Average Hit", fmt = ".1f", compPercent = true, flag = "isPvP" },
270271
{ stat = "AverageDamage", label = "Average Damage", fmt = ".1f", compPercent = true, flag = "attack" },
272+
{ stat = "PvpAverageDamage", label = "PvP Average Damage", fmt = ".1f", compPercent = true, flag = "attackPvP" },
271273
{ stat = "Speed", label = "Attack Rate", fmt = ".2f", compPercent = true, flag = "attack", condFunc = function(v,o) return v > 0 and (o.TriggerTime or 0) == 0 end },
272274
{ stat = "Speed", label = "Cast Rate", fmt = ".2f", compPercent = true, flag = "spell", condFunc = function(v,o) return v > 0 and (o.TriggerTime or 0) == 0 end },
273275
{ stat = "ServerTriggerRate", label = "Trigger Rate", fmt = ".2f", compPercent = true, condFunc = function(v,o) return (o.TriggerTime or 0) ~= 0 end },
@@ -283,6 +285,7 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild)
283285
{ stat = "CritMultiplier", label = "Crit Multiplier", fmt = "d%%", pc = true, condFunc = function(v,o) return (o.CritChance or 0) > 0 end },
284286
{ stat = "HitChance", label = "Hit Chance", fmt = ".0f%%", flag = "attack" },
285287
{ stat = "TotalDPS", label = "Total DPS", fmt = ".1f", compPercent = true, flag = "notAverage" },
288+
{ stat = "PvpTotalDPS", label = "PvP Total DPS", fmt = ".1f", compPercent = true, flag = "notAveragePvP" },
286289
{ stat = "TotalDPS", label = "Total DPS", fmt = ".1f", compPercent = true, flag = "showAverage", condFunc = function(v,o) return (o.TriggerTime or 0) ~= 0 end },
287290
{ stat = "TotalDot", label = "DoT DPS", fmt = ".1f", compPercent = true },
288291
{ stat = "WithDotDPS", label = "Total DPS inc. DoT", fmt = ".1f", compPercent = true, flag = "notAverage", condFunc = function(v,o) return v ~= o.TotalDPS and (o.PoisonDPS or 0) == 0 and (o.IgniteDPS or 0) == 0 and (o.ImpaleDPS or 0) == 0 and (o.BleedDPS or 0) == 0 end },

src/Modules/CalcOffence.lua

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,85 @@ function calcs.offence(env, actor, activeSkill)
25602560
t_insert(breakdown.AverageDamage, s_format("= %.1f", output.AverageDamage))
25612561
end
25622562
end
2563+
2564+
2565+
-- Calculate PvP values
2566+
2567+
--setup flags
2568+
skillFlags.isPvP = false
2569+
skillFlags.notAttackPvP = false
2570+
skillFlags.attackPvP = false
2571+
skillFlags.weapon1AttackPvP = false
2572+
skillFlags.weapon2AttackPvP = false
2573+
skillFlags.notAveragePvP = false
2574+
2575+
if env.configInput.PvpScaling then
2576+
skillFlags.isPvP = true
2577+
skillFlags.attackPvP = skillFlags.attack
2578+
skillFlags.notAttackPvP = not skillFlags.attack
2579+
skillFlags.weapon1AttackPvP = skillFlags.weapon1Attack
2580+
skillFlags.weapon2AttackPvP = skillFlags.weapon2Attack
2581+
skillFlags.notAveragePvP = skillFlags.notAverage
2582+
local PvpTvalue = env.configInput.multiplierPvpTvalueOverride or nil
2583+
if PvpTvalue then
2584+
PvpTvalue = PvpTvalue / 1000
2585+
else
2586+
if skillFlags.mine then
2587+
PvpTvalue = output.MineLayingTime*globalOutput.ActionSpeedMod
2588+
elseif skillFlags.trap then
2589+
PvpTvalue = output.TrapThrowingTime*globalOutput.ActionSpeedMod
2590+
else
2591+
PvpTvalue = 1/((globalOutput.HitSpeed or globalOutput.Speed)/globalOutput.ActionSpeedMod)
2592+
end
2593+
if PvpTvalue > 2147483647 then
2594+
PvpTvalue = 1
2595+
end
2596+
end
2597+
local PvpMultiplier = (env.configInput.multiplierPvpDamage or 100) / 100
2598+
2599+
local PvpNonElemental1 = data.misc.PvpNonElemental1
2600+
local PvpNonElemental2 = data.misc.PvpNonElemental2
2601+
local PvpElemental1 = data.misc.PvpElemental1
2602+
local PvpElemental2 = data.misc.PvpElemental2
2603+
2604+
local percentageNonElemental = ((output["PhysicalHitAverage"] + output["ChaosHitAverage"]) / (totalHitMin + totalHitMax) * 2)
2605+
local percentageElemental = 1 - percentageNonElemental
2606+
local portionNonElemental = (output.AverageHit / PvpTvalue / PvpNonElemental2 ) ^ PvpNonElemental1 * PvpTvalue * PvpNonElemental2 * percentageNonElemental
2607+
local portionElemental = (output.AverageHit / PvpTvalue / PvpElemental2 ) ^ PvpElemental1 * PvpTvalue * PvpElemental2 * percentageElemental
2608+
output.PvpAverageHit = (portionNonElemental + portionElemental) * PvpMultiplier
2609+
output.PvpAverageDamage = output.PvpAverageHit * output.HitChance / 100
2610+
output.PvpTotalDPS = output.PvpAverageDamage * (globalOutput.HitSpeed or globalOutput.Speed) * (skillData.dpsMultiplier or 1)
2611+
2612+
-- fix for these being nan
2613+
if output.PvpAverageHit ~= output.PvpAverageHit then
2614+
output.PvpAverageHit = 0
2615+
end
2616+
if output.PvpAverageDamage ~= output.PvpAverageDamage then
2617+
output.PvpAverageDamage = 0
2618+
end
2619+
if output.PvpTotalDPS ~= output.PvpTotalDPS then
2620+
output.PvpTotalDPS = 0
2621+
end
2622+
2623+
if breakdown then
2624+
breakdown.PvpAverageHit = { }
2625+
t_insert(breakdown.PvpAverageHit, s_format("Pvp Formula is (D/(T*M))^E*T*M*P, where D is the damage, T is the time taken," ))
2626+
t_insert(breakdown.PvpAverageHit, s_format("M is the multiplier, E is the exponent and P is the percentage of that type (ele or non ele)"))
2627+
t_insert(breakdown.PvpAverageHit, s_format("(M=%.1f for ele and %.1f for non-ele)(E=%.2f for ele and %.2f for non-ele)", PvpElemental2, PvpNonElemental2, PvpElemental1, PvpNonElemental1))
2628+
t_insert(breakdown.PvpAverageHit, s_format("(%.1f / (%.2f * %.1f)) ^ %.2f * %.2f * %.1f * %.2f = %.1f", output.AverageHit, PvpTvalue, PvpNonElemental2, PvpNonElemental1, PvpTvalue, PvpNonElemental2, percentageNonElemental, portionNonElemental))
2629+
t_insert(breakdown.PvpAverageHit, s_format("(%.1f / (%.2f * %.1f)) ^ %.2f * %.2f * %.1f * %.2f = %.1f", output.AverageHit, PvpTvalue, PvpElemental2, PvpElemental1, PvpTvalue, PvpElemental2, percentageElemental, portionElemental))
2630+
t_insert(breakdown.PvpAverageHit, s_format("(portionNonElemental + portionElemental) * PvP multiplier"))
2631+
t_insert(breakdown.PvpAverageHit, s_format("(%.1f + %.1f) * %.1f", portionNonElemental, portionElemental, PvpMultiplier))
2632+
t_insert(breakdown.PvpAverageHit, s_format("= %.1f", output.PvpAverageHit))
2633+
if isAttack then
2634+
breakdown.PvpAverageDamage = { }
2635+
t_insert(breakdown.PvpAverageDamage, s_format("%s:", pass.label))
2636+
t_insert(breakdown.PvpAverageDamage, s_format("%.1f ^8(average pvp hit)", output.PvpAverageHit))
2637+
t_insert(breakdown.PvpAverageDamage, s_format("x %.2f ^8(chance to hit)", output.HitChance / 100))
2638+
t_insert(breakdown.PvpAverageDamage, s_format("= %.1f", output.PvpAverageDamage))
2639+
end
2640+
end
2641+
end
25632642
end
25642643

25652644
if isAttack then
@@ -2568,7 +2647,9 @@ function calcs.offence(env, actor, activeSkill)
25682647
combineStat("CritChance", "AVERAGE")
25692648
combineStat("CritMultiplier", "AVERAGE")
25702649
combineStat("AverageDamage", "DPS")
2650+
combineStat("PvpAverageDamage", "DPS")
25712651
combineStat("TotalDPS", "DPS")
2652+
combineStat("PvpTotalDPS", "DPS")
25722653
combineStat("LifeLeechDuration", "DPS")
25732654
combineStat("LifeLeechInstances", "DPS")
25742655
combineStat("LifeLeechInstant", "DPS")
@@ -2597,6 +2678,16 @@ function calcs.offence(env, actor, activeSkill)
25972678
t_insert(breakdown.AverageDamage, s_format("(%.1f + %.1f) / 2 ^8(skill alternates weapons)", output.MainHand.AverageDamage, output.OffHand.AverageDamage))
25982679
end
25992680
t_insert(breakdown.AverageDamage, s_format("= %.1f", output.AverageDamage))
2681+
if skillFlags.isPvP then
2682+
breakdown.PvpAverageDamage = { }
2683+
t_insert(breakdown.PvpAverageDamage, "Both weapons:")
2684+
if skillData.doubleHitsWhenDualWielding then
2685+
t_insert(breakdown.PvpAverageDamage, s_format("%.1f + %.1f ^8(skill hits with both weapons at once)", output.MainHand.PvpAverageDamage, output.OffHand.PvpAverageDamage))
2686+
else
2687+
t_insert(breakdown.PvpAverageDamage, s_format("(%.1f + %.1f) / 2 ^8(skill alternates weapons)", output.MainHand.PvpAverageDamage, output.OffHand.PvpAverageDamage))
2688+
end
2689+
t_insert(breakdown.PvpAverageDamage, s_format("= %.1f", output.PvpAverageDamage))
2690+
end
26002691
end
26012692
end
26022693
end
@@ -2631,6 +2722,25 @@ function calcs.offence(env, actor, activeSkill)
26312722
t_insert(breakdown.TotalDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier))
26322723
end
26332724
t_insert(breakdown.TotalDPS, s_format("= %.1f", output.TotalDPS))
2725+
if skillFlags.isPvP then
2726+
local rateType = "cast"
2727+
if isAttack then
2728+
rateType = "attack"
2729+
elseif isTriggered then
2730+
rateType = "trigger"
2731+
end
2732+
breakdown.PvpTotalDPS = {
2733+
s_format("%.1f ^8(average pvp hit)", output.PvpAverageDamage),
2734+
output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(%s rate)", output.Speed, rateType),
2735+
}
2736+
if skillData.dpsMultiplier then
2737+
t_insert(breakdown.PvpTotalDPS, s_format("x %g ^8(DPS multiplier for this skill)", skillData.dpsMultiplier))
2738+
end
2739+
if quantityMultiplier > 1 then
2740+
t_insert(breakdown.PvpTotalDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier))
2741+
end
2742+
t_insert(breakdown.PvpTotalDPS, s_format("= %.1f", output.PvpTotalDPS))
2743+
end
26342744
end
26352745

26362746
-- Calculate leech rates

src/Modules/CalcSections.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ return {
168168
},
169169
},
170170
{ label = "Skill Average Hit", notFlag = "attack", { format = "{1:output:AverageHit}", { breakdown = "AverageHit" }, }, },
171+
{ label = "Skill PvP Average Hit", flag = "notAttackPvP", { format = "{1:output:PvpAverageHit}", { breakdown = "PvpAverageHit" }, }, },
171172
-- Main Hand Hit Damage
172173
{ label = "MH Total Increased", bgCol = colorCodes.MAINHANDBG, flag = "weapon1Attack",
173174
{ format = "{0:mod:1}%", { modName = "Damage", modType = "INC", cfg = "weapon1" }, },
@@ -235,6 +236,7 @@ return {
235236
},
236237
},
237238
{ label = "MH Average Hit", bgCol = colorCodes.MAINHANDBG, flag = "weapon1Attack", { format = "{1:output:MainHand.AverageHit}", { breakdown = "MainHand.AverageHit" }, }, },
239+
{ label = "MH PvP Average Hit", bgCol = colorCodes.MAINHANDBG, flag = "weapon1AttackPvP", { format = "{1:output:MainHand.PvpAverageHit}", { breakdown = "MainHand.PvpAverageHit" }, }, },
238240
-- Off Hand Hit Damage
239241
{ label = "OH Total Increased", bgCol = colorCodes.OFFHANDBG, flag = "weapon2Attack",
240242
{ format = "{0:mod:1}%", { modName = "Damage", modType = "INC", cfg = "weapon2" }, },
@@ -302,12 +304,19 @@ return {
302304
},
303305
},
304306
{ label = "OH Average Hit", bgCol = colorCodes.OFFHANDBG, flag = "weapon2Attack", { format = "{1:output:OffHand.AverageHit}", { breakdown = "OffHand.AverageHit" }, }, },
307+
{ label = "OH PvP Average Hit", bgCol = colorCodes.OFFHANDBG, flag = "weapon2AttackPvP", { format = "{1:output:OffHand.PvpAverageHit}", { breakdown = "OffHand.PvpAverageHit" }, }, },
305308
{ label = "Average Damage", flag = "attack", { format = "{1:output:AverageDamage}",
306309
{ breakdown = "MainHand.AverageDamage" },
307310
{ breakdown = "OffHand.AverageDamage" },
308311
{ breakdown = "AverageDamage" },
309312
}, },
313+
{ label = "PvP Average Dmg", flag = "attackPvP", { format = "{1:output:PvpAverageDamage}",
314+
{ breakdown = "MainHand.PvpAverageDamage" },
315+
{ breakdown = "OffHand.PvpAverageDamage" },
316+
{ breakdown = "PvpAverageDamage" },
317+
}, },
310318
{ label = "Skill DPS", flag = "notAverage", notFlag = "triggered", { format = "{1:output:TotalDPS}", { breakdown = "TotalDPS" }, }, },
319+
{ label = "Skill PvP DPS", flag = "notAveragePvP", { format = "{1:output:PvpTotalDPS}", { breakdown = "PvpTotalDPS" }, }, },
311320
{ label = "Skill DPS", flag = "triggered", { format = "{1:output:TotalDPS}", { breakdown = "TotalDPS" }, }, },
312321
} }
313322
} },

src/Modules/ConfigOptions.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ return {
532532
{ var = "multiplierSextant", type = "count", label = "# of Sextants affecting the area", ifMult = "Sextant", apply = function(val, modList, enemyModList)
533533
modList:NewMod("Multiplier:Sextant", "BASE", m_min(val, 5), "Config")
534534
end },
535+
{ label = "Unique Map Modifiers:" },
536+
{ var = "PvpScaling", type = "check", label = "PvP damage scaling in effect", tooltip = "'Hall of Grandmasters'", apply = function(val, modList, enemyModList)
537+
modList:NewMod("HasPvpScaling", "FLAG", true, "Config")
538+
end },
535539
{ label = "Player is cursed by:" },
536540
{ var = "playerCursedWithAssassinsMark", type = "count", label = "Assassin's Mark:", tooltip = "Sets the level of Assassin's Mark to apply to the player.", apply = function(val, modList, enemyModList)
537541
modList:NewMod("ExtraCurse", "LIST", { skillId = "AssassinsMark", level = val, applyToPlayer = true })
@@ -1154,6 +1158,12 @@ return {
11541158
{ var = "buffFanaticism", type = "check", label = "Do you have Fanaticism?", ifFlag = "Condition:CanGainFanaticism", tooltip = "This will enable the Fanaticism buff itself. (Grants 75% more cast speed, reduced ^x7070FFmana ^7cost, and increased area of effect)", apply = function(val, modList, enemyModList)
11551159
modList:NewMod("Condition:Fanaticism", "FLAG", true, "Config", { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanGainFanaticism" })
11561160
end },
1161+
{ var = "multiplierPvpTvalueOverride", type = "count", label = "PvP Tvalue override (ms):", ifFlag = "isPvP", tooltip = "Tvalue in milliseconds. This overrides the Tvalue of a given skill, for instance any with fixed tvalues or for traps/mines until those are supported", apply = function(val, modList, enemyModList)
1162+
modList:NewMod("Multiplier:PvpTvalueOverride", "BASE", val, "Config", { type = "Condition", var = "Combat" })
1163+
end },
1164+
{ var = "multiplierPvpDamage", type = "count", label = "Custom PvP Damage multiplier percent:", ifFlag = "isPvP", tooltip = "This multiplies the damage of a given skill in pvp, for instance any with damage multiplier specific to pvp (from skill or support or item like sire of shards)", apply = function(val, modList, enemyModList)
1165+
modList:NewMod("Multiplier:PvpDamage", "BASE", val, "Config", { type = "Condition", var = "Combat" })
1166+
end },
11571167
-- Section: Effective DPS options
11581168
{ section = "For Effective DPS", col = 1 },
11591169
{ var = "critChanceLucky", type = "check", label = "Is your Crit Chance Lucky?", apply = function(val, modList, enemyModList)

src/Modules/Data.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,12 @@ data.misc = { -- magic numbers
398398
ehpCalcMaxDepth = 512,
399399
-- max hits is currently depth + speedup - 1 to give as much accuracy with as few cycles as possible, but can be increased for more accuracy
400400
ehpCalcMaxHitsToCalc = 519,
401+
-- PvP scaling used for hogm
402+
PvpElemental1 = 0.55,
403+
PvpElemental2 = 150,
404+
PvpNonElemental1 = 0.57,
405+
PvpNonElemental2 = 90,
406+
401407
}
402408

403409
data.bossSkills = {

0 commit comments

Comments
 (0)