diff --git a/spec/System/TestBirthedReservation_spec.lua b/spec/System/TestBirthedReservation_spec.lua new file mode 100644 index 0000000000..565e050d2c --- /dev/null +++ b/spec/System/TestBirthedReservation_spec.lua @@ -0,0 +1,58 @@ +describe("TestBirthedReservation", function() + before_each(function() + newBuild() + build.configTab.input.customMods = "+1000 to Spirit" + build.configTab:BuildModList() + end) + + local function grantAmulet(baseName, skillLine) + build.itemsTab:CreateDisplayItemFromRaw("New Item\n"..baseName.."\nImplicits: 1\nGrants Skill: "..skillLine.."\n") + build.itemsTab:AddDisplayItem() + end + + it("Absent Amulet grants a reservation-free skill", function() + grantAmulet("Absent Amulet", "Level 20 Archmage") + runCallback("OnFrame") + assert.are.equals(0, build.calcsTab.mainOutput.SpiritReserved) + end) + + it("other Birthed amulets also grant reservation-free skills", function() + grantAmulet("Lament Amulet", "Level 20 Arctic Armour") + runCallback("OnFrame") + assert.are.equals(0, build.calcsTab.mainOutput.SpiritReserved) + + newBuild() + build.configTab.input.customMods = "+1000 to Spirit" + build.configTab:BuildModList() + grantAmulet("Portent Amulet", "Level 20 Wolf Pack") + runCallback("OnFrame") + assert.are.equals(0, build.calcsTab.mainOutput.SpiritReserved) + end) + + it("support gems added to a birthed-granted skill still reserve", function() + grantAmulet("Absent Amulet", "Level 20 Archmage") + build.skillsTab:PasteSocketGroup("Slot: Amulet\nClarity I 1/0 1\n") + runCallback("OnFrame") + assert.are.equals(10, build.calcsTab.mainOutput.SpiritReserved) + end) + + it("support reservation conversions still apply", function() + grantAmulet("Absent Amulet", "Level 20 Archmage") + build.skillsTab:PasteSocketGroup("Slot: Amulet\nClarity I 1/0 1\nAtziri's Communion 1/0 1\n") + runCallback("OnFrame") + assert.is_true(build.calcsTab.mainOutput.LifeReservedPercent > 0) + assert.are.equals(0, build.calcsTab.mainOutput.SpiritReserved) + end) + + it("a non-birthed item granting the same skill still reserves normally", function() + grantAmulet("Lapis Amulet", "Level 20 Archmage") + runCallback("OnFrame") + assert.are.equals(100, build.calcsTab.mainOutput.SpiritReserved) + end) + + it("a socketed copy of the skill still reserves normally", function() + build.skillsTab:PasteSocketGroup("Archmage 20/0 1\n") + runCallback("OnFrame") + assert.are.equals(100, build.calcsTab.mainOutput.SpiritReserved) + end) +end) diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index 5ebd18d29c..ff2b15fe0f 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -2149,6 +2149,7 @@ function ItemClass:BuildModList() skillId = skill.skillId, level = skill.level, noSupports = skill.noSupports, + noReservation = self.base and self.base.grantedSkillsHaveNoReservation or nil, source = self.modSource, triggered = skill.triggered, triggerChance = skill.triggerChance, diff --git a/src/Data/Bases/amulet.lua b/src/Data/Bases/amulet.lua index 9c2a4d1446..9264b5381a 100644 --- a/src/Data/Bases/amulet.lua +++ b/src/Data/Bases/amulet.lua @@ -114,6 +114,7 @@ itemBases["Runemastered Veridical Chain"] = { itemBases["Lament Amulet"] = { type = "Amulet", tags = { amulet = true, default = true, }, + grantedSkillsHaveNoReservation = true, variantList = { "Arctic Armour", "Herald of Ash", "Herald of Ice", "Herald of Thunder", "Plague Bearer", "Barrier Invocation", "Lingering Illusion", "Ghost Dance", "Mana Remnants", "Magma Barrier", "Raging Spirits", "Wind Dancer", "Cast on Minion Death", "Scavenged Plating", "War Banner", "Defiance Banner", "Dread Banner", "Time of Need", "Attrition", "Charge Regulation", "Shard Scavenger", "Overwhelming Presence", "Alchemist's Boon", "Reaper's Invocation", "Berserk", "Herald of Plague", "Herald of Blood", "Withering Presence", "Ravenous Swarm", "Combat Frenzy", "Trail of Caltrops", "Convalescence", "Iron Ward", "Siphon Elements", "Briarpatch", "Savage Fury", "Barkskin", }, implicit = "-1 Prefix Modifier allowed\n{variant:1}Grants Skill: Level (1-20) Arctic Armour\n{variant:2}Grants Skill: Level (1-20) Herald of Ash\n{variant:3}Grants Skill: Level (1-20) Herald of Ice\n{variant:4}Grants Skill: Level (1-20) Herald of Thunder\n{variant:5}Grants Skill: Level (1-20) Plague Bearer\n{variant:6}Grants Skill: Level (1-20) Barrier Invocation\n{variant:7}Grants Skill: Level (1-20) Lingering Illusion\n{variant:8}Grants Skill: Level (1-20) Ghost Dance\n{variant:9}Grants Skill: Level (1-20) Mana Remnants\n{variant:10}Grants Skill: Level (1-20) Magma Barrier\n{variant:11}Grants Skill: Level (1-20) Raging Spirits\n{variant:12}Grants Skill: Level (1-20) Wind Dancer\n{variant:13}Grants Skill: Level (1-20) Cast on Minion Death\n{variant:14}Grants Skill: Level (1-20) Scavenged Plating\n{variant:15}Grants Skill: Level (1-20) War Banner\n{variant:16}Grants Skill: Level (1-20) Defiance Banner\n{variant:17}Grants Skill: Level (1-20) Dread Banner\n{variant:18}Grants Skill: Level (1-20) Time of Need\n{variant:19}Grants Skill: Level (1-20) Attrition\n{variant:20}Grants Skill: Level (1-20) Charge Regulation\n{variant:21}Grants Skill: Level (1-20) Shard Scavenger\n{variant:22}Grants Skill: Level (1-20) Overwhelming Presence\n{variant:23}Grants Skill: Level (1-20) Alchemist's Boon\n{variant:24}Grants Skill: Level (1-20) Reaper's Invocation\n{variant:25}Grants Skill: Level (1-20) Berserk\n{variant:26}Grants Skill: Level (1-20) Herald of Plague\n{variant:27}Grants Skill: Level (1-20) Herald of Blood\n{variant:28}Grants Skill: Level (1-20) Withering Presence\n{variant:29}Grants Skill: Level (1-20) Ravenous Swarm\n{variant:30}Grants Skill: Level (1-20) Combat Frenzy\n{variant:31}Grants Skill: Level (1-20) Trail of Caltrops\n{variant:32}Grants Skill: Level (1-20) Convalescence\n{variant:33}Grants Skill: Level (1-20) Iron Ward\n{variant:34}Grants Skill: Level (1-20) Siphon Elements\n{variant:35}Grants Skill: Level (1-20) Briarpatch\n{variant:36}Grants Skill: Level (1-20) Savage Fury\n{variant:37}Grants Skill: Level (1-20) Barkskin", implicitModTypes = { { }, }, @@ -122,6 +123,7 @@ itemBases["Lament Amulet"] = { itemBases["Portent Amulet"] = { type = "Amulet", tags = { amulet = true, default = true, }, + grantedSkillsHaveNoReservation = true, variantList = { "Wolf Pack", "Blink", "Elemental Invocation", "Elemental Conflux", "Sacrifice", "Mirage Archer", "Feral Invocation", }, implicit = "-1 Suffix Modifier allowed\n{variant:1}Grants Skill: Level (1-20) Wolf Pack\n{variant:2}Grants Skill: Level (1-20) Blink\n{variant:3}Grants Skill: Level (1-20) Elemental Invocation\n{variant:4}Grants Skill: Level (1-20) Elemental Conflux\n{variant:5}Grants Skill: Level (1-20) Sacrifice\n{variant:6}Grants Skill: Level (1-20) Mirage Archer\n{variant:7}Grants Skill: Level (1-20) Feral Invocation", implicitModTypes = { { }, }, @@ -130,6 +132,7 @@ itemBases["Portent Amulet"] = { itemBases["Absent Amulet"] = { type = "Amulet", tags = { amulet = true, default = true, }, + grantedSkillsHaveNoReservation = true, variantList = { "Cast on Elemental Ailment", "Cast on Critical", "Cast on Dodge", "Rhoa Mount", "Archmage", "Trinity", "Eternal Rage", }, implicit = "-1 Prefix Modifier allowed\n-1 Suffix Modifier allowed\n{variant:1}Grants Skill: Level (1-20) Cast on Elemental Ailment\n{variant:2}Grants Skill: Level (1-20) Cast on Critical\n{variant:3}Grants Skill: Level (1-20) Cast on Dodge\n{variant:4}Grants Skill: Level (1-20) Rhoa Mount\n{variant:5}Grants Skill: Level (1-20) Archmage\n{variant:6}Grants Skill: Level (1-20) Trinity\n{variant:7}Grants Skill: Level (1-20) Eternal Rage", implicitModTypes = { { }, { }, }, diff --git a/src/Export/Scripts/bases.lua b/src/Export/Scripts/bases.lua index 7c9eea9740..cd55bd6a82 100644 --- a/src/Export/Scripts/bases.lua +++ b/src/Export/Scripts/bases.lua @@ -171,6 +171,9 @@ directiveTable.base = function(state, args, out) end local inherentSkillType = dat("ItemInherentSkills"):GetRow("BaseItemType", baseItemType) if inherentSkillType then + if inherentSkillType.NoReservation then + out:write('\tgrantedSkillsHaveNoReservation = true,\n') + end local hasVariants = #inherentSkillType.Skill > 1 for index, skill in ipairs(inherentSkillType.Skill) do local skillGem = dat("SkillGems"):GetRow("BaseItemType", skill.BaseItemType) diff --git a/src/Export/spec.lua b/src/Export/spec.lua index 7a0ebd8585..327748c126 100644 --- a/src/Export/spec.lua +++ b/src/Export/spec.lua @@ -31728,10 +31728,10 @@ return { }, [3]={ list=false, - name="Mainhand", + name="NoReservation", refTo="", type="Bool", - width=50 + width=80 } }, itemisedcorpse={ diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index 05aab91e53..49d8ca6c40 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -795,6 +795,12 @@ function calcs.buildActiveSkillModList(env, activeSkill) grantedEffectLevel[k] = v end end + if activeEffect.srcInstance and activeEffect.srcInstance.noReservation then + for _, resource in ipairs({ "mana", "life", "spirit" }) do + grantedEffectLevel[resource.."ReservationFlat"] = 0 + grantedEffectLevel[resource.."ReservationPercent"] = 0 + end + end activeEffect.grantedEffectLevel = grantedEffectLevel -- Add extra modifiers from granted effect level diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 38a68d62f1..5ba727778c 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -1534,6 +1534,7 @@ function calcs.initEnv(build, mode, override, specEnv) activeGemInstance.enableGlobal1 = true activeGemInstance.noSupports = grantedSkill.noSupports group.noSupports = grantedSkill.noSupports + activeGemInstance.noReservation = grantedSkill.noReservation activeGemInstance.triggered = grantedSkill.triggered activeGemInstance.triggerChance = grantedSkill.triggerChance wipeTable(group.gemList)