Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
351ce94
Add radius jewel finder
mcagnion May 23, 2026
17338fd
Add radius jewel finder tests
mcagnion May 23, 2026
36a5b51
Clarify radius jewel variant selection
mcagnion May 23, 2026
cecc326
Derive radius jewel data from item text
mcagnion May 23, 2026
dd12410
Derive radius jewel family filter options
mcagnion May 24, 2026
6e943e5
Clarify radius jewel variant filtering
mcagnion May 24, 2026
cebe01a
Support Foulborn variants in Radius Jewel Finder
mcagnion Jul 28, 2026
7717dd8
Rebuild radius jewel specs for historic replacements
mcagnion Aug 3, 2026
ac228d6
Reuse ordinary Impossible Escape cache
mcagnion Aug 3, 2026
15f8308
Show replaced jewels in Apply tooltip
mcagnion Aug 3, 2026
d1e309f
Show replaced jewel tooltips
mcagnion Aug 3, 2026
5e1b86e
Rebuild cluster trees for jewel comparisons
mcagnion Aug 3, 2026
e1245ec
Label replaced jewels by base type
mcagnion Aug 3, 2026
92acbc4
Allow ordinary jewels in safe sockets
mcagnion Aug 3, 2026
d212aee
Label special radius jewel sockets
mcagnion Aug 3, 2026
5ddbfd4
Handle Abyss Timeless replacements
mcagnion Aug 3, 2026
74eb8ed
Refresh radius jewel manifest
mcagnion Aug 5, 2026
a6a0054
Adapt radius jewel constructors to current class syntax
mcagnion Aug 15, 2026
cf8023a
Share passive tree comparison classification
mcagnion Aug 16, 2026
511d7eb
Extract radius jewel result controls
mcagnion Aug 16, 2026
de3b3cc
Unify radius jewel result sort keys
mcagnion Aug 16, 2026
45600f7
Clarify radius jewel module ownership
mcagnion Aug 16, 2026
d68cafe
Share radius jewel presentation helpers
mcagnion Aug 16, 2026
82582cd
Decompose Impossible Escape evaluation
mcagnion Aug 16, 2026
e5d8d4e
Extract radius jewel popup workflows
mcagnion Aug 16, 2026
f95f949
Split radius jewel system specs
mcagnion Aug 16, 2026
4e8792e
Spell out radius jewel point labels
mcagnion Aug 16, 2026
4c0ee6f
Reduce radius jewel result cache memory
mcagnion Aug 16, 2026
28c25cb
Remove unused radius jewel module surface
mcagnion Aug 16, 2026
6b5fcb6
Model canonical radius jewel variants
mcagnion Aug 16, 2026
9a01e27
Bind radius jewel results to build context
mcagnion Aug 17, 2026
ae0fb71
Plan radius jewel result actions
mcagnion Aug 17, 2026
4acae95
Keep Thread plans attached to their sockets
mcagnion Aug 17, 2026
13ed99d
Isolate Impossible Escape result groups
mcagnion Aug 17, 2026
5030ce7
Restore Split Personality state on every exit
mcagnion Aug 17, 2026
8a734e6
Evaluate every Fast radius jewel plan
mcagnion Aug 17, 2026
2346ae7
Move radius jewel calculations into their own object
mcagnion Aug 17, 2026
999be22
Replace positional radius jewel compute arguments
mcagnion Aug 17, 2026
1977f1d
Define radius jewel Find and Compute strategies
mcagnion Aug 17, 2026
f5eba3e
Extract radius jewel result state
mcagnion Aug 17, 2026
2fd95e9
Extract radius jewel result actions
mcagnion Aug 17, 2026
1aa7bd1
Extract radius jewel result presentation
mcagnion Aug 18, 2026
829b352
Keep stale radius jewel results visible
mcagnion Aug 18, 2026
cb597b6
Clarify Find availability for jewel variants
mcagnion Aug 18, 2026
7ab3535
Enforce Max points in radius jewel Find
mcagnion Aug 19, 2026
2e8d4e7
Simplify radius jewel result details
mcagnion Aug 20, 2026
7d2d4d9
Simplify radius jewel result data and state
mcagnion Aug 21, 2026
f4d8311
Extract radius jewel item actions
mcagnion Aug 22, 2026
15a4004
Clarify radius jewel result contracts
mcagnion Aug 22, 2026
b39896a
Consolidate radius jewel strategy capabilities
mcagnion Aug 22, 2026
473ca4f
Update radius jewel manifest hashes
mcagnion Aug 26, 2026
4d389b4
Simplify Impossible Escape result fan-out
mcagnion Aug 26, 2026
aaef569
Test radius jewel results with distinct candidates
mcagnion Sep 26, 2026
21d977d
Use smaller fixtures in radius jewel tests
mcagnion Sep 26, 2026
81b5a2c
Clean up shared state in radius jewel tests
mcagnion Sep 26, 2026
6b9cc1e
Test radius jewel UI by behavior
mcagnion Sep 27, 2026
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
15 changes: 11 additions & 4 deletions manifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@
<File name="Classes/ItemListControl.lua" part="program" sha1="fcfdc29c1e1a69c5d8840286ff325886c91fc2ef" />
<File name="Classes/ItemSetListControl.lua" part="program" sha1="443038191a6ba3a17c3ce6683b96ab2797cf5d39" />
<File name="Classes/ItemSlotControl.lua" part="program" sha1="f353849939ff90f259110baaf59bced890b0994e" />
<File name="Classes/ItemsTab.lua" part="program" sha1="75b76c44dfd9f9c472a2f9d26a48b2998f84fba6" />
<File name="Classes/ItemsTab.lua" part="program" sha1="5330b7ae2f5f84d7be502ee7a8b0574c337eb57f" />
<File name="Classes/LabelControl.lua" part="program" sha1="b6c56903b054e14c302a5e4e60ed8e91764bc6a0" />
<File name="Classes/ListControl.lua" part="program" sha1="b51a294cd00391400bc5d0ad101319bb126dc6a0" />
<File name="Classes/MinionListControl.lua" part="program" sha1="b9324d7c16d20ac4d7508ecd151c2e9838fdb98c" />
Expand All @@ -162,7 +162,7 @@
<File name="Classes/NotesTab.lua" part="program" sha1="de067274e65a7d71940caead279c3a1f8d6fce3e" />
<File name="Classes/PartyTab.lua" part="program" sha1="a2763e12e81f8708d9e179e887bde63016e79d24" />
<File name="Classes/PassiveMasteryControl.lua" part="program" sha1="d26082d3fa6485b0813c3a988d180208fdd652ef" />
<File name="Classes/PassiveSpec.lua" part="program" sha1="b9ea628f8f365795aa0375c1f3fe67ba671ffad9" />
<File name="Classes/PassiveSpec.lua" part="program" sha1="e4178911779ed63533f783da6d436f8924032e8e" />
<File name="Classes/PassiveSpecListControl.lua" part="program" sha1="694d7b088e895348857b97a78babb00d612469f8" />
<File name="Classes/PassiveTree.lua" part="program" sha1="3c1e123c7563640ddfe83e197dbee7a12ad33725" />
<File name="Classes/PassiveTreeView.lua" part="program" sha1="28e5dcdd5e470db6f04fd454957c36c791d87524" />
Expand All @@ -171,6 +171,13 @@
<File name="Classes/PoEAPI.lua" part="program" sha1="8d2d4ac10133002f869fc0a2e157605ceba32ea4" />
<File name="Classes/PopupDialog.lua" part="program" sha1="f37b60b6589d4ff0c721c2418d78409f2dc69452" />
<File name="Classes/PowerReportListControl.lua" part="program" sha1="c9d51d41962a7d8d3a7508765758e10d3ebcb3c7" />
<File name="Classes/RadiusJewelCompute.lua" part="program" sha1="2fc47abb521460c1adf3e2c27696f012ded6c68b" />
<File name="Classes/RadiusJewelData.lua" part="program" sha1="6d4607a936d51849913e99253c7d294a811a8121" />
<File name="Classes/RadiusJewelDetailListControl.lua" part="program" sha1="fc651bf47cc714d5460e2e2e36f341715bbb4039" />
<File name="Classes/RadiusJewelFinder.lua" part="program" sha1="c9d28c8a1c7e145952786aeb96ce52236cda7616" />
<File name="Classes/RadiusJewelItemActions.lua" part="program" sha1="5fba2b7595c46e9217e1c20c47d8c818df9d07cb" />
<File name="Classes/RadiusJewelResultsListControl.lua" part="program" sha1="78bbfb0bf09739a76a88a119653a33fa27ab91de" />
<File name="Classes/RadiusJewelTooltipPlacement.lua" part="program" sha1="768fe21dcb1dff1809f4d6180d94b49374899082" />
<File name="Classes/RectangleOutlineControl.lua" part="program" sha1="4da285dbe76549deae46d3835e00c382c59c18b4" />
<File name="Classes/ResizableEditControl.lua" part="program" sha1="1270c263bd762759cc1121c3eeb4906018136e05" />
<File name="Classes/ScrollBarControl.lua" part="program" sha1="58f68ca961c625d3aba4c8946f7894371c74d335" />
Expand All @@ -193,7 +200,7 @@
<File name="Classes/TradeQueryRateLimiter.lua" part="program" sha1="d7c4f5655b36e911ccf4597e8ab6a3c1e3a27ec5" />
<File name="Classes/TradeQueryRequests.lua" part="program" sha1="0f8342ef30c9240ce96028defbad5838b8a22306" />
<File name="Classes/TradeStatWeightMultiplierListControl.lua" part="program" sha1="df442a192fcaf26558e7485b9c31d2b4e79dc6fc" />
<File name="Classes/TreeTab.lua" part="program" sha1="a3af8fff50d314f3119362c79670a0e7d3e6dce1" />
<File name="Classes/TreeTab.lua" part="program" sha1="616e02c2c89e6c509231b780d0966c3b9ff0a2ae" />
<File name="Classes/UndoHandler.lua" part="program" sha1="ce4835c384c834da0de47b0302b1e774c8300c6b" />
<File name="Data/Bases/amulet.lua" part="program" sha1="0c35de0a6731169f674fee440af79e5215ba627e" />
<File name="Data/Bases/axe.lua" part="program" sha1="0b7a87867c677b95ccf1bdd0937f0874857f35af" />
Expand Down Expand Up @@ -1394,4 +1401,4 @@
<File name="TreeData/VaalJewelCircle2.png" part="tree" sha1="facc5d2fea2f0027d09fdb6e4692f9f298aff293" />
<File name="TreeData/VerdantOil.png" part="tree" sha1="97e77b6e96accf440c17a81d622bf629b8c78fe7" />
<File name="TreeData/VioletOil.png" part="tree" sha1="1e9e4f0683a5156c27cb7ddafada8bed877e1c25" />
</PoBVersion>
</PoBVersion>
157 changes: 157 additions & 0 deletions spec/System/RadiusJewelFinderTestSupport.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
-- Shared fixture helpers and state checks for Radius Jewel system specs.

local support = { }

support.occVortex = LoadModule("../spec/TestBuilds/3.13/OccVortex.lua")
support.mirageArcherToxicRain = LoadModule("../spec/TestBuilds/3.13/Mirage Archer Toxic Rain.lua")
support.RadiusJewelData = LoadModule("Classes/RadiusJewelData")

support.MIGHT_OF_MEEK_RAW_TEXT = [[Might of the Meek
Crimson Jewel
Radius: Large
50% increased Effect of non-Keystone Passive Skills in Radius
Notable Passive Skills in Radius grant nothing]]

support.UNNATURAL_INSTINCT_RAW_TEXT = [[Unnatural Instinct
Viridian Jewel
Limited to: 1
Radius: Small
Allocated Small Passive Skills in Radius grant nothing
Grants all bonuses of Unallocated Small Passive Skills in Radius]]

support.ANATOMICAL_KNOWLEDGE_RAW_TEXT = [[Anatomical Knowledge
Cobalt Jewel
Source: No longer obtainable
Radius: Large
8% increased maximum Life
Adds 1 to Maximum Life per 3 Intelligence Allocated in Radius]]

function support.buildSplitPersonalityRawText(modLine)
return table.concat({
"Split Personality",
"Crimson Jewel",
"Variable",
"This Jewel's Socket has 25% increased effect per Allocated Passive Skill between it and your Class' starting location",
modLine,
"Corrupted",
}, "\n")
end

function support.buildImpossibleEscapeRawText(keystoneName)
return table.concat({
"Impossible Escape",
"Viridian Jewel",
"Limited to: 1",
"Small",
"Passive Skills in radius of " .. keystoneName .. " can be allocated without being connected to your tree",
"Corrupted",
}, "\n")
end

function support.makeFinder()
return new("RadiusJewelFinder"):RadiusJewelFinder({ build = build })
end

local function getRadiusIndex(label)
local radiusIndexByLabel = { }
for i, radius in ipairs(data.jewelRadius) do
if radius.inner == 0 and not radiusIndexByLabel[radius.label] then
radiusIndexByLabel[radius.label] = i
end
end
return radiusIndexByLabel[label]
end

function support.getLargeRadiusIndex()
return getRadiusIndex("Large")
end

function support.getSmallRadiusIndex()
return getRadiusIndex("Small")
end

function support.getRadiusIndexFromRawText(rawText)
local item = new("Item"):Item("Rarity: Unique\n" .. rawText)
return item.jewelRadiusIndex
end

function support.makeImpossibleEscapeTestVariant()
local smallRadiusIndex = support.getSmallRadiusIndex()
local allocNodes = build.spec.allocNodes
for keystoneName, node in pairs(build.spec.tree.keystoneMap or { }) do
if node and node.nodesInRadius and node.nodesInRadius[smallRadiusIndex] then
local hasCandidate = false
for nodeId, radiusNode in pairs(node.nodesInRadius[smallRadiusIndex]) do
if not allocNodes[nodeId] and not radiusNode.ascendancyName
and radiusNode.type ~= "Socket" and radiusNode.type ~= "ClassStart"
and radiusNode.type ~= "AscendClassStart" and radiusNode.type ~= "Mastery" then
hasCandidate = true
break
end
end
if hasCandidate then
return {
name = keystoneName,
keystoneName = keystoneName,
rawText = support.buildImpossibleEscapeRawText(keystoneName),
}
end
end
end
end

function support.makeThreadVariants()
return support.RadiusJewelData.getThreadOfHopeVariants()
end

function support.isSorted(results, key)
for i = 2, #results do
if results[i - 1][key] < results[i][key] then
return false
end
end
return true
end

function support.snapshotFinderState()
local socketSelItemIds = { }
for socketId, slot in pairs(build.itemsTab.sockets) do
socketSelItemIds[socketId] = slot.selItemId
end

local itemOrderList = { }
for i, itemId in ipairs(build.itemsTab.itemOrderList) do
itemOrderList[i] = itemId
end

local itemCount = 0
local itemStateById = { }
for itemId, item in pairs(build.itemsTab.items) do
itemCount = itemCount + 1
itemStateById[itemId] = item.BuildRaw and item:BuildRaw() or {
title = item.title,
name = item.name,
baseName = item.baseName,
limit = item.limit,
}
end

return {
socketSelItemIds = socketSelItemIds,
itemOrderList = itemOrderList,
itemCount = itemCount,
itemStateById = itemStateById,
jewels = copyTable(build.spec.jewels, true),
}
end

function support.assertFinderStateUnchanged(before, check)
local after = support.snapshotFinderState()
check.are.same(before.socketSelItemIds, after.socketSelItemIds)
check.are.same(before.itemOrderList, after.itemOrderList)
check.are.equal(before.itemCount, after.itemCount)
check.are.same(before.itemStateById, after.itemStateById)
check.are.same(before.jewels, after.jewels)
end

return support
Loading
Loading