Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add warnings if skill cost exceeds avilable resource #5019

Merged
merged 13 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions src/Modules/Build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -318,19 +318,19 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild)
{ stat = "AreaOfEffectRadius", label = "AoE Radius", fmt = "d" },
{ stat = "BrandAttachmentRange", label = "Attachment Range", fmt = "d", flag = "brand" },
{ stat = "BrandTicks", label = "Activations per Brand", fmt = "d", flag = "brand" },
{ stat = "ManaCost", label = "Mana Cost", fmt = "d", color = colorCodes.MANA, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaHasCost end },
{ stat = "ManaPercentCost", label = "Mana Cost", fmt = "d%%", color = colorCodes.MANA, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPercentHasCost end },
{ stat = "ManaPerSecondCost", label = "Mana Cost per second", fmt = ".2f", color = colorCodes.MANA, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPerSecondHasCost end },
{ stat = "ManaPercentPerSecondCost", label = "Mana Cost per second", fmt = ".2f%%", color = colorCodes.MANA, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPercentPerSecondHasCost end },
{ stat = "LifeCost", label = "Life Cost", fmt = "d", color = colorCodes.LIFE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifeHasCost end },
{ stat = "LifePercentCost", label = "Life Cost", fmt = "d%%", color = colorCodes.LIFE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePercentHasCost end },
{ stat = "LifePerSecondCost", label = "Life Cost per second", fmt = ".2f", color = colorCodes.LIFE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePerSecondHasCost end },
{ stat = "LifePercentPerSecondCost", label = "Life Cost per second", fmt = ".2f%%", color = colorCodes.LIFE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePercentPerSecondHasCost end },
{ stat = "ESCost", label = "Energy Shield Cost", fmt = "d", color = colorCodes.ES, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ESHasCost end },
{ stat = "RageCost", label = "Rage Cost", fmt = "d", color = colorCodes.RAGE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.RageHasCost end },
{ stat = "RagePerSecondCost", label = "Rage Cost per second", fmt = ".2f", color = colorCodes.RAGE, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.RagePerSecondHasCost end },
{ stat = "ESPerSecondCost", label = "ES Cost per second", fmt = ".2f", color = colorCodes.ES, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ESPerSecondHasCost end },
{ stat = "ManaCost", label = "Mana Cost", fmt = "d", color = colorCodes.MANA, pool = "ManaUnreserved", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaHasCost end },
{ stat = "ManaPercentCost", label = "Mana Cost", fmt = "d%%", color = colorCodes.MANA, pool = "ManaUnreservedPercent", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPercentHasCost end },
{ stat = "ManaPerSecondCost", label = "Mana Cost", fmt = ".2f/s", color = colorCodes.MANA, pool = "ManaUnreserved", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPerSecondHasCost end },
{ stat = "ManaPercentPerSecondCost", label = "Mana Cost", fmt = ".2f%%/s", color = colorCodes.MANA, pool = "ManaUnreservedPercent", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPercentPerSecondHasCost end },
{ stat = "LifeCost", label = "Life Cost", fmt = "d", color = colorCodes.LIFE, pool = "LifeUnreserved", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifeHasCost end },
{ stat = "LifePercentCost", label = "Life Cost", fmt = "d%%", color = colorCodes.LIFE, pool = "LifeUnreservedPercent", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePercentHasCost end },
{ stat = "LifePerSecondCost", label = "Life Cost", fmt = ".2f/s", color = colorCodes.LIFE, pool = "LifeUnreserved", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePerSecondHasCost end },
{ stat = "LifePercentPerSecondCost", label = "Life Cost", fmt = ".2f%%/s", color = colorCodes.LIFE, pool = "LifeUnreservedPercent", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.LifePercentPerSecondHasCost end },
{ stat = "ESCost", label = "Energy Shield Cost", fmt = "d", color = colorCodes.ES, pool = "EnergyShield", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ESHasCost end },
{ stat = "ESPerSecondCost", label = "ES Cost per second", fmt = ".2f", color = colorCodes.ES, pool = "EnergyShield", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ESPerSecondHasCost end },
{ stat = "ESPercentPerSecondCost", label = "ES Cost per second", fmt = ".2f%%", color = colorCodes.ES, compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ESPercentPerSecondHasCost end },
{ stat = "RageCost", label = "Rage Cost", fmt = "d", color = colorCodes.RAGE, pool = "Rage", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.RageHasCost end },
{ stat = "RagePerSecondCost", label = "Rage Cost per second", fmt = ".2f", color = colorCodes.RAGE, pool = "Rage", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.RagePerSecondHasCost end },
{ },
{ stat = "Str", label = "Strength", color = colorCodes.STRENGTH, fmt = "d" },
{ stat = "ReqStr", label = "Strength Required", color = colorCodes.STRENGTH, fmt = "d", lowerIsBetter = true, condFunc = function(v,o) return v > o.Str end, warnFunc = function(v) return "You do not meet the Strength requirement" end },
Expand Down Expand Up @@ -1263,13 +1263,14 @@ function buildMode:RefreshSkillSelectControls(controls, mainGroup, suffix)
end
end

function buildMode:FormatStat(statData, statVal, overCapStatVal)
function buildMode:FormatStat(statData, statVal, overCapStatVal, colorOverride)
if type(statVal) == "table" then return "" end
local val = statVal * ((statData.pc or statData.mod) and 100 or 1) - (statData.mod and 100 or 0)
local color = (statVal >= 0 and "^7" or statData.chaosInoc and "^8" or colorCodes.NEGATIVE)
local color = colorOverride or (statVal >= 0 and "^7" or statData.chaosInoc and "^8" or colorCodes.NEGATIVE)
if statData.label == "Unreserved Life" and statVal == 0 then
color = colorCodes.NEGATIVE
end

local valStr = s_format("%"..statData.fmt, val)
valStr:gsub("%.", main.decimalSeparator)
valStr = color .. formatNumSep(valStr)
Expand Down Expand Up @@ -1330,14 +1331,27 @@ function buildMode:AddDisplayStatList(statList, actor)
end
end
elseif not (statData.hideStat) then
-- Change the color of the stat label to red if cost exceeds pool
local output = actor.output
local poolVal = output[statData.pool]
local colorOverride = nil
if statData.stat:match("Cost$") and statVal and poolVal then
if statData.stat == "ManaCost" and output.EnergyShieldProtectsMana then
if statVal > output.ManaUnreserved + output.EnergyShield then
colorOverride = colorCodes.NEGATIVE
end
elseif statVal > poolVal then
colorOverride = colorCodes.NEGATIVE
end
end
t_insert(statBoxList, {
height = 16,
labelColor..statData.label..":",
self:FormatStat(statData, statVal, overCapStatVal),
self:FormatStat(statData, statVal, overCapStatVal, colorOverride),
})
end
end
if statData.warnFunc and statVal and ((statData.condFunc and statData.condFunc(statVal, actor.output)) or not statData.condFunc) then
if statData.warnFunc and statVal and ((statData.condFunc and statData.condFunc(statVal, actor.output)) or not statData.condFunc) then
local v = statData.warnFunc(statVal, actor.output)
if v then
InsertIfNew(self.controls.warnings.lines, v)
Expand All @@ -1352,6 +1366,24 @@ function buildMode:AddDisplayStatList(statList, actor)
end
end
end
for pool, warningFlag in pairs({["Life"] = "LifeCostWarning", ["Mana"] = "ManaCostWarning", ["Rage"] = "RageCostWarning", ["Energy Shield"] = "ESCostWarning"}) do
if actor.output[warningFlag] then
local line = "You do not have enough "..(actor.output.EnergyShieldProtectsMana and pool == "Mana" and "Energy Shield and Mana" or pool).." to use a Selected Skill"
InsertIfNew(self.controls.warnings.lines, line)
end
end
for pool, warningFlag in pairs({["Life"] = "LifePerSecondCostPerSecondWarning", ["Mana"] = "ManaPerSecondCostPerSecondWarning", ["Rage"] = "RagePerSecondCostPerSecondWarning", ["EnergyShield"] = "ESPerSecondCostPerSecondWarning"}) do
if actor.output[warningFlag] then
local line = "You do not have enough ".. pool .." to use a Selected Skill for a second"
InsertIfNew(self.controls.warnings.lines, line)
end
end
for pool, warningFlag in pairs({["Unreserved life"] = "LifePercentCostPercentPerSecondWarning", ["Unreserved life"] = "LifePercentPerSecondCostPercentPerSecondWarning", ["Unreserved Mana"] = "ManaPercentPerSecondCostPercentPerSecondWarning", ["Unreserved Mana"] = "ManaPercentCostPercentPerSecondWarning", ["EnergyShield"] = "ESPercentPerSecondCostPercentPerSecondWarning"}) do
if actor.output[warningFlag] then
local line = "You do not have enough ".. pool .."% to use a Selected Skill"
InsertIfNew(self.controls.warnings.lines, line)
end
end
end

-- Build list of side bar stats
Expand Down
1 change: 0 additions & 1 deletion src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4203,7 +4203,6 @@ function calcs.offence(env, actor, activeSkill)
local uuid = cacheSkillUUID(triggerSkill)
if not GlobalCache.cachedData[calcMode][uuid] then
calcs.buildActiveSkill(env, calcMode, triggerSkill)
env.dontCache = true
end
-- We found a skill and it can crit
if GlobalCache.cachedData[calcMode][uuid] and GlobalCache.cachedData[calcMode][uuid].CritChance and GlobalCache.cachedData[calcMode][uuid].CritChance > 0 then
Expand Down
26 changes: 3 additions & 23 deletions src/Modules/CalcPerform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ local function findTriggerSkill(env, skill, source, triggerRate, reqManaCost)
local uuid = cacheSkillUUID(skill)
if not GlobalCache.cachedData["CACHE"][uuid] or GlobalCache.noCache then
calcs.buildActiveSkill(env, "CACHE", skill)
env.dontCache = true
end

if GlobalCache.cachedData["CACHE"][uuid] then
Expand Down Expand Up @@ -1790,12 +1789,6 @@ function calcs.perform(env, avoidCache)
local skillModList = activeSkill.skillModList
local skillCfg = activeSkill.skillCfg
for _, buff in ipairs(activeSkill.buffList) do
--Skip adding buff if reservation exceeds maximum
for _, value in ipairs({"Mana", "Life"}) do
if activeSkill.skillData[value.."ReservedBase"] and activeSkill.skillData[value.."ReservedBase"] > env.player.output[value] then
goto disableAura
end
end
if buff.cond and not skillModList:GetCondition(buff.cond, skillCfg) then
-- Nothing!
elseif buff.enemyCond and not enemyDB:GetCondition(buff.enemyCond) then
Expand Down Expand Up @@ -1995,7 +1988,6 @@ function calcs.perform(env, avoidCache)
t_insert(curses, curse)
end
end
::disableAura::
end
if activeSkill.minion and activeSkill.minion.activeSkillList then
local castingMinion = activeSkill.minion
Expand Down Expand Up @@ -2186,13 +2178,6 @@ function calcs.perform(env, avoidCache)
if (activeSkill.buffList[1] and curse.name == activeSkill.buffList[1].name and activeSkill.skillTypes[SkillType.Aura]) then
if modDB:Flag(nil, "SelfAurasOnlyAffectYou") then
skipAddingCurse = true
break
end
for _, value in ipairs({"Mana", "Life"}) do
if activeSkill.skillData[value.."ReservedBase"] and activeSkill.skillData[value.."ReservedBase"] > env.player.output[value] then
skipAddingCurse = true
break
end
end
break
end
Expand Down Expand Up @@ -2366,7 +2351,7 @@ function calcs.perform(env, avoidCache)
activeSkill.skillModList:NewMod("Multiplier:ScorchingRayStageAfterFirst", "BASE", maximum, "Base")
end
end

-- Process Triggered Skill and Set Trigger Conditions
-- Cospri's Malice
if env.player.mainSkill.skillData.triggeredByCospris and not env.player.mainSkill.skillFlags.minion then
Expand Down Expand Up @@ -2478,7 +2463,6 @@ function calcs.perform(env, avoidCache)
-- cache a new copy of this skill that's affected by Mirage Archer
if avoidCache then
usedSkill = env.player.mainSkill
env.dontCache = true
else
if not GlobalCache.cachedData[calcMode][uuid] then
calcs.buildActiveSkill(env, calcMode, env.player.mainSkill, true)
Expand Down Expand Up @@ -2518,7 +2502,6 @@ function calcs.perform(env, avoidCache)
newEnv.player.mainSkill = newSkill
-- mark it so we don't recurse infinitely
newSkill.marked = true
newEnv.dontCache = true
calcs.perform(newEnv)

env.player.mainSkill.infoMessage = tostring(mirageCount) .. " Mirage Archers using " .. usedSkill.activeEffect.grantedEffect.name
Expand Down Expand Up @@ -3007,7 +2990,7 @@ function calcs.perform(env, avoidCache)
end
end
end

-- Fix the configured impale stacks on the enemy
-- If the config is missing (blank), then use the maximum number of stacks
-- If the config is larger than the maximum number of stacks, replace it with the correct maximum
Expand Down Expand Up @@ -3214,8 +3197,5 @@ function calcs.perform(env, avoidCache)
calcs.offence(env, env.minion, env.minion.mainSkill)
end

local uuid = cacheSkillUUID(env.player.mainSkill)
if not env.dontCache then
cacheData(uuid, env)
end
cacheData(cacheSkillUUID(env.player.mainSkill), env)
end
43 changes: 43 additions & 0 deletions src/Modules/Calcs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,49 @@ function calcs.buildOutput(build, mode)
calcs.perform(env)

local output = env.player.output

for _, skill in ipairs(env.player.activeSkillList) do
local uuid = cacheSkillUUID(skill)
if not GlobalCache.cachedData["CACHE"][uuid] then
calcs.buildActiveSkill(env, "CACHE", skill)
end
if GlobalCache.cachedData["CACHE"][uuid] then
local EB = env.modDB:Flag(nil, "EnergyShieldProtectsMana")
for pool, costResource in pairs({["LifeUnreserved"] = "LifeCost", ["ManaUnreserved"] = "ManaCost", ["Rage"] = "RageCost", ["EnergyShield"] = "ESCost"}) do
local cachedCost = GlobalCache.cachedData["CACHE"][uuid].Env.player.output[costResource]
if cachedCost then
if EB and costResource == "Mana" then --Handling for mana cost warnings with EB allocated
output.EnergyShieldProtectsMana = true
output[costResource.."Warning"] = output[costResource.."Warning"] or (((output[pool] or 0) + (output["EnergyShield"] or 0)) < cachedCost)
else
output[costResource.."Warning"] = output[costResource.."Warning"] or ((output[pool] or 0) < cachedCost) -- defaulting to 0 to avoid crashing
end
end
end
for pool, costResource in pairs({["LifeUnreserved"] = "LifePerSecondCost", ["ManaUnreserved"] = "ManaPerSecondCost", ["Rage"] = "RagePerSecondCost", ["EnergyShield"] = "ESPerSecondCost"}) do
local cachedCost = GlobalCache.cachedData["CACHE"][uuid].Env.player.output[costResource]
if cachedCost then
if EB and costResource == "Mana" then
output.EnergyShieldProtectsMana = true
output[costResource.."PerSecondWarning"] = output[costResource.."PerSecondWarning"] or (((output[pool] or 0) + (output["EnergyShield"] or 0)) < cachedCost)
else
output[costResource.."PerSecondWarning"] = output[costResource.."PerSecondWarning"] or ((output[pool] or 0) < cachedCost)
ConPrintf(costResource.."PerSecondWarning".." "..(output[costResource.."PerSecondWarning"] and "true" or "false"))
end
end
end
for pool, costResource in pairs({["LifeUnreservedPercent"] = "LifePercentCost", ["LifeUnreservedPercent"] = "LifePercentPerSecondCost", ["ManaUnreservedPercent"] = "ManaPercentPerSecondCost", ["ManaUnreservedPercent"] = "ManaPercentCost", ["ESPercentPerSecondCost"] = "ESPercentPerSecondCost"}) do
local cachedCost = GlobalCache.cachedData["CACHE"][uuid].Env.player.output[costResource]
if cachedCost then
if costResource == "ESPercentPerSecondCost" then --Assuming 100% of Es is always available
output["ESPercentPerSecondCostPercentPerSecondWarning"] = output["ESPercentPerSecondCostPercentPerSecondWarning"] or ((output["EnergyShield"] or 0) < cachedCost)
else
output[costResource.."PercentPerSecondWarning"] = output[costResource.."PercentPerSecondWarning"] or ((output[pool] or 0) < cachedCost)
end
end
end
end
end

-- Build output across all skills added to FullDPS skills
GlobalCache.noCache = true
Expand Down
3 changes: 3 additions & 0 deletions src/Modules/Common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,9 @@ function cacheData(uuid, env)
Name = env.player.mainSkill.activeEffect.grantedEffect.name,
Speed = env.player.output.Speed,
ManaCost = env.player.output.ManaCost,
LifeCost = env.player.output.LifeCost,
ESCost = env.player.output.ESCost,
RageCost = env.player.output.RageCost,
HitChance = env.player.output.HitChance,
PreEffectiveCritChance = env.player.output.PreEffectiveCritChance,
CritChance = env.player.output.CritChance,
Expand Down