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
272 changes: 272 additions & 0 deletions spec/System/TestCadirosGambit_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
describe("Cadiro's Gambit", function()
local function equipCadirosGambit()
build.itemsTab:CreateDisplayItemFromRaw([[
Rarity: Unique
Cadiro's Gambit
Primed Quiver
Implicits: 1
10% increased Attack Speed
Each Arrow fired is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow
]])

local item = build.itemsTab.displayItem
build.itemsTab:AddDisplayItem(true)
build.itemsTab:EquipItemInSet(item, build.itemsTab.activeItemSetId)
return item
end

local function setupSkill(skillName)
build.itemsTab:CreateDisplayItemFromRaw([[
New Item
Crude Bow
Quality: 0
]])
build.itemsTab:AddDisplayItem()
build.skillsTab:PasteSocketGroup(skillName .. " 1/0 1")
end

local arrowConditions = {
"PerandusArrowCrescendo",
"PerandusArrowSplinter",
"PerandusArrowReversing",
"PerandusArrowDiamond",
"PerandusArrowCovetous",
"PerandusArrowBlunt",
}

local function selectArrow(condition)
build.configTab.input.cadirosGambitArrow = condition
build.configTab:BuildModList()
runCallback("OnFrame")
end

before_each(function()
newBuild()
runCallback("OnFrame")
end)

it("only shows its arrow selector while equipped", function()
setupSkill("Shockchain Arrow")
runCallback("OnFrame")

local control = build.configTab.varControls.cadirosGambitArrow
assert.is_not_nil(control)
assert.is_false(control.shown())
assert.are.equals("NONE", build.configTab.input.cadirosGambitArrow)

local cadirosGambit = equipCadirosGambit()
runCallback("OnFrame")

assert.is_true(control.shown())

build.itemsTab:DeleteItem(cadirosGambit)
runCallback("OnFrame")

assert.is_false(control.shown())
end)

it("applies only the selected arrow condition", function()
equipCadirosGambit()
runCallback("OnFrame")

local selections = { "NONE" }
for _, condition in ipairs(arrowConditions) do
table.insert(selections, condition)
end

for _, selected in ipairs(selections) do
build.configTab.input.cadirosGambitArrow = selected
build.configTab:BuildModList()

for _, condition in ipairs(arrowConditions) do
local conditionExists = build.configTab.modList:HasMod(
"FLAG", nil, "Condition:" .. condition
)
assert.are.equals(selected == condition, conditionExists)
end
end
end)

it("applies Crescendo Arrow chain and damage bonuses", function()
setupSkill("Shockchain Arrow")
equipCadirosGambit()

build.configTab.input.skillChainCount = 1
selectArrow("NONE")

local baselineChainMax = build.calcsTab.mainOutput.ChainMax or 0
local baselineSkill = build.calcsTab.mainEnv.player.mainSkill
local baselineDamage = baselineSkill.skillModList:Sum(
"INC", baselineSkill.skillCfg, "Damage"
)

selectArrow("PerandusArrowCrescendo")

local mainSkill = build.calcsTab.mainEnv.player.mainSkill
assert.are.equals(baselineChainMax + 6, build.calcsTab.mainOutput.ChainMax)
assert.are.equals(1, build.calcsTab.mainOutput.Chain)
assert.are.equals(baselineDamage + 60, mainSkill.skillModList:Sum(
"INC", mainSkill.skillCfg, "Damage"
))
end)

it("applies Splinter Arrow split bonus", function()
setupSkill("Shockchain Arrow")
equipCadirosGambit()

selectArrow("NONE")
local baselineSplitCount = build.calcsTab.mainOutput.SplitCount or 0

selectArrow("PerandusArrowSplinter")

assert.are.equals(
baselineSplitCount + 6,
build.calcsTab.mainOutput.SplitCount
)
assert.are.equals(
baselineSplitCount + 6,
build.calcsTab.mainOutput.SplitCountString
)
end)

it("applies Diamond Arrow critical bonuses", function()
setupSkill("Shockchain Arrow")
equipCadirosGambit()

selectArrow("NONE")
local baselineCritMultiplier = build.calcsTab.mainOutput.CritMultiplier
local baselineSkill = build.calcsTab.mainEnv.player.mainSkill
local baselineCritMultiplierIncrease = baselineSkill.skillModList:Sum(
"INC", baselineSkill.skillCfg, "CritMultiplier"
)

selectArrow("PerandusArrowDiamond")

local mainSkill = build.calcsTab.mainEnv.player.mainSkill
assert.are.equals(100, build.calcsTab.mainOutput.CritChance)
assert.are.equals(
baselineCritMultiplierIncrease + 60,
mainSkill.skillModList:Sum(
"INC", mainSkill.skillCfg, "CritMultiplier"
)
)
assert.is_true(
build.calcsTab.mainOutput.CritMultiplier > baselineCritMultiplier
)
end)

it("applies Covetous Arrow rarity bonus", function()
setupSkill("Shockchain Arrow")
equipCadirosGambit()

selectArrow("NONE")
local baselineSkill = build.calcsTab.mainEnv.player.mainSkill
local baselineRarity = baselineSkill.skillModList:Sum(
"INC", baselineSkill.skillCfg, "LootRarity"
)

selectArrow("PerandusArrowCovetous")

local mainSkill = build.calcsTab.mainEnv.player.mainSkill
assert.are.equals(
baselineRarity + 600,
mainSkill.skillModList:Sum(
"INC", mainSkill.skillCfg, "LootRarity"
)
)
end)

it("applies Blunt Arrow stun buildup bonus", function()
setupSkill("Shockchain Arrow")
equipCadirosGambit()

selectArrow("NONE")
local baselineBuildup = build.calcsTab.mainOutput.HeavyStunBuildupAvg or 0
local baselineSkill = build.calcsTab.mainEnv.player.mainSkill
local baselineBuildupIncrease = baselineSkill.skillModList:Sum(
"INC", baselineSkill.skillCfg, "EnemyHeavyStunBuildup"
)

selectArrow("PerandusArrowBlunt")

local mainSkill = build.calcsTab.mainEnv.player.mainSkill
assert.are.equals(
baselineBuildupIncrease + 600,
mainSkill.skillModList:Sum(
"INC", mainSkill.skillCfg, "EnemyHeavyStunBuildup"
)
)
assert.is_true(
build.calcsTab.mainOutput.HeavyStunBuildupAvg > baselineBuildup
)
end)

it("does not apply arrow bonuses to a non-arrow skill", function()
setupSkill("Fireball")
equipCadirosGambit()

local scopedMods = {
{
condition = "PerandusArrowCrescendo",
modType = "BASE",
modName = "ChainCountMax",
},
{
condition = "PerandusArrowSplinter",
modType = "BASE",
modName = "SplitCount",
},
{
condition = "PerandusArrowReversing",
modType = "BASE",
modName = "ProjectileReturnChance",
},
{
condition = "PerandusArrowDiamond",
modType = "INC",
modName = "CritMultiplier",
},
{
condition = "PerandusArrowCovetous",
modType = "INC",
modName = "LootRarity",
},
{
condition = "PerandusArrowBlunt",
modType = "INC",
modName = "EnemyHeavyStunBuildup",
},
}

for _, scopedMod in ipairs(scopedMods) do
selectArrow(scopedMod.condition)

local mainSkill = build.calcsTab.mainEnv.player.mainSkill
assert.are.equals(
0,
mainSkill.skillModList:Sum(
scopedMod.modType,
mainSkill.skillCfg,
scopedMod.modName
)
)
end
end)

it("shows Reversing Arrow outputs and removes them with the item", function()
setupSkill("Shockchain Arrow")
local cadirosGambit = equipCadirosGambit()

selectArrow("PerandusArrowReversing")

assert.are.equals(100, build.calcsTab.mainOutput.PierceCount)
assert.are.equals("All targets", build.calcsTab.mainOutput.PierceCountString)
assert.are.equals(100, build.calcsTab.mainOutput.ProjectileReturnChance)

build.itemsTab:DeleteItem(cadirosGambit)
runCallback("OnFrame")

assert.are.equals(0, build.calcsTab.mainOutput.PierceCount)
assert.are.equals(0, build.calcsTab.mainOutput.ProjectileReturnChance)
end)
end)
2 changes: 1 addition & 1 deletion src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5226,7 +5226,7 @@ c["Double Stun Threshold while Shield is Raised"]={{[1]={[1]={globalLimit=100,gl
c["Double the number of your Poisons that targets can be affected by at the same time"]={{[1]={flags=0,keywordFlags=0,name="PoisonCanStack",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PoisonStacks",type="MORE",value=100}},nil}
c["Drop Ignited Ground while moving, which lasts 8 seconds and Ignites as though dealing Fire Damage equal to 10% of your maximum Life"]={nil,"Drop Ignited Ground while moving, which lasts 8 seconds and Ignites as though dealing Fire Damage equal to 10% of your maximum Life "}
c["Drop Shocked Ground while moving, lasting 8 seconds"]={nil,"Drop Shocked Ground while moving, lasting 8 seconds "}
c["Each Arrow fired is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow"]={nil,"Each Arrow fired is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow "}
c["Each Arrow fired is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow"]={{[1]={flags=0,keywordFlags=0,name="Condition:HaveCadirosGambit",type="FLAG",value=true},[2]={[1]={type="Condition",var="PerandusArrowCrescendo"},flags=0,keywordFlags=2048,name="ChainCountMax",type="BASE",value=6},[3]={[1]={stat="Chain",type="PerStat"},[2]={type="Condition",var="PerandusArrowCrescendo"},flags=0,keywordFlags=2048,name="Damage",type="INC",value=60},[4]={[1]={type="Condition",var="PerandusArrowSplinter"},flags=0,keywordFlags=2048,name="SplitCount",type="BASE",value=6},[5]={[1]={type="Condition",var="PerandusArrowReversing"},flags=0,keywordFlags=2048,name="PierceAllTargets",type="FLAG",value=true},[6]={[1]={type="Condition",var="PerandusArrowReversing"},flags=0,keywordFlags=2048,name="ProjectileReturnChance",type="BASE",value=100},[7]={[1]={type="Condition",var="PerandusArrowDiamond"},flags=0,keywordFlags=2048,name="CritChance",type="OVERRIDE",value=100},[8]={[1]={type="Condition",var="PerandusArrowDiamond"},flags=0,keywordFlags=2048,name="CritMultiplier",type="INC",value=60},[9]={[1]={type="Condition",var="PerandusArrowCovetous"},flags=0,keywordFlags=2048,name="LootRarity",type="INC",value=600},[10]={[1]={type="Condition",var="PerandusArrowBlunt"},flags=0,keywordFlags=2048,name="EnemyHeavyStunBuildup",type="INC",value=600}},nil}
c["Each Totem applies 2% increased Damage taken to Enemies in their Presence"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Multiplier",var="TotemsSummoned"},flags=0,keywordFlags=0,name="DamageTaken",type="INC",value=2}}}},nil}
c["Echoed Spells have 25% increased Area of Effect"]={nil,"Echoed Spells have 25% increased Area of Effect "}
c["Effect is not removed when Unreserved Life is Filled"]={nil,"Effect is not removed when Unreserved Life is Filled "}
Expand Down
1 change: 1 addition & 0 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,7 @@ function calcs.offence(env, actor, activeSkill)
breakdown.ProjectileSpeedMod = breakdown.mod(skillModList, skillCfg, "ProjectileSpeed")
end
output.TwoAdditionalProjectiles = m_min(skillModList:Sum("BASE", skillCfg, "TwoAdditionalProjectilesChance"), 100)
output.ProjectileReturnChance = m_min(skillModList:Sum("BASE", skillCfg, "ProjectileReturnChance"), 100)
end
if skillFlags.melee then
if skillFlags.weapon1Attack then
Expand Down
1 change: 1 addition & 0 deletions src/Modules/CalcSections.lua
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ return {
{ label = "Repeat Count", haveOutput = "RepeatCount", { format = "{output:Repeats}", { modName = { "RepeatCount" }, cfg = "skill" }, }, },
{ label = "Projectile Count", flag = "projectile", { format = "{output:ProjectileCount}", { modName = { "NoAdditionalProjectiles" , "ProjectileCount", "SurpassingProjectileChance", "TwoAdditionalProjectilesChance" }, cfg = "skill" }, }, },
{ label = "2 Add. Proj. Chance", haveOutput = "TwoAdditionalProjectiles", { format = "{output:TwoAdditionalProjectiles}%", { modName = { "TwoAdditionalProjectilesChance", "NoAdditionalProjectiles" }, cfg = "skill" }, }, },
{ label = "Return Chance", haveOutput = "ProjectileReturnChance", { format = "{0:output:ProjectileReturnChance}%", { modName = "ProjectileReturnChance", modType = "BASE", cfg = "skill" }, }, },
{ label = "Pierce Count", haveOutput = "PierceCount", { format = "{output:PierceCountString}", { modName = { "CannotPierce", "PierceCount", "PierceChance", "PierceAllTargets" }, cfg = "skill" }, }, },
{ label = "Fork Count", haveOutput = "ForkCountMax", { format = "{output:ForkCountString}", { modName = { "CannotFork", "ForkCountMax" }, cfg = "skill" }, }, },
{ label = "Max Chain Count", haveOutput = "ChainMax", { format = "{output:ChainMaxString}", { modName = { "CannotChain", "ChainCountMax", "ChainChance", "NoAdditionalChains" }, cfg = "skill" }, }, },
Expand Down
22 changes: 22 additions & 0 deletions src/Modules/ConfigOptions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,28 @@ Huge sets the radius to 11.
modList:NewMod("Keystone", "LIST", "Resolute Technique", "Config")
end
end },
{ var = "cadirosGambitArrow", type = "list", label = "Cadiro's Gambit Arrow:", ifFlag = "Condition:HaveCadirosGambit",
list = {
{ val = "NONE", label = "Not selected", tooltip = "No Cadiro's Gambit arrow effect." },
{ val = "PerandusArrowCrescendo", label = "Crescendo", tooltip = "Crescendo Arrows Chain 6 additional times and deal 60% increased Damage for each time they have Chained." },
{ val = "PerandusArrowSplinter", label = "Splinter", tooltip = "Splintering Arrows Split towards 6 targets." },
{ val = "PerandusArrowReversing", label = "Reversing", tooltip = "Reversing Arrows Pierce all targets and Return to you." },
{ val = "PerandusArrowDiamond", label = "Diamond", tooltip = "All Hits with Diamond Arrows are Critical Hits with 60% increased Critical Damage Bonus." },
{ val = "PerandusArrowCovetous", label = "Covetous", tooltip = "Enemies killed with Covetous Arrows drop items with 600% increased Rarity." },
{ val = "PerandusArrowBlunt", label = "Blunt", tooltip = "Blunt Arrows cause 600% increased Stun Buildup." },
},
defaultIndex = 1,
tooltipFunc = function(tooltip, mode, index, value)
tooltip:Clear()
if value and value.tooltip then
tooltip:AddLine(14, value.tooltip)
end
end,
apply = function(val, modList, enemyModList)
if val ~= "NONE" then
modList:NewMod("Condition:" .. val, "FLAG", true, "Config", { type = "Condition", var = "Combat" })
end
end },
{ var = "conditionHaveVulconus", type = "check", label = "Do you have Avatar Of Fire?", ifFlag = "Condition:HaveVulconus", tooltip = "This option is specific to Vulconus.", apply = function(val, modList, enemyModList)
modList:NewMod("Condition:HaveAvatarOfFire", "FLAG", true, "Config", { type = "Condition", var = "Combat" })
modList:NewMod("Keystone", "LIST", "Avatar of Fire", "Config")
Expand Down
27 changes: 27 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4824,6 +4824,33 @@ local specialModList = {
mod("MinionModifier", "LIST", { mod = mod("Speed", "INC", num, nil, ModFlag.Attack, { type = "Multiplier", var = "RageEffect", actor = "player" }) }),
} end,
-- Projectiles
["each arrow fired is a crescendo, splinter, reversing, diamond, covetous, or blunt arrow"] = { flag("Condition:HaveCadirosGambit"),
-- Crescendo
mod("ChainCountMax", "BASE", 6, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowCrescendo" }),
mod("Damage", "INC", 60, nil, 0, KeywordFlag.Arrow,
{ type = "PerStat", stat = "Chain" },
{ type = "Condition", var = "PerandusArrowCrescendo" }),
-- Splinter
mod("SplitCount", "BASE", 6, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowSplinter" }),
-- Reversing
flag("PierceAllTargets", nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowReversing" }),
mod("ProjectileReturnChance", "BASE", 100, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowReversing" }),
-- Diamond
mod("CritChance", "OVERRIDE", 100, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowDiamond" }),
mod("CritMultiplier", "INC", 60, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowDiamond" }),
-- Covetous
mod("LootRarity", "INC", 600, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowCovetous" }),
-- Blunt
mod("EnemyHeavyStunBuildup", "INC", 600, nil, 0, KeywordFlag.Arrow,
{ type = "Condition", var = "PerandusArrowBlunt" }),
},
["skills chain %+(%d) times"] = function(num) return { mod("ChainCountMax", "BASE", num) } end,
["arrows chain %+(%d) times"] = function(num) return { mod("ChainCountMax", "BASE", num, nil, 0, KeywordFlag.Arrow) } end,
["skills chain an additional time while at maximum frenzy charges"] = { mod("ChainCountMax", "BASE", 1, { type = "StatThreshold", stat = "FrenzyCharges", thresholdStat = "FrenzyChargesMax" }) },
Expand Down