diff --git a/spec/System/TestPyromanticPact_spec.lua b/spec/System/TestPyromanticPact_spec.lua new file mode 100644 index 0000000000..e921c07559 --- /dev/null +++ b/spec/System/TestPyromanticPact_spec.lua @@ -0,0 +1,50 @@ +describe("TestPyromanticPact", function() + before_each(function() + newBuild() + end) + + teardown(function() + -- newBuild() takes care of resetting everything in setup() + end) + + local function withMods(customMods) + build.configTab.input.customMods = customMods + build.configTab:BuildModList() + runCallback("OnFrame") + return build.calcsTab.mainOutput + end + + it("parses the Pyromantic Pact node", function() + local node = build.spec.nodes[13174] + assert.is_not_nil(node) + assert.True(node.modList:Flag(nil, "ManaReplacedByInfernalFlame")) + assert.True(node.modList:Flag(nil, "InfernalFlameInsteadOfManaCost")) + end) + + it("replaces maximum Mana with twice as much maximum Infernal Flame", function() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + local mana = withMods("").Mana + assert.True(mana > 0) + local output = withMods("Maximum Mana is replaced by twice as much Maximum Infernal Flame") + assert.are.equals(0, output.Mana) + assert.are.equals(mana * 2, output.MaximumInfernalFlame) + end) + + it("turns Mana costs into Infernal Flame gained", function() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + local manaCost = withMods("").ManaCost + assert.True(manaCost > 0) + local output = withMods("Gain Infernal Flame instead of spending Mana for Skill costs") + assert.are.equals(0, output.ManaCost) + assert.False(output.ManaHasCost) + assert.are.equals(manaCost, output.InfernalFlameCost) + assert.True(output.InfernalFlameHasCost) + end) + + it("leaves Mana alone without Pyromantic Pact", function() + build.skillsTab:PasteSocketGroup("Fireball 20/0 1") + local output = withMods("") + assert.is_nil(output.MaximumInfernalFlame) + assert.is_nil(output.InfernalFlameCost) + end) +end) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 50484e61c0..618b5d9755 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -7774,10 +7774,7 @@ c["Gain Guard equal to 20% of missing Energy Shield for 4 seconds when you Dodge c["Gain Guard equal to Current Runic Ward for 10 seconds when Effect ends"]={nil,"Guard equal to Current Runic Ward when Effect ends "} c["Gain Guard equal to Current Runic Ward for 10 seconds when Effect ends Excess Life Recovery added as Guard for 10 seconds"]={nil,"Guard equal to Current Runic Ward when Effect ends Excess Life Recovery added as Guard "} c["Gain Immunity to Physical Damage for 1.5 seconds on Rampage"]={nil,"Immunity to Physical Damage for 1.5 seconds on"} -c["Gain Infernal Flame instead of spending Mana for Skill costs"]={nil,"Infernal Flame instead of spending Mana for Skill costs "} -c["Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum"]={nil,"Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum "} -c["Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame"]={nil,"Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame "} -c["Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds"]={nil,"Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds "} +c["Gain Infernal Flame instead of spending Mana for Skill costs"]={{[1]={flags=0,keywordFlags=0,name="InfernalFlameInsteadOfManaCost",type="FLAG",value=true}},nil} c["Gain Maddening Presence for 10 seconds when you Kill a Rare or Unique Enemy"]={{[1]={[1]={type="Condition",var="KilledUniqueEnemy"},flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="HasMaddeningPresence",type="FLAG",value=true}}}},nil} c["Gain Onslaught for 4 seconds on Hit while at maximum Frenzy Charges"]={{[1]={[1]={stat="FrenzyCharges",thresholdStat="FrenzyChargesMax",type="StatThreshold"},[2]={type="Condition",var="HitRecently"},flags=0,keywordFlags=0,name="Onslaught",type="FLAG",value=true}},nil} c["Gain Onslaught for 4 seconds when a Minion Dies"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Condition:Onslaught",type="FLAG",value=true}}}}," when a Dies "} @@ -8572,11 +8569,7 @@ c["Maximum Block chance is 75%"]={{[1]={flags=0,keywordFlags=0,name="BlockChance c["Maximum Chance to Evade is 50%"]={{[1]={flags=0,keywordFlags=0,name="EvadeChanceMax",type="MAX",value=50}},nil} c["Maximum Energy Shield cannot be Converted"]={{[1]={flags=0,keywordFlags=0,name="EnergyShieldCannotBeConverted",type="FLAG",value=true}},nil} c["Maximum Life is 1"]={{[1]={flags=0,keywordFlags=0,name="Life",type="OVERRIDE",value=1}},nil} -c["Maximum Mana is replaced by twice as much Maximum Infernal Flame"]={nil,"Maximum Mana is replaced by twice as much Maximum Infernal Flame "} -c["Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs"]={nil,"Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs "} -c["Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum"]={nil,"Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum "} -c["Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame"]={nil,"Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame "} -c["Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds"]={nil,"Maximum Mana is replaced by twice as much Maximum Infernal Flame Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds "} +c["Maximum Mana is replaced by twice as much Maximum Infernal Flame"]={{[1]={flags=0,keywordFlags=0,name="ManaReplacedByInfernalFlame",type="FLAG",value=true}},nil} c["Maximum Physical Damage Reduction is 50%"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamageReductionMax",type="MAX",value=50}},nil} c["Maximum Quality is 200%"]={{},nil} c["Maximum Quality is 40%"]={{},nil} @@ -10003,7 +9996,6 @@ c["Your speed is Unaffected by Slows while Sprinting"]={nil,"Your speed is Unaff c["Your speed is Unaffected by Slows while Sprinting 10% less Movement and Skill Speed per Dodge Roll in the past 20 seconds"]={nil,"Your speed is Unaffected by Slows while Sprinting 10% less Movement and Skill Speed per Dodge Roll in the past 20 seconds "} c["Your speed is unaffected by Slows"]={{[1]={flags=0,keywordFlags=0,name="UnaffectedBySlows",type="FLAG",value=true}},nil} c["Your spells have 100% chance to Shock against Frozen Enemies"]={nil,"Your spells have 100% chance to Shock against Frozen Enemies "} -end)();(function() c["Zealot's Oath"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Zealot's Oath"},[2]={flags=0,keywordFlags=0,name="Condition:HaveZealot'sOath",type="FLAG",value=true}},nil} c["Zealot's Oath during Effect"]={{[1]={[1]={type="Condition",var="UsingFlask"},flags=0,keywordFlags=0,name="ZealotsOath",type="FLAG",value=true}},nil} c["additional Elemental Infusion of the same type"]={nil,"additional Elemental Infusion of the same type "} @@ -10011,6 +10003,7 @@ c["additional Rune-only sockets:"]={{},nil} c["as being boosted by Chilled Ground"]={nil,"as being boosted by Chilled Ground "} c["as being boosted by Ignited Ground"]={nil,"as being boosted by Ignited Ground "} c["as being boosted by Ignited, Shocked, and Chilled Ground"]={nil,"as being boosted by Ignited, Shocked, and Chilled Ground "} +end)();(function() c["as being boosted by Shocked Ground"]={nil,"as being boosted by Shocked Ground "} c["being Shapeshifted for at least 8 seconds"]={nil,"being Shapeshifted for at least 8 seconds "} c["for 4 seconds, every 0.25 seconds while raised"]={nil,"for 4 seconds, every 0.25 seconds while raised "} diff --git a/src/Modules/BuildDisplayStats.lua b/src/Modules/BuildDisplayStats.lua index 1547d24501..c529507c1c 100644 --- a/src/Modules/BuildDisplayStats.lua +++ b/src/Modules/BuildDisplayStats.lua @@ -111,6 +111,8 @@ local displayStats = { { stat = "BrandAttachmentRangeMetre", label = "Attachment Range", fmt = ".1fm", flag = "brand" }, { stat = "BrandTicks", label = "Activations per Brand", fmt = "d", flag = "brand" }, { 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 = "InfernalFlameCost", label = "Infernal Flame Gain", fmt = "d", color = colorCodes.FIRE, condFunc = function(v,o) return o.InfernalFlameHasCost end }, + { stat = "InfernalFlamePerSecondCost", label = "Infernal Flame per second", fmt = ".2f", color = colorCodes.FIRE, condFunc = function(v,o) return o.InfernalFlamePerSecondHasCost 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 per second", fmt = ".2f", color = colorCodes.MANA, pool = "ManaUnreserved", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPerSecondHasCost end }, { stat = "ManaPercentPerSecondCost", label = "Mana Cost per second", fmt = ".2f%%", color = colorCodes.MANA, pool = "ManaUnreservedPercent", compPercent = true, lowerIsBetter = true, condFunc = function(v,o) return o.ManaPercentPerSecondHasCost end }, @@ -168,6 +170,7 @@ local displayStats = { { stat = "LifeLeechGainPerHit", label = "Life Leech/Gain per Hit", fmt = ".1f", color = colorCodes.LIFE, compPercent = true }, { }, { stat = "Mana", label = "Total Mana", fmt = "d", color = colorCodes.MANA, compPercent = true, modNames = { "Mana" }, ignoredSections = { "Base from Gear", "Inc. from Tree" } }, + { stat = "MaximumInfernalFlame", label = "Max Infernal Flame", fmt = "d", color = colorCodes.FIRE, compPercent = true, condFunc = function(v,o) return v > 0 end }, { stat = "Spec:ManaInc", label = "%Inc Mana from Tree", color = colorCodes.MANA, fmt = "d%%" }, { stat = "ManaUnreserved", label = "Unreserved Mana", fmt = "d", color = colorCodes.MANA, condFunc = function(v,o) return v < o.Mana end, compPercent = true, warnFunc = function(v) return v < 0 and "Your unreserved Mana is negative" end, breakdown = "ManaReserved" }, { stat = "ManaUnreservedPercent", label = "Unreserved Mana", fmt = "d%%", color = colorCodes.MANA, condFunc = function(v, o) return v < 100 end, breakdown = "ManaReserved" }, diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index de8d8996b5..9bf0a6b05f 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -94,6 +94,11 @@ function calcs.doActorLifeManaSpirit(actor, skipBreakdown) local override = modDB:Override(nil, res) output[res.."HasOverride"] = override ~= nil output[res] = override or m_max(round((base * (1 - conv/100) + extra) * (1 + inc/100) * more + total), 1) + if res == "Mana" and modDB:Flag(nil, "ManaReplacedByInfernalFlame") then + -- Pyromantic Pact: maximum Mana is replaced by twice as much maximum Infernal Flame + output.MaximumInfernalFlame = output.Mana * 2 + output.Mana = 0 + end if breakdown then if inc ~= 0 or more ~= 1 or conv ~= 0 or extra ~= 0 or total ~= 0 then breakdown[res][1] = s_format("%g ^8(base)", base) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 960a5e16d4..9b58351f58 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -2393,6 +2393,20 @@ function calcs.offence(env, actor, activeSkill) end end end + -- Pyromantic Pact: Mana costs give Infernal Flame instead of spending Mana + if skillModList:Flag(skillCfg, "InfernalFlameInsteadOfManaCost") then + for _, cost in ipairs({ "Cost", "PerSecondCost" }) do + if output["Mana" .. cost] then + output["InfernalFlame" .. cost] = output["Mana" .. cost] + output["InfernalFlame" .. cost:gsub("Cost$", "HasCost")] = output["Mana" .. cost:gsub("Cost$", "HasCost")] + if breakdown then + breakdown["InfernalFlame" .. cost] = breakdown["Mana" .. cost] + end + output["Mana" .. cost] = 0 + output["Mana" .. cost:gsub("Cost$", "HasCost")] = false + end + end + end -- Eldritch Battery adds maximum Energy Shield to the Mana available for payable-cost damage. output.ManaCostPayablePool = (output.ManaUnreserved or 0) + (modDB:Flag(nil, "EnergyShieldProtectsMana") and output.EnergyShield or 0) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 787ffca96b..cc876216ad 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -704,6 +704,8 @@ return { { label = "Spirit % Cost", color = colorCodes.SPIRIT, haveOutput = "SpiritPercentHasCost", { format = "{0:output:SpiritPercentCost}", { breakdown = "SpiritPercentCost" }, { modName = { "SpiritCost", "Cost", "SpiritCostNoMult" }, cfg = "skill" }, }, }, { label = "Mana Cost", color = colorCodes.MANA, haveOutput = "ManaHasCost", { format = "{0:output:ManaCost}", { breakdown = "ManaCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, { label = "Mana % Cost", color = colorCodes.MANA, haveOutput = "ManaPercentHasCost", { format = "{0:output:ManaPercentCost}", { breakdown = "ManaPercentCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, + { label = "Infernal Flame", color = colorCodes.FIRE, haveOutput = "InfernalFlameHasCost", { format = "{0:output:InfernalFlameCost}", { breakdown = "InfernalFlameCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, + { label = "Infernal Flame/s", color = colorCodes.FIRE, haveOutput = "InfernalFlamePerSecondHasCost", { format = "{2:output:InfernalFlamePerSecondCost}", { breakdown = "InfernalFlamePerSecondCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, { label = "Mana per second", color = colorCodes.MANA, haveOutput = "ManaPerSecondHasCost", { format = "{2:output:ManaPerSecondCost}", { breakdown = "ManaPerSecondCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, { label = "Mana % per second", color = colorCodes.MANA, haveOutput = "ManaPercentPerSecondHasCost", { format = "{2:output:ManaPercentPerSecondCost}", { breakdown = "ManaPercentPerSecondCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, { label = "Life Cost", color = colorCodes.LIFE, haveOutput = "LifeHasCost", { format = "{0:output:LifeCost}", { breakdown = "LifeCost" }, { modName = { "LifeCost", "Cost", "LifeCostNoMult" }, cfg = "skill" }, }, }, @@ -1666,6 +1668,7 @@ return { { label = "Total Base", { format = "{0:mod:1}", { modName = "Mana", modType = "BASE" }, }, }, { label = "Total Increased", { format = "{0:mod:1}%", { modName = "Mana", modType = "INC" }, }, }, { label = "Total", { format = "{0:output:Mana}", { breakdown = "Mana" }, }, }, + { label = "Max Infernal Flame", haveOutput = "MaximumInfernalFlame", { format = "{0:output:MaximumInfernalFlame}", { modName = { "Mana" } }, }, }, { label = "Reserved", { format = "{0:output:ManaReserved} ({0:output:ManaReservedPercent}%)", { breakdown = "ManaReserved" }, }, }, { label = "Unreserved", { format = "{0:output:ManaUnreserved} ({0:output:ManaUnreservedPercent}%)" }, }, { label = "Recovery", { format = "{1:output:ManaRegenRecovery} ({1:output:ManaRegenPercent}%)", diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index ff8a00f8fa..67ec7642b6 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3443,6 +3443,8 @@ local specialModList = { } end, -- Witch -- Infernalist ["demonflame has no maximum"] = { mod("Multiplier:DemonFlameMaximum", "BASE", 999) }, + ["maximum mana is replaced by twice as much maximum infernal flame"] = { flag("ManaReplacedByInfernalFlame") }, + ["gain infernal flame instead of spending mana for skill costs"] = { flag("InfernalFlameInsteadOfManaCost") }, -- Druid -- Shaman ["enemies in your presence have exposure"] = { mod("EnemyModifier", "LIST", { mod = mod("FireExposure", "BASE", 20, { type = "ActorCondition", actor = "enemy", var = "EnemyInPresence" }) }),