Skip to content
Open
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
123 changes: 123 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,127 @@ describe("TestSkills", function()
runCallback("OnFrame")
assert.True(build.calcsTab.mainOutput.TotalDPS > iceShotDPS)
end)

describe("Combo stacking", function()
local CHAKRA_MOD = "Skills deal 8% increased Damage per Combo consumed, up to 40%"

local function equipQuarterstaff()
build.itemsTab:CreateDisplayItemFromRaw([[
New Item
Razor Quarterstaff
Quality: 0
]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")
end

local function applyComboConfig(stacks, customMods)
build.configTab.input.multiplierCombo = stacks
build.configTab.input.customMods = customMods or ""
build.configTab:BuildModList()
runCallback("OnFrame")
build.calcsTab:BuildOutput()
runCallback("OnFrame")
end

local function findSkillIndex(skillName)
for index, skill in ipairs(build.calcsTab.mainEnv.player.activeSkillList) do
if skill.activeEffect.grantedEffect.name == skillName then
return index
end
end
error("Skill not found: " .. skillName)
end

local function getSkillIncDamage(skillIndex)
local skill = build.calcsTab.mainEnv.player.activeSkillList[skillIndex]
return skill.skillModList:Sum("INC", skill.skillCfg, "Damage")
end

local function getSkillMoreDamage(skillIndex)
local skill = build.calcsTab.mainEnv.player.activeSkillList[skillIndex]
return skill.skillModList:Sum("MORE", skill.skillCfg, "Damage")
end

local function getAverageHit()
return build.calcsTab.mainOutput.AverageHit or 0
end

it("does not apply damage per combo consumed to non-ComboStacking skills", function()
equipQuarterstaff()
build.skillsTab:PasteSocketGroup("Ball Lightning 20/0 1\n")
build.skillsTab:PasteSocketGroup("Tempest Bell 20/0 1\n")
runCallback("OnFrame")

applyComboConfig(10, "")
local ballIncBase = getSkillIncDamage(findSkillIndex("Ball Lightning"))
local tempestIncBase = getSkillIncDamage(findSkillIndex("Tempest Bell"))

applyComboConfig(10, CHAKRA_MOD)
local ballIncWith = getSkillIncDamage(findSkillIndex("Ball Lightning"))
local tempestIncWith = getSkillIncDamage(findSkillIndex("Tempest Bell"))

assert.are.equals(ballIncBase, ballIncWith)
assert.True(tempestIncWith > tempestIncBase)
end)

it("caps damage per combo consumed at the stated limit", function()
equipQuarterstaff()
build.skillsTab:PasteSocketGroup("Tempest Bell 20/0 1\n")
runCallback("OnFrame")

applyComboConfig(0, "")
local tempestIncBase = getSkillIncDamage(findSkillIndex("Tempest Bell"))

applyComboConfig(3, CHAKRA_MOD)
local incAt3 = getSkillIncDamage(findSkillIndex("Tempest Bell"))

applyComboConfig(5, CHAKRA_MOD)
local incAt5 = getSkillIncDamage(findSkillIndex("Tempest Bell"))

applyComboConfig(10, CHAKRA_MOD)
local incAt10 = getSkillIncDamage(findSkillIndex("Tempest Bell"))

assert.are.equals(24, incAt3 - tempestIncBase)
assert.are.equals(40, incAt5 - tempestIncBase)
assert.are.equals(40, incAt10 - tempestIncBase)
assert.are.equals(incAt5, incAt10)
end)

it("Culmination I caps combo damage at 10 stacks", function()
equipQuarterstaff()
build.skillsTab:PasteSocketGroup("Quarterstaff Strike 20/0 1\nCulmination I 20/0 1\n")
runCallback("OnFrame")

applyComboConfig(10)
local moreAt10 = getSkillMoreDamage(findSkillIndex("Quarterstaff Strike"))
local hitAt10 = getAverageHit()

applyComboConfig(50)
local moreAt50 = getSkillMoreDamage(findSkillIndex("Quarterstaff Strike"))
local hitAt50 = getAverageHit()

assert.are.equals(30, moreAt10)
assert.are.equals(moreAt10, moreAt50)
assert.are.equals(hitAt10, hitAt50)
end)

it("Culmination II caps combo damage at 20 stacks", function()
equipQuarterstaff()
build.skillsTab:PasteSocketGroup("Quarterstaff Strike 20/0 1\nCulmination II 20/0 1\n")
runCallback("OnFrame")

applyComboConfig(20)
local moreAt20 = getSkillMoreDamage(findSkillIndex("Quarterstaff Strike"))
local hitAt20 = getAverageHit()

applyComboConfig(50)
local moreAt50 = getSkillMoreDamage(findSkillIndex("Quarterstaff Strike"))
local hitAt50 = getAverageHit()

assert.are.equals(40, moreAt20)
assert.are.equals(moreAt20, moreAt50)
assert.are.equals(hitAt20, hitAt50)
end)
end)
end)
2 changes: 1 addition & 1 deletion src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5930,7 +5930,7 @@ c["Skills Cost +3 Rage"]={{[1]={flags=0,keywordFlags=0,name="RageCostBase",type=
c["Skills Supported by Unleash have 10% increased Seal gain frequency"]={{[1]={flags=0,keywordFlags=0,name="SealGainFrequency",type="INC",value=10}},nil}
c["Skills Supported by Unleash have 25% increased Seal gain frequency"]={{[1]={flags=0,keywordFlags=0,name="SealGainFrequency",type="INC",value=25}},nil}
c["Skills deal 20% increased Damage per Connected Red Support Gem"]={{[1]={flags=0,keywordFlags=0,name="SkillDamageIncreasedPerRedSupport",type="FLAG",value=20}},nil}
c["Skills deal 8% increased Damage per Combo consumed, up to 40%"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="INC",value=8}}," per Combo consumed, up to 40% "}
c["Skills deal 8% increased Damage per Combo consumed, up to 40%"]={{[1]={[1]={limit=40,limitTotal=true,type="Multiplier",var="ComboStacks"},[2]={skillType=152,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=8}},nil}
c["Skills fire an additional Projectile"]={{[1]={flags=0,keywordFlags=0,name="ProjectileCount",type="BASE",value=1}},nil}
c["Skills gain 1 Glory every 2 seconds for each Rare or Unique monster in your Presence"]={{}," Glory every 2 seconds for each Rare or Unique monster in your Presence "}
c["Skills gain 1% of Damage as Chaos Damage per 3 Life Cost"]={{[1]={[1]={div=3,stat="LifeCost",type="PerStat"},flags=0,keywordFlags=0,name="DamageAsChaos",type="BASE",value=1}},nil}
Expand Down
6 changes: 6 additions & 0 deletions src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,12 @@ return {
["active_skill_damage_+%_final"] = {
mod("Damage", "MORE", nil),
},
["support_damage_+%_final_per_combo_stack"] = {
mod("Damage", "MORE", nil, 0, 0, { type = "Multiplier", var = "ComboStacks", limitVar = "ComboStacksMax" }),
},
["skill_maximum_number_of_combo_stacks"] = {
mod("Multiplier:ComboStacksMax", "BASE", nil),
},
["support_no_fear_damage_+%_final_per_second_up_to_30%"] = {
mod("Damage", "MORE", nil, 0, 0,
{ type = "Condition", var = "UsingStoicism" },
Expand Down
3 changes: 3 additions & 0 deletions src/Modules/ConfigOptions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,9 @@ Huge sets the radius to 11.
{ var = "multiplierRage", type = "count", label = "^xFF9922Rage:", ifFlag = "Condition:CanGainRage", tooltip = "Base Maximum ^xFF9922Rage ^7is 30, and inherently grants 1% More Attack Damage per 1 ^xFF9922Rage^7\nYou lose 10 ^xFF9922Rage ^7every second if you have not been Hit or gained ^xFF9922Rage ^7in the last 2 seconds.", apply = function(val, modList, enemyModList)
modList:NewMod("Multiplier:RageStack", "BASE", val, "Config", { type = "IgnoreCond" }, { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanGainRage" })
end },
{ var = "multiplierCombo", type = "count", label = "Combo:", ifMult = "ComboStacks", tooltip = "Some skills and effects require a certain Combo count to use.\nCombo is built by successfully Striking Enemies.", apply = function(val, modList, enemyModList)
modList:NewMod("Multiplier:ComboStacks", "BASE", val, "Config", { type = "IgnoreCond" }, { type = "Condition", var = "Combat" })
end },
{ var = "conditionLeeching", type = "check", label = "Are you Leeching?", ifCond = "Leeching", tooltip = "You will automatically be considered to be Leeching if you have '^xE05030Life ^7Leech effects are not removed at Full ^xE05030Life^7',\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Condition:Leeching", "FLAG", true, "Config", { type = "Condition", var = "Combat" })
end },
Expand Down
1 change: 1 addition & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,7 @@ local modTagList = {
["per crab barrier"] = { tag = { type = "Multiplier", var = "CrabBarrier" } },
["per rage"] = { tag = { type = "Multiplier", var = "Rage" } },
["per rage while you are not losing rage"] = { tag = { type = "Multiplier", var = "Rage" } },
["per combo consumed, up to (%d+)%%"] = function(num) return { tagList = { { type = "Multiplier", var = "ComboStacks", limit = tonumber(num), limitTotal = true }, { type = "SkillType", skillType = SkillType.ComboStacking } } } end,
["per (%d+) rage"] = function(num) return { tag = { type = "Multiplier", var = "Rage", div = num } } end,
["per mana burn"] = { tag = { type = "Multiplier", var = "ManaBurnStacks" } },
["per mana burn on you"] = { tag = { type = "Multiplier", var = "ManaBurnStacks" } },
Expand Down
Loading