From 22aa7189cfcf309bc4a12d32c46215358244696a Mon Sep 17 00:00:00 2001 From: Lucas Karsten Date: Sat, 15 Aug 2026 11:34:43 -0300 Subject: [PATCH] Support Cadiro's Gambit's Perandus Arrows "Each Arrow fired is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow" was unsupported, so Cadiro's Gambit measured as a plain quiver with increased Attack Speed. The Diamond Arrow alone is worth more than doubling the DPS of a bow build with average Critical Hit Chance, which made the item look far weaker than it is. The six Arrows behave too differently to average into a single number, so the quiver's line only sets a condition and a new config picks which Arrow to calculate, the same shape as the existing "Random element mode" for modifiers that choose an element. Random, the default, applies none of them and leaves the current behaviour untouched. Crescendo (Chain +6, 60% increased Damage for each Chain), Splinter (Split towards 6 targets), Reversing (Pierce all targets), Diamond (all Hits are Critical Hits, 60% increased Critical Damage Bonus), Covetous (600% increased Rarity) and Blunt (600% increased Stun Buildup) all reuse existing modifiers. The Reversing Arrow also returns to you, which PoB does not model. The config gates itself on Condition:PerandusArrows, granted by the quiver. ifFlag only decides whether the control is drawn, while ConfigTab:BuildModList applies every stored list var regardless, so without the condition a build that picked Diamond and then unequipped the quiver would keep 100% Critical Hit Chance with the control no longer visible. --- src/Data/ModCache.lua | 2 +- src/Modules/ConfigOptions.lua | 25 +++++++++++++++++++++++++ src/Modules/ModParser.lua | 4 ++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 96c7f933cb..85fb2147c8 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -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:PerandusArrows",type="FLAG",value=true}},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 "} diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 0437732526..02b2fffe6f 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -170,6 +170,31 @@ local configSettings = { { var = "ailmentMode", type = "list", label = "Ailment calculation mode:", tooltip = "Controls how the base damage for applying Ailments is calculated:\n\tAverage: damage is based on the average application, including both crits and non-crits\n\tCrits Only: damage is based solely on Ailments inflicted with crits", list = {{val="AVERAGE",label="Average"},{val="CRIT",label="Crits Only"}} }, { var = "cooldownMode", type = "list", label = "Cooldown calculation mode:", tooltip = "Controls how the cooldown for skills is calculated:\n\tBase: The cooldown is calculated with normal behavior.\n\tAverage: The cooldown is adjusted to reflect the average time between uses, factoring in effects such as a chance to not consume a cooldown.", list = {{val="BASE",label="Base"},{val="AVERAGE",label="Average"}} }, { var = "physMode", type = "list", label = "Random element mode:", ifFlag = "randomPhys", tooltip = "Controls how modifiers which choose a random element will function.\n\tAverage: Modifiers will grant one third of their value to ^xB97123Fire^7, ^x3F6DB3Cold^7, and ^xADAA47Lightning ^7simultaneously\n\t^xB97123Fire ^7/ ^x3F6DB3Cold ^7/ ^xADAA47Lightning^7: Modifiers will grant their full value as the specified element\nIf a modifier chooses between just two elements, the full value can only be given as those two elements.", list = {{val="AVERAGE",label="Average"},{val="FIRE",label="^xB97123Fire"},{val="COLD",label="^x3F6DB3Cold"},{val="LIGHTNING",label="^xADAA47Lightning"}} }, + { var = "perandusArrow", type = "list", label = "Perandus Arrow type:", ifFlag = "Condition:PerandusArrows", tooltip = "Cadiro's Gambit turns every Arrow into a random one of six Perandus Arrows, so each type applies to a sixth of the Arrows you fire.\nTheir behaviours are too different to average into one number (Chaining against guaranteed Critical Hits), so this picks the Arrow to calculate.\nRandom: none of the six is applied.", list = {{val="NONE",label="Random (none applied)"},{val="CRESCENDO",label="Crescendo (Chain)"},{val="SPLINTER",label="Splinter (Split)"},{val="REVERSING",label="Reversing (Pierce)"},{val="DIAMOND",label="Diamond (Critical)"},{val="COVETOUS",label="Covetous (Rarity)"},{val="BLUNT",label="Blunt (Stun)"}}, apply = function(val, modList, enemyModList) + -- In-game Arrow descriptions, quoted so the values below can be checked: + -- Crescendo: "Crescendo Arrows Chain 6 additional times and deal 60% increased Damage for each time they have Chained." + -- Splinter: "Splintering Arrows Split towards 6 targets." + -- Reversing: "Reversing Arrows Pierce all targets and Return to you." + -- Diamond: "All Hits with Diamond Arrows are Critical Hits with 60% increased Critical Damage Bonus." + -- Covetous: "Enemies killed with Covetous Arrows drop items with 600% increased Rarity." + -- Blunt: "Blunt Arrows cause 600% increased Stun Buildup." + if val == "CRESCENDO" then + modList:NewMod("ChainCountMax", "BASE", 6, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + modList:NewMod("Damage", "INC", 60, "Config", 0, KeywordFlag.Arrow, { type = "PerStat", stat = "Chain" }, { type = "Condition", var = "PerandusArrows" }) + elseif val == "SPLINTER" then + modList:NewMod("SplitCount", "BASE", 6, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + elseif val == "REVERSING" then + -- The Arrow also returns to you, which PoB does not model. + modList:NewMod("PierceAllTargets", "FLAG", true, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + elseif val == "DIAMOND" then + modList:NewMod("CritChance", "OVERRIDE", 100, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + modList:NewMod("CritMultiplier", "INC", 60, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + elseif val == "COVETOUS" then + modList:NewMod("LootRarity", "INC", 600, "Config", { type = "Condition", var = "PerandusArrows" }) + elseif val == "BLUNT" then + modList:NewMod("EnemyHeavyStunBuildup", "INC", 600, "Config", 0, KeywordFlag.Arrow, { type = "Condition", var = "PerandusArrows" }) + end + end }, { var = "lifeRegenMode", type = "list", label = "^xE05030Life ^7regen calculation mode:", ifCond = { "LifeRegenBurstAvg", "LifeRegenBurstFull" }, tooltip = "Controls how ^xE05030Life ^7regeneration is calculated:\n\tMinimum: does not include burst regen\n\tAverage: includes burst regen, averaged based on uptime\n\tBurst: includes full burst regen", list = {{val="MIN",label="Minimum"},{val="AVERAGE",label="Average"},{val="FULL",label="Burst"}}, apply = function(val, modList, enemyModList) if val == "AVERAGE" then modList:NewMod("Condition:LifeRegenBurstAvg", "FLAG", true, "Config") diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 52fa3b4316..02555644bb 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -4866,6 +4866,10 @@ local specialModList = { ["always pierce with arrows"] = { flag("PierceAllTargets", nil, 0, KeywordFlag.Arrow) }, ["arrows always pierce"] = { flag("PierceAllTargets", nil, 0, KeywordFlag.Arrow) }, ["arrows pierce all targets"] = { flag("PierceAllTargets", nil, 0, KeywordFlag.Arrow) }, + -- Cadiro's Gambit. Each Arrow is a random one of six Perandus Arrows, whose + -- behaviours differ too much to average; the "Perandus Arrow type" config + -- picks which one to calculate. + ["each arrow fired is a crescendo, splinter, reversing, diamond, covetous, or blunt arrow"] = { flag("Condition:PerandusArrows") }, ["arrows that pierce cause bleeding"] = { mod("BleedChance", "BASE", 100, nil, 0, KeywordFlag.Arrow, { type = "StatThreshold", stat = "PierceCount", threshold = 1 }) }, ["arrows that pierce have (%d+)%% chance to cause bleeding"] = function(num) return { mod("BleedChance", "BASE", num, nil, 0, KeywordFlag.Arrow, { type = "StatThreshold", stat = "PierceCount", threshold = 1 }) } end, ["arrows that pierce deal (%d+)%% increased damage"] = function(num) return { mod("Damage", "INC", num, nil, 0, KeywordFlag.Arrow, { type = "StatThreshold", stat = "PierceCount", threshold = 1 }) } end,