Skip to content
Merged
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
102 changes: 102 additions & 0 deletions spec/System/TestIdolatry_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
describe("TestIdolatry", function()
before_each(function()
newBuild()
end)

-- The Spirit Walker "Idolatry" notable grants three mods that scale with the
-- number of Idols / non-Idol augments (Runes + Soul Cores) socketed across equipped items.

-- Counting: CalcSetup tallies socketed augments by type into the IdolsInEquipment and
-- NonIdolAugmentsInEquipment multipliers, which the three Idolatry mods scale against.
it("counts Idols and non-Idol augments across equipped items", function()
-- Gloves with 2 Idols socketed
build.itemsTab:CreateDisplayItemFromRaw([[
Rarity: MAGIC
Idolatry Test Gloves
Vaal Gloves
Sockets: S S
Rune: Idol of Sirrius
Rune: Idol of Sirrius
Implicits: 0
]])
build.itemsTab:AddDisplayItem()

-- Quarterstaff with 3 Soul Cores socketed (non-Idol augments)
build.itemsTab:CreateDisplayItemFromRaw([[
Rarity: MAGIC
Idolatry Test Staff
Aegis Quarterstaff
Sockets: S S S
Rune: Soul Core of Cholotl
Rune: Soul Core of Zantipi
Rune: Soul Core of Atmohua
Implicits: 0
]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")

local modDB = build.calcsTab.mainEnv.modDB
assert.are.equals(2, modDB.multipliers.IdolsInEquipment)
assert.are.equals(3, modDB.multipliers.NonIdolAugmentsInEquipment)
end)

-- Empty sockets (itemSocketCount populated while item.runes has no entry for the slot, e.g. a
-- freshly created base item) must not be counted as augments.
it("does not count empty sockets as augments", function()
build.itemsTab:CreateDisplayItemFromRaw([[
Rarity: MAGIC
Empty Socket Test Gloves
Vaal Gloves
Sockets: S S
Implicits: 0
]])
build.itemsTab:AddDisplayItem()
runCallback("OnFrame")

local modDB = build.calcsTab.mainEnv.modDB
assert.is_nil(modDB.multipliers.IdolsInEquipment)
assert.is_nil(modDB.multipliers.NonIdolAugmentsInEquipment)
end)

-- Parsing: the three stat lines must resolve to mods that scale against those multipliers.
it("parses the three Idolatry stat lines", function()
local parseMod = LoadModule("Modules/ModParser")

-- Helper to find the Multiplier tag on a mod (tags are stored as array entries)
local function multiplierTag(mod)
for _, tag in ipairs(mod) do
if tag.type == "Multiplier" then return tag end
end
end

-- 1) Companion damage scales by the player's Idol count (read via actor = "player"
-- since the mod is evaluated in the companion's own modDB).
local companion = parseMod("Companions deal 10% increased damage per Idol in your Equipment")
assert.are.equals(1, #companion)
assert.are.equals("MinionModifier", companion[1].name)
local inner = companion[1].value.mod
assert.are.equals("Damage", inner.name)
assert.are.equals("INC", inner.type)
assert.are.equals(10, inner.value)
local companionTag = multiplierTag(inner)
assert.is_not_nil(companionTag)
assert.are.equals("IdolsInEquipment", companionTag.var)
assert.are.equals("player", companionTag.actor)

-- 2) Reservation Efficiency scales by the Idol count (player context).
local reservation = parseMod("2% increased Reservation Efficiency of Skills per Idol in your Equipment")
assert.are.equals(1, #reservation)
assert.are.equals("ReservationEfficiency", reservation[1].name)
assert.are.equals("INC", reservation[1].type)
assert.are.equals(2, reservation[1].value)
assert.are.equals("IdolsInEquipment", multiplierTag(reservation[1]).var)

-- 3) Elemental Resistance penalty scales by the non-Idol augment count (player context).
local resist = parseMod("-4% to all Elemental Resistances per non-Idol Augment in your Equipment")
assert.are.equals(1, #resist)
assert.are.equals("ElementalResist", resist[1].name)
assert.are.equals("BASE", resist[1].type)
assert.are.equals(-4, resist[1].value)
assert.are.equals("NonIdolAugmentsInEquipment", multiplierTag(resist[1]).var)
end)
end)
9 changes: 3 additions & 6 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ c["-30% to Lightning Resistance"]={{[1]={flags=0,keywordFlags=0,name="LightningR
c["-30% to all Elemental Resistances"]={{[1]={flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-30}},nil}
c["-35% to Lightning Resistance"]={{[1]={flags=0,keywordFlags=0,name="LightningResist",type="BASE",value=-35}},nil}
c["-4 Physical Damage taken from Attack Hits"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamageTakenFromAttacks",type="BASE",value=-4}},nil}
c["-4% to all Elemental Resistances per non-Idol Augment in your Equipment"]={{[1]={flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-4}}," per non-Idol Augment in your Equipment "}
c["-4% to all Elemental Resistances per non-Idol Augment in your Equipment"]={{[1]={[1]={actor="player",type="Multiplier",var="NonIdolAugmentsInEquipment"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-4}},nil}
c["-5% to all Elemental Resistances"]={{[1]={flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=-5}},nil}
c["-5% to amount of Damage Prevented by Deflection"]={{[1]={flags=0,keywordFlags=0,name="DeflectEffect",type="BASE",value=-5}},nil}
c["-6% to amount of Damage Prevented by Deflection"]={{[1]={flags=0,keywordFlags=0,name="DeflectEffect",type="BASE",value=-6}},nil}
Expand Down Expand Up @@ -1819,8 +1819,7 @@ c["2% increased Maximum Life per socketed Grand Spectrum"]={{[1]={[1]={type="Mul
c["2% increased Movement Speed"]={{[1]={flags=0,keywordFlags=0,name="MovementSpeed",type="INC",value=2}},nil}
c["2% increased Movement Speed while Sprinting"]={{[1]={[1]={type="Condition",var="Sprinting"},flags=0,keywordFlags=0,name="MovementSpeed",type="INC",value=2}},nil}
c["2% increased Parried Debuff Duration per 10 Tribute"]={{[1]={[1]={actor="parent",div=10,stat="Tribute",type="PerStat"},flags=0,keywordFlags=0,name="ParryDebuffDuration",type="INC",value=2}},nil}
c["2% increased Reservation Efficiency of Skills per Idol in your Equipment"]={{[1]={flags=0,keywordFlags=0,name="ReservationEfficiency",type="INC",value=2}}," per Idol in your Equipment "}
c["2% increased Reservation Efficiency of Skills per Idol in your Equipment -4% to all Elemental Resistances per non-Idol Augment in your Equipment"]={{[1]={flags=0,keywordFlags=0,name="ReservationEfficiency",type="INC",value=2}}," per Idol in your Equipment -4% to all Elemental Resistances per non-Idol Augment in your Equipment "}
c["2% increased Reservation Efficiency of Skills per Idol in your Equipment"]={{[1]={[1]={actor="player",type="Multiplier",var="IdolsInEquipment"},flags=0,keywordFlags=0,name="ReservationEfficiency",type="INC",value=2}},nil}
c["2% increased Skill Speed"]={{[1]={flags=0,keywordFlags=0,name="Speed",type="INC",value=2},[2]={flags=0,keywordFlags=0,name="WarcrySpeed",type="INC",value=2},[3]={flags=0,keywordFlags=0,name="TotemPlacementSpeed",type="INC",value=2}},nil}
c["2% increased Skill Speed with Channelling Skills"]={{[1]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="Speed",type="INC",value=2},[2]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="WarcrySpeed",type="INC",value=2},[3]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="TotemPlacementSpeed",type="INC",value=2}},nil}
c["2% increased Spell Damage per 10 Intelligence"]={{[1]={[1]={div=10,stat="Int",type="PerStat"},flags=2,keywordFlags=0,name="Damage",type="INC",value=2}},nil}
Expand Down Expand Up @@ -4836,9 +4835,7 @@ c["Charms use no Charges"]={{[1]={flags=0,keywordFlags=0,name="CharmsUseNoCharge
c["Cold Damage from Hits Contributes to Flammability and Ignite Magnitudes instead of Chill Magnitude or Freeze Buildup"]={{[1]={flags=0,keywordFlags=0,name="ColdCanIgnite",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ColdCannotChill",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="ColdCannotFreeze",type="FLAG",value=true}},nil}
c["Cold Resistance is unaffected by Area Penalties"]={nil,"Cold Resistance is unaffected by Area Penalties "}
c["Companions deal 10% increased Damage"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=10}}}},nil}
c["Companions deal 10% increased damage per Idol in your Equipment"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=10}}}}," per Idol in your Equipment "}
c["Companions deal 10% increased damage per Idol in your Equipment 2% increased Reservation Efficiency of Skills per Idol in your Equipment"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=10}}}}," per Idol in your Equipment 2% increased Reservation Efficiency of Skills per Idol in your Equipment "}
c["Companions deal 10% increased damage per Idol in your Equipment 2% increased Reservation Efficiency of Skills per Idol in your Equipment -4% to all Elemental Resistances per non-Idol Augment in your Equipment"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=10}}}}," per Idol in your Equipment 2% increased Reservation Efficiency of Skills per Idol in your Equipment -4% to all Elemental Resistances per non-Idol Augment in your Equipment "}
c["Companions deal 10% increased damage per Idol in your Equipment"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="IdolsInEquipment"},flags=0,keywordFlags=0,name="Damage",type="INC",value=10}}}},nil}
c["Companions deal 12% increased Damage"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=12}}}},nil}
c["Companions deal 15% increased Damage"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Damage",type="INC",value=15}}}},nil}
c["Companions deal 60% increased damage against Immobilised enemies"]={{[1]={[1]={skillType=219,type="SkillType"},flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="enemy",type="ActorCondition",var="Immobilised"},flags=0,keywordFlags=0,name="Damage",type="INC",value=60}}}},nil}
Expand Down
105 changes: 105 additions & 0 deletions src/Data/ModRunes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4994,6 +4994,111 @@ return {
rank = { 50 },
},
},
["Carved Cunning"] = {
["helmet"] = {
type = "Idol",
"Enemies which are on Full Life cannot Evade your Hits",
"Bonded: 30% increased Accuracy Rating",
statOrder = { 5293, 1331 },
tradeHashes = { [4111745607] = { "Enemies which are on Full Life cannot Evade your Hits" }, },
rank = { 60 },
},
["body armour"] = {
type = "Idol",
"Prevent +5% of Damage from Deflected Hits if you've",
"Deflected no Hits Recently",
"Bonded: 8% increased Deflection Rating",
statOrder = { 4668, 4668.1, 6106 },
tradeHashes = { [967155385] = { "Prevent +5% of Damage from Deflected Hits if you've", "Deflected no Hits Recently" }, },
rank = { 60 },
},
["boots"] = {
type = "Idol",
"Gain Onslaught for 4 seconds when your Marks Activate",
"Bonded: Buffs on you expire 10% slower",
statOrder = { 6805, 5228 },
tradeHashes = { [1811977226] = { "Gain Onslaught for 4 seconds when your Marks Activate" }, },
rank = { 60 },
},
},
["Carved Majesty"] = {
["body armour"] = {
type = "Idol",
"+3 to Spirit per Idol socketed in your Equipment",
"Bonded: 5% increased Spirit",
statOrder = { 4742, 1416 },
tradeHashes = { [1073847159] = { "+3 to Spirit per Idol socketed in your Equipment" }, },
rank = { 60 },
},
["gloves"] = {
type = "Idol",
"Companions gain Onslaught for 4 seconds on Hitting your Marked targets",
"Bonded: Companions deal 30% increased Damage",
statOrder = { 5720, 5709 },
tradeHashes = { [226999623] = { "Companions gain Onslaught for 4 seconds on Hitting your Marked targets" }, },
rank = { 60 },
},
["boots"] = {
type = "Idol",
"1% increased Movement Speed while Sprinting per Persistent Minion",
"Bonded: Minions have 12% increased maximum Life",
statOrder = { 10042, 1025 },
tradeHashes = { [3639405795] = { "1% increased Movement Speed while Sprinting per Persistent Minion" }, },
rank = { 60 },
},
},
["Carved Mischief"] = {
["helmet"] = {
type = "Idol",
"Gain Guard equal to 10% of maximum Life for 4 seconds on taking Savage Hit",
"Bonded: Buffs on you expire 10% slower",
statOrder = { 6783, 5228 },
tradeHashes = { [3863682550] = { "Gain Guard equal to 10% of maximum Life for 4 seconds on taking Savage Hit" }, },
rank = { 60 },
},
["gloves"] = {
type = "Idol",
"+5% to maximum Block chance if you've Blocked with a raised Shield Recently",
"Bonded: 20% increased Block chance",
statOrder = { 4197, 1132 },
tradeHashes = { [3617372509] = { "+5% to maximum Block chance if you've Blocked with a raised Shield Recently" }, },
rank = { 60 },
},
["body armour"] = {
type = "Idol",
"200% increased Stun Threshold if you've been Stunned Recently",
"Bonded: 25% increased Stun Threshold",
statOrder = { 10104, 2981 },
tradeHashes = { [751944209] = { "200% increased Stun Threshold if you've been Stunned Recently" }, },
rank = { 60 },
},
},
["Carved Tenacity"] = {
["helmet"] = {
type = "Idol",
"Enemies have no Critical Damage Bonus for 4 seconds after you Blind them",
"Bonded: 20% increased Blind Effect",
statOrder = { 6368, 4916 },
tradeHashes = { [25786091] = { "Enemies have no Critical Damage Bonus for 4 seconds after you Blind them" }, },
rank = { 60 },
},
["gloves"] = {
type = "Idol",
"Enemies you Critically Hit get 100% reduced Life Regeneration Rate for 4 seconds",
"Bonded: 15% increased Critical Hit Chance",
statOrder = { 5809, 975 },
tradeHashes = { [3370077792] = { "Enemies you Critically Hit get 100% reduced Life Regeneration Rate for 4 seconds" }, },
rank = { 60 },
},
["boots"] = {
type = "Idol",
"Your speed is Unaffected by Slows while Sprinting",
"Bonded: 8% increased Movement Speed while Sprinting",
statOrder = { 9911, 10041 },
tradeHashes = { [3128773415] = { "Your speed is Unaffected by Slows while Sprinting" }, },
rank = { 60 },
},
},
["Raven-Touched Shard"] = {
["helmet"] = {
type = "CongealedMist",
Expand Down
1 change: 1 addition & 0 deletions src/Export/Bases/soulcore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ local itemBases = ...
#type Idol
#baseMatch Metadata/Items/SoulCores/Talisman
#baseMatch Metadata/Items/SoulCores/Idol
#baseMatch Metadata/Items/SoulCores/Carved

#type CongealedMist
#baseMatch Metadata/Items/SoulCores/AugmentAnoint
21 changes: 19 additions & 2 deletions src/Modules/CalcSetup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1090,11 +1090,28 @@ function calcs.initEnv(build, mode, override, specEnv)
Int = item.requirements.intMod,
})
end
-- Rune / Soul Core Sockets
-- Rune / Soul Core / Idol Sockets
local socketed = 0
for i = 1, item.itemSocketCount do
if item.runes[i] ~= "None" then
local runeName = item.runes[i]
if runeName and runeName ~= "None" then
socketed = socketed + 1
-- Track Idols vs non-Idol augments (Runes + Soul Cores) across all equipment
local runeData = data.itemMods.Runes[runeName]
local augType
if runeData then
for _, baseEntry in pairs(runeData) do
if type(baseEntry) == "table" and baseEntry.type then
augType = baseEntry.type
break
end
end
end
if augType == "Idol" then
env.itemModDB.multipliers["IdolsInEquipment"] = (env.itemModDB.multipliers["IdolsInEquipment"] or 0) + 1
elseif augType then
env.itemModDB.multipliers["NonIdolAugmentsInEquipment"] = (env.itemModDB.multipliers["NonIdolAugmentsInEquipment"] or 0) + 1
end
end
end
env.itemModDB.multipliers["RunesSocketedIn"..slotName] = socketed
Expand Down
2 changes: 2 additions & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,8 @@ local modTagList = {
["per (%d+)%% (%a+) effect on enemy"] = function(num, _, effectName) return { tag = { type = "Multiplier", var = firstToUpper(effectName) .. "Effect", div = num, actor = "enemy" } } end,
["per socketed rune or soul core"] = { tag = { type = "Multiplier", var = "RunesSocketedIn{SlotName}" } },
["per socket filled"] = { tag = { type = "Multiplier", var = "RunesSocketedIn{SlotName}" } },
["per idol in your equipment"] = { tag = { type = "Multiplier", var = "IdolsInEquipment", actor = "player" } },
["per non%-idol augment in your equipment"] = { tag = { type = "Multiplier", var = "NonIdolAugmentsInEquipment", actor = "player" } },
["per (%d+) (%a+) support gems socketed"] = function(num, _, color) return { tag = { type = "Multiplier", var = firstToUpper(color) .. "SupportGems", div = num } } end,
["per socketed (%a+) support gem"] = function(color) return { tag = { type = "Multiplier", var = firstToUpper(color) .. "SupportGems" } } end,
["for each equipped normal item"] = { tag = { type = "Multiplier", var = "NormalItem" } },
Expand Down
Loading