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
90 changes: 90 additions & 0 deletions spec/System/TestPassiveSpec_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,96 @@ Item Level: 80
assert.are.equals(2, build.calcsTab.mainEnv.weaponSetEnvs[2].weaponSet)
end)

local function selectLeylinesAscendancy(spec)
-- Leylines only counts for its own ascendancy, and changing class resets the
-- tree, so this must run before anything else is allocated
local ascend = spec.tree.ascendNameMap["Disciple of Varashta"]
spec:SelectClass(ascend.classId)
spec:SelectAscendClass(ascend.ascendClassId)
return select(2, assert(findNodeByName(spec, "Baryanic Leylines")))
end

local function socketSmallRadiusJewel(rarity, base)
local nodeId, node = firstNormalJewelSocket(build.spec)
build.spec:AllocNode(node)
local jewel = socketJewel(nodeId, table.concat({
"Rarity: " .. rarity,
"Test Jewel",
base,
"--------",
"Radius: Small",
"--------",
"Item Level: 80",
"--------",
"+10 to Intelligence",
}, "\n"))
runCallback("OnFrame")
return nodeId, node, jewel
end

local function radiusJewelNodeCount(env, socketNodeId)
for _, radiusJewel in ipairs(env.radiusJewelList) do
if radiusJewel.nodeId == socketNodeId then
local count = 0
for _ in pairs(radiusJewel.nodes) do
count = count + 1
end
return count
end
end
end

local function nodesInRadiusCount(node, radiusIndex)
local count = 0
for _ in pairs(node.nodesInRadius[radiusIndex]) do
count = count + 1
end
return count
end

it("Baryanic Leylines increases the radius of non-unique Time-Lost jewels", function()
local leylines = selectLeylinesAscendancy(build.spec)
local socketNodeId, socketNode, jewel = socketSmallRadiusJewel("RARE", "Time-Lost Sapphire")
local baseCount = nodesInRadiusCount(socketNode, jewel.jewelRadiusIndex)
local increasedCount = nodesInRadiusCount(socketNode, data.timeLostJewelIncreasedRadiusIndex[jewel.jewelRadiusIndex])
assert.True(increasedCount > baseCount)
assert.are.equals(baseCount, radiusJewelNodeCount(build.calcsTab.mainEnv, socketNodeId))

build.spec:AllocNode(leylines)
build.buildFlag = true
runCallback("OnFrame")

assert.are.equals(increasedCount, radiusJewelNodeCount(build.calcsTab.mainEnv, socketNodeId))
end)

it("Baryanic Leylines hover previews use the radius the jewel would have", function()
local leylines = selectLeylinesAscendancy(build.spec)
local socketNodeId, socketNode, jewel = socketSmallRadiusJewel("RARE", "Time-Lost Sapphire")
local baseCount = nodesInRadiusCount(socketNode, jewel.jewelRadiusIndex)
local increasedCount = nodesInRadiusCount(socketNode, data.timeLostJewelIncreasedRadiusIndex[jewel.jewelRadiusIndex])

local env = build.calcsTab.calcs.initEnv(build, "CALCULATOR", { addNodes = { [leylines] = true } })
assert.are.equals(increasedCount, radiusJewelNodeCount(env, socketNodeId))

build.spec:AllocNode(leylines)
build.buildFlag = true
runCallback("OnFrame")

env = build.calcsTab.calcs.initEnv(build, "CALCULATOR", { removeNodes = { [leylines] = true } })
assert.are.equals(baseCount, radiusJewelNodeCount(env, socketNodeId))
end)

it("Baryanic Leylines does not change the radius of unique or non-Time-Lost jewels", function()
for _, jewelType in ipairs({ { "UNIQUE", "Time-Lost Sapphire" }, { "RARE", "Sapphire" } }) do
newBuild()
local leylines = selectLeylinesAscendancy(build.spec)
build.spec:AllocNode(leylines)
local socketNodeId, socketNode, jewel = socketSmallRadiusJewel(jewelType[1], jewelType[2])

assert.are.equals(nodesInRadiusCount(socketNode, jewel.jewelRadiusIndex), radiusJewelNodeCount(build.calcsTab.mainEnv, socketNodeId), jewelType[1] .. " " .. jewelType[2])
end
end)

it("does not apply jewel socket passive skill effect to jewels in item-granted Zarokh's Gift", function()
local normalNodeId, normalNode = firstNormalJewelSocket(build.spec)
build.spec:AllocNode(normalNode)
Expand Down
11 changes: 11 additions & 0 deletions src/Classes/PassiveSpec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,13 @@ function PassiveSpecClass:BuildNodePathsToRootNodes(roots)
::continueBuildPath::
end
end

-- Returns the radius index a jewel actually uses in this spec, accounting for
-- "Non-Unique Time-Lost Jewels have 40% increased radius" (Baryanic Leylines)
function PassiveSpecClass:GetJewelRadiusIndex(item)
return data.getTimeLostJewelRadiusIndex(item, self.hasTimeLostJewelRadiusIncrease)
end

-- Rebuilds dependencies and paths for all nodes
function PassiveSpecClass:BuildAllDependsAndPaths()
-- This table will keep track of which nodes have been visited during each path-finding attempt
Expand All @@ -1493,6 +1500,7 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
end
end
wipeTable(intuitiveLeapLikeNodes)
self.hasTimeLostJewelRadiusIncrease = false
for id, node in pairs(self.allocNodes) do
if node.ascendancyName then -- avoid processing potentially replaceable nodes
self.tree:ProcessStats(node)
Expand All @@ -1501,6 +1509,9 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
t_insert(intuitiveLeapLikeNodes, radius)
end
end
if node.modList:Sum("INC", nil, "NonUniqueTimeLostJewelRadius") > 0 then
self.hasTimeLostJewelRadiusIncrease = true
end
processed[id] = true
end
end
Expand Down
25 changes: 18 additions & 7 deletions src/Classes/PassiveTreeView.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,10 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
end
else
-- Jewel in socket is not Thread of Hope or similar
-- Use the increased radii instead of the base ones if the socketed jewel benefits from them
local isIncreased = jewel and build.spec:GetJewelRadiusIndex(jewel) ~= jewel.jewelRadiusIndex
for index, data in ipairs(build.data.jewelRadius) do
if hoverNode.nodesInRadius[index][node.id] then
if (not data.increased) == (not isIncreased) and hoverNode.nodesInRadius[index][node.id] then
-- Draw normal jewel radii
if data.inner == 0 then
SetDrawColor(data.col)
Expand Down Expand Up @@ -1277,8 +1279,8 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
end

-- Draw ring overlays for jewel sockets
local function drawJewelRadius(jewel, scrX, scrY, tint)
local radData = build.data.jewelRadius[jewel.jewelRadiusIndex]
local function drawJewelRadius(jewel, scrX, scrY, tint, jewelSpec)
local radData = build.data.jewelRadius[jewelSpec:GetJewelRadiusIndex(jewel)]
local outerSize = radData.outer * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale
local innerSize = radData.inner * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale * 1.06
SetDrawColor(tint[1], tint[2], tint[3], tint[4])
Expand Down Expand Up @@ -1326,6 +1328,9 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
if node == hoverNode then
local effectiveJewel = jewel or cJewel
local isThreadOfHope = effectiveJewel and effectiveJewel.jewelRadiusLabel == "Variable"
-- Preview the increased radii instead of the base ones if the socketed jewel benefits from them
local jewelSpec = jewel and spec or self.compareSpec
local isIncreased = effectiveJewel and jewelSpec and jewelSpec:GetJewelRadiusIndex(effectiveJewel) ~= effectiveJewel.jewelRadiusIndex
for _, radData in ipairs(build.data.jewelRadius) do
local outerSize = radData.outer * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale
local innerSize = radData.inner * data.gameConstants["PassiveTreeJewelDistanceMultiplier"] * scale
Expand All @@ -1338,7 +1343,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
end
else
-- Standard jewel: draw the full-disc radii (inner == 0)
if innerSize == 0 then
if innerSize == 0 and (not radData.increased) == (not isIncreased) then
SetDrawColor(radData.col)
DrawImage(self.ring, scrX - outerSize, scrY - outerSize, outerSize * 2, outerSize * 2)
end
Expand All @@ -1349,12 +1354,16 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
local pHasRadius = jewel and jewel.jewelRadiusIndex
local cHasRadius = cJewel and cJewel.jewelRadiusIndex
local sameJewel = compareJewelsEqual(jewel, cJewel)
if sameJewel and pHasRadius and cHasRadius then
-- Identical jewels can have different radii when only one spec allocates Baryanic Leylines.
sameJewel = spec:GetJewelRadiusIndex(jewel) == self.compareSpec:GetJewelRadiusIndex(cJewel)
end
if pHasRadius then
local tint = (not self.compareSpec or sameJewel) and JEWEL_RADIUS_TINT_NEUTRAL or JEWEL_RADIUS_TINT_PRIMARY_ONLY
drawJewelRadius(jewel, scrX, scrY, tint)
drawJewelRadius(jewel, scrX, scrY, tint, spec)
end
if cHasRadius and not sameJewel then
drawJewelRadius(cJewel, scrX, scrY, JEWEL_RADIUS_TINT_COMPARE_ONLY)
drawJewelRadius(cJewel, scrX, scrY, JEWEL_RADIUS_TINT_COMPARE_ONLY, self.compareSpec)
end
end
end
Expand Down Expand Up @@ -1869,7 +1878,9 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
local isInRadius = false
for id, socket in pairs(build.itemsTab.sockets) do
if build.itemsTab.activeSocketList and socket.inactive == false or socket.inactive == nil then
isInRadius = isInRadius or (build.spec.nodes[id] and build.spec.nodes[id].nodesInRadius and build.spec.nodes[id].nodesInRadius[4][node.id] ~= nil)
-- index 4 is Very Large; its increased version covers the largest possible Time-Lost radius
local maxRadiusIndex = build.spec.hasTimeLostJewelRadiusIncrease and data.timeLostJewelIncreasedRadiusIndex[4] or 4
isInRadius = isInRadius or (build.spec.nodes[id] and build.spec.nodes[id].nodesInRadius and build.spec.nodes[id].nodesInRadius[maxRadiusIndex][node.id] ~= nil)
if isInRadius then break end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8817,7 +8817,7 @@ c["Non-Keystone Passive Skills in Medium Radius of allocated Keystone Passive Sk
c["Non-Minion Skills have 50% less Reservation Efficiency"]={{[1]={[1]={neg=true,skillType=6,type="SkillType"},flags=0,keywordFlags=0,name="ReservationEfficiency",type="MORE",value=-50}},nil}
c["Non-Unique Life Flasks apply their Effects constantly"]={nil,"Non-Unique Life Flasks apply their Effects constantly "}
c["Non-Unique Life Flasks apply their Effects constantly Recovery from Life Flasks cannot be Instant"]={nil,"Non-Unique Life Flasks apply their Effects constantly Recovery from Life Flasks cannot be Instant "}
c["Non-Unique Time-Lost Jewels have 40% increased radius"]={nil,"Non-Unique Time-Lost Jewels have 40% increased radius "}
c["Non-Unique Time-Lost Jewels have 40% increased radius"]={{[1]={flags=0,keywordFlags=0,name="NonUniqueTimeLostJewelRadius",type="INC",value=40}},nil}
c["Non-instant Recovery from Mana Flasks also applies to Life"]={nil,"Non-instant Recovery from Mana Flasks also applies to Life "}
c["Nova Spells have 20% less Area of Effect"]={{[1]={[1]={skillType=85,type="SkillType"},flags=0,keywordFlags=0,name="AreaOfEffect",type="MORE",value=-20}},nil}
c["Oasis"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Oasis"},[2]={flags=0,keywordFlags=0,name="Condition:HaveOasis",type="FLAG",value=true}},nil}
Expand Down
10 changes: 7 additions & 3 deletions src/Modules/CalcSetup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,9 @@ function calcs.initEnv(build, mode, override, specEnv)
local nodesModsList = calcs.buildModListForNodeList(env, env.allocNodes, true, true)
env.useAltGemQualityStats = nodesModsList:Flag(nil, "GemlingQuality")
local canUseBonded = nodesModsList:Flag(nil, "CanUseBonded")
-- Check the environment's own node list rather than the spec's allocation, so that
-- simulated allocations (e.g. node hover tooltips) see the radius change too
local timeLostJewelRadiusIncrease = nodesModsList:Sum("INC", nil, "NonUniqueTimeLostJewelRadius") > 0

if allocatedNotableCount and allocatedNotableCount > 0 then
modDB:NewMod("Multiplier:AllocatedNotable", "BASE", allocatedNotableCount)
Expand Down Expand Up @@ -1285,22 +1288,23 @@ function calcs.initEnv(build, mode, override, specEnv)
end
if item and not (node and node.sinister) and ( item.jewelRadiusIndex or (override and override.extraJewelFuncs and #override.extraJewelFuncs > 0) ) then
-- Jewel has a radius, add it to the list
local radiusIndex = data.getTimeLostJewelRadiusIndex(item, timeLostJewelRadiusIncrease)
local funcList = (item.jewelData and item.jewelData.funcList) or { { type = "Self", func = defaultRadiusJewelFunc } }
for _, func in ipairs(funcList) do
t_insert(env.radiusJewelList, {
nodes = node.nodesInRadius and node.nodesInRadius[item.jewelRadiusIndex] or { },
nodes = node.nodesInRadius and node.nodesInRadius[radiusIndex] or { },
func = func.func,
type = func.type,
item = item,
nodeId = slot.nodeId,
attributes = node.attributesInRadius and node.attributesInRadius[item.jewelRadiusIndex] or { },
attributes = node.attributesInRadius and node.attributesInRadius[radiusIndex] or { },
data = { },
-- store this to compare with cache later
jewelHash = getHashFromString(item.modSource..item.raw)
})
if func.type ~= "Self" and node.nodesInRadius then
-- Add nearby unallocated nodes to the extra node list
for nodeId, node in pairs(node.nodesInRadius[item.jewelRadiusIndex]) do
for nodeId, node in pairs(node.nodesInRadius[radiusIndex]) do
if not env.allocNodes[nodeId] then
env.extraRadiusNodeList[nodeId] = env.spec.nodes[nodeId]
end
Expand Down
23 changes: 23 additions & 0 deletions src/Modules/Data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -680,9 +680,32 @@ data.jewelRadii = {
{ inner = 1400, outer = 1700, col = "^xFFCC00", label = "Variable" },
{ inner = 1650, outer = 1950, col = "^xFF6600", label = "Variable" },
{ inner = 1800, outer = 2100, col = "^x0099FF", label = "Variable" },

-- 40% increased versions of the four base radii, used for non-Unique Time-Lost
-- jewels when "Non-Unique Time-Lost Jewels have 40% increased radius" is allocated
-- (Baryanic Leylines). `increased` keeps them out of the generic radius previews.
{ inner = 0, outer = 1400, col = "^xBB6600", label = "Increased Small", increased = true },
{ inner = 0, outer = 1610, col = "^x66FFCC", label = "Increased Medium", increased = true },
{ inner = 0, outer = 1820, col = "^x2222CC", label = "Increased Large", increased = true },
{ inner = 0, outer = 2100, col = "^xC100FF", label = "Increased Very Large", increased = true },
}
}

-- Maps a Time-Lost jewel's base radius index to its 40% increased counterpart above
data.timeLostJewelIncreasedRadiusIndex = { [1] = 13, [2] = 14, [3] = 15, [4] = 16 }

-- Returns the radius index a jewel uses given whether the Time-Lost radius increase
-- (Baryanic Leylines) applies; only non-unique Time-Lost jewels are remapped
data.getTimeLostJewelRadiusIndex = function(item, timeLostJewelRadiusIncrease)
local radiusIndex = item.jewelRadiusIndex
if radiusIndex and timeLostJewelRadiusIncrease
and item.rarity ~= "UNIQUE" and item.rarity ~= "RELIC"
and item.baseName and item.baseName:find("Time%-Lost") then
return data.timeLostJewelIncreasedRadiusIndex[radiusIndex] or radiusIndex
end
return radiusIndex
end

data.jewelRadius = data.setJewelRadiiGlobally(latestTreeVersion)

-- Stat descriptions
Expand Down
9 changes: 9 additions & 0 deletions src/Modules/ItemSlotHelper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ function M.DrawViewer(itemsTab, nodeId, x, y, w, h)

local viewer = itemsTab.socketViewer
viewer.zoom = 17
-- Zoom out if needed so the socketed jewel's radius ring (including the Time-Lost
-- radius increase from Baryanic Leylines) fits inside the preview: the ring's
-- diameter must fit min(w,h), with ~5% margin so the ring stroke isn't clipped
local _, jewel = itemsTab:GetSocketAndJewelForNodeID(nodeId)
if jewel and jewel.jewelRadiusIndex then
local radData = data.jewelRadius[itemsTab.build.spec:GetJewelRadiusIndex(jewel)]
local ringSize = radData.outer * data.gameConstants["PassiveTreeJewelDistanceMultiplier"]
viewer.zoom = math.min(viewer.zoom, itemsTab.build.spec.tree.size / (2 * ringSize) / 1.05)
end

local viewPortSize = math.min(w, h)
local scale = itemsTab.build.spec.tree.size / (viewPortSize * viewer.zoom)
Expand Down
1 change: 1 addition & 0 deletions src/Modules/ModParser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5605,6 +5605,7 @@ local specialModList = {
["upgrades radius to medium"] = { mod("JewelData", "LIST", { key = "timeLostJewelRadiusOverride", value = 2 })},
["upgrades radius to large"] = { mod("JewelData", "LIST", { key = "timeLostJewelRadiusOverride", value = 3 })},
["upgrades radius to very large"] = { mod("JewelData", "LIST", { key = "timeLostJewelRadiusOverride", value = 4 })},
["non%-unique time%-lost jewels have (%d+)%% increased radius"] = function(num) return { mod("NonUniqueTimeLostJewelRadius", "INC", num) } end,
["primordial"] = { mod("Multiplier:PrimordialItem", "BASE", 1) },
["spectres have a base duration of (%d+) seconds"] = { mod("SkillData", "LIST", { key = "duration", value = 6 }, { type = "SkillName", skillName = "Raise Spectre", includeTransfigured = true }) },
["flasks applied to you have (%d+)%% increased effect"] = function(num) return { mod("FlaskEffect", "INC", num, { type = "ActorCondition", actor = "player"}) } end,
Expand Down
Loading