Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ced2038
feat(weighted-score): add shared WeightedScore module and integrate i…
mcagnion Mar 21, 2026
22f6515
test(weighted-score): add WeightedScore test coverage
mcagnion Mar 21, 2026
84ad6dc
feat(weighted-score): add WeightedScore sort support to anoint panel
mcagnion Mar 22, 2026
77f822d
feat(weighted-score): add getValue to WeightedScore powerStatList entry
mcagnion Mar 22, 2026
2473468
fix(weighted-score): cache WeightedScore module load in Data.lua
mcagnion Mar 23, 2026
3c70cb3
fix(weighted-score): support getValue in generateFallbackWeights
mcagnion Mar 24, 2026
72f547f
fix(weighted-score): propagate getValue into fallbackWeightsList entries
mcagnion Mar 24, 2026
398a0ae
fix(trade): initialize stat weights before opening editor
mcagnion Mar 28, 2026
2e3cc19
feat(weighted-score): show weighted score in Power Report
mcagnion May 9, 2026
8fb2fa4
refactor(weighted-score): unify Edit Weights affordance via dropdown …
mcagnion May 10, 2026
dd84715
fix(weighted-score): preserve output stat semantics
mcagnion Jul 26, 2026
b663101
fix(weighted-score): limit sorting to supported surfaces
mcagnion Jul 26, 2026
3670348
fix(weighted-score): preserve Item DB ranking
mcagnion Jul 26, 2026
d9a980c
fix(weighted-score): preserve comparison context
mcagnion Jul 26, 2026
2f96932
test(weighted-score): cover combined stat weights
mcagnion Jul 26, 2026
a8da48d
refactor(weighted-score): share default weights
mcagnion Jul 26, 2026
fa293dc
fix(weighted-score): use Full DPS for anoint ranking
mcagnion Jul 26, 2026
79ea2fc
fix(weighted-score): persist weight edits
mcagnion Jul 26, 2026
cc16eb6
fix(weighted-score): place score last in menus
mcagnion Jul 28, 2026
d815cf8
fix(weighted-score): place weight editor after score
mcagnion Jul 28, 2026
e59169e
feat(weighted-score): sort item modifiers by score
mcagnion Jul 28, 2026
4042a77
fix(weighted-score): preserve refresh callback after reset
mcagnion Aug 6, 2026
8b10faf
Fix weighted score sorting for crafted affixes
mcagnion Aug 6, 2026
074c6f6
Add weighted score editing to remaining selectors
mcagnion Aug 7, 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
36 changes: 36 additions & 0 deletions spec/System/TestAbyssTimelessJewel_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,42 @@ describe("Abyss timeless jewels", function()
assert.matches("abyss_special_small_attribute25, 1, 0, 0", build.timelessData.searchListFallback, nil, true)
end)

it("exposes weight editing beside the Weighted Score fallback mode", function()
build.timelessData.jewelType = { id = 11 }
build.timelessData.conquerorType = { }
build.timelessData.jewelSocket = { id = 26196 }
build.itemsTab.tradeQuery.statSortSelectionList = {
{ stat = "FullDPS", label = "Full DPS", weightMult = 1 },
}
build.treeTab:FindTimelessJewel()
local control = main.popups[1].controls.fallbackWeightsList
local weightedIndex
local weightedCount = 0
for index, entry in ipairs(control.list) do
if entry.isWeightedScore then
weightedIndex = index
weightedCount = weightedCount + 1
end
end
assert.are.equal(1, weightedCount)
assert.is_truthy(weightedIndex)
assert.is_true(control.list[weightedIndex + 1].isAction)
assert.is_true(data.powerStatList.RequiresFullDPS(control.list[weightedIndex], build))

local opened = false
build.itemsTab.tradeQuery.SetStatWeights = function()
opened = true
end
control:SetSel(weightedIndex)
for char in ("Edit"):gmatch(".") do
control:OnSearchChar(char)
end
control:SetSel(1)

assert.is_true(opened)
assert.are.equal("WeightedScore", control:GetSelValue().stat)
end)

it("reads Zorath seed 6564 node and Inquisitor ascendancy changes", function()
data.timelessJewelLUTs[11] = parseAbyssJewel(11, zorathExampleData())
local expected = {
Expand Down
97 changes: 97 additions & 0 deletions spec/System/TestItemDBControl_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,103 @@ describe("ItemDBControl", function()
assert.are.equal(-math.huge, invalidItem.measuredPower)
end)

it("preserves negative WeightedScore results and skips unneeded FullDPS", function()
local function makeItem(name)
return {
name = name,
base = {},
enchantModLines = {},
implicitModLines = {},
explicitModLines = {},
baseModList = {},
}
end
local betterItem = makeItem("Better Item")
local worseItem = makeItem("Worse Item")
local invalidItem = makeItem("Invalid Item")
local takenDamage = {
[betterItem] = 80,
[worseItem] = 120,
}
local requestedFullDPS = { }
local itemsTab = {
activeItemSet = { useSecondWeaponSet = false },
slots = { ["Body Armour"] = {} },
tradeQuery = {
statSortSelectionList = {
{ stat = "PhysicalTakenHit", weightMult = 1, transform = function(value) return -value end },
},
},
IsItemValidForSlot = function(_, item)
return item ~= invalidItem
end,
}
itemsTab.build = {
itemsTab = itemsTab,
calcsTab = {
GetMiscCalculator = function()
return function(args, useFullDPS)
table.insert(requestedFullDPS, useFullDPS)
return { PhysicalTakenHit = takenDamage[args.repItem] }
end, { PhysicalTakenHit = 100 }
end,
},
}
local control = new("ItemDBControl", nil, { 0, 0, 100, 100 }, itemsTab, {
list = { invalidItem, betterItem, worseItem },
}, "RARE")
control.sortDetail = { stat = "WeightedScore", isWeightedScore = true }
control.sortOrder = { control.sortControl.STAT, control.sortControl.NAME }

control:ListBuilder()

assert.are.equal(betterItem, control.list[1])
assert.are.equal(worseItem, control.list[2])
assert.are.equal(invalidItem, control.list[3])
assert.are.equal(-0.8, betterItem.measuredPower)
assert.are.equal(-1.2, worseItem.measuredPower)
assert.are.equal(-math.huge, invalidItem.measuredPower)
assert.are.same({ false, false }, requestedFullDPS)
end)

it("requests FullDPS for WeightedScore when active weights need it", function()
local item = {
name = "Full DPS Item",
base = {},
enchantModLines = {},
implicitModLines = {},
explicitModLines = {},
baseModList = {},
}
local requestedFullDPS = { }
local itemsTab = {
activeItemSet = { useSecondWeaponSet = false },
slots = { ["Body Armour"] = {} },
tradeQuery = { statSortSelectionList = { { stat = "FullDPS", weightMult = 1 } } },
IsItemValidForSlot = function()
return true
end,
}
itemsTab.build = {
itemsTab = itemsTab,
calcsTab = {
GetMiscCalculator = function()
return function(_, useFullDPS)
table.insert(requestedFullDPS, useFullDPS)
return { FullDPS = 120 }
end, { FullDPS = 100 }
end,
},
}
local control = new("ItemDBControl", nil, { 0, 0, 100, 100 }, itemsTab, { list = { item } }, "RARE")
control.sortDetail = { stat = "WeightedScore", isWeightedScore = true }
control.sortOrder = { control.sortControl.STAT, control.sortControl.NAME }

control:ListBuilder()

assert.are.same({ true }, requestedFullDPS)
end)

it("searches Foulborn modifier text without case sensitivity", function()
local item = new("Item", [[
Rarity: Unique
Expand Down
37 changes: 37 additions & 0 deletions spec/System/TestNotableDBControl_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
describe("NotableDBControl", function()
it("requests FullDPS when sorting by WeightedScore with FullDPS weights", function()
local notable = {
dn = "Full DPS Notable",
sd = {},
recipe = { "Amber Oil" },
modKey = "NotableFullDPS",
}
local requestedFullDPS = {}
local itemsTab = {
displayItem = { base = { type = "Amulet" } },
tradeQuery = { statSortSelectionList = { { stat = "FullDPS", weightMult = 1 } } },
anointItem = function(_, node)
return node
end,
}
itemsTab.build = {
itemsTab = itemsTab,
calcsTab = {
GetMiscCalculator = function()
return function(args, useFullDPS)
table.insert(requestedFullDPS, useFullDPS)
return { FullDPS = args.repItem and 120 or 100 }
end
end,
},
}
local control = new("NotableDBControl", nil, { 0, 0, 100, 100 }, itemsTab, { [1] = notable }, "ANNOINT")
control.sortDetail = { stat = "WeightedScore", isWeightedScore = true }
control.sortOrder = { control.sortControl.STAT, control.sortControl.NAME }

control:ListBuilder()

assert.are.same({ true, true }, requestedFullDPS)
assert.are.equal(notable, control.list[1])
end)
end)
38 changes: 38 additions & 0 deletions spec/System/TestPowerReport_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
describe("PowerReportListControl", function()
local PowerReportListControl

before_each(function()
LoadModule("Classes/PowerReportListControl")
PowerReportListControl = common.classes.PowerReportListControl
end)

local function relist(originalList, showClusters, allocated)
local control = {
originalList = originalList,
showClusters = showClusters or false,
allocated = allocated or false,
}
PowerReportListControl.ReList(control)
return control.list
end

it("Show Unallocated excludes allocated nodes", function()
local list = relist({
{ name = "allocated", power = 10, pathDist = 1, allocated = true },
{ name = "unallocated", power = 5, pathDist = 1, allocated = false },
}, false, false)

assert.are.equal(1, #list)
assert.are.equal("unallocated", list[1].name)
end)

it("Show Allocated includes allocated nodes", function()
local list = relist({
{ name = "allocated", power = 10, pathDist = 1, allocated = true },
{ name = "unallocated", power = 5, pathDist = 1, allocated = false },
}, false, true)

assert.are.equal(1, #list)
assert.are.equal("allocated", list[1].name)
end)
end)
56 changes: 56 additions & 0 deletions spec/System/TestTradeQuery_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,60 @@ describe("TradeQuery", function()
assert.are.equals(1.2, result)
end)
end)

describe("SetStatWeights", function()
it("marks the build modified after saving changed weights", function()
local capturedControls
local originalOpenPopup = main.OpenPopup
local originalClosePopup = main.ClosePopup
main.OpenPopup = function(_, _, _, _, controls)
capturedControls = controls
end
main.ClosePopup = function() end

local itemsTab = {}
local tradeQuery = new("TradeQuery", itemsTab)
local ok, errMsg = pcall(function()
tradeQuery:SetStatWeights()
for _, entry in ipairs(capturedControls.ListControl.list) do
if entry.stat.stat == "FullDPS" then
entry.stat.weightMult = 0.75
break
end
end
capturedControls.finalise.onClick()
end)
main.OpenPopup = originalOpenPopup
main.ClosePopup = originalClosePopup

assert.is_true(ok, errMsg)
assert.is_true(itemsTab.modFlag)
assert.are.equal(0.75, tradeQuery.statSortSelectionList[1].weightMult)
end)

it("preserves the save callback after resetting weights", function()
local capturedControls
local originalOpenPopup = main.OpenPopup
local originalClosePopup = main.ClosePopup
main.OpenPopup = function(_, _, _, _, controls)
capturedControls = controls
end
main.ClosePopup = function() end

local callbackCount = 0
local ok, errMsg = pcall(function()
local tradeQuery = new("TradeQuery", {})
tradeQuery:SetStatWeights(nil, function()
callbackCount = callbackCount + 1
end)
capturedControls.reset.onClick()
capturedControls.finalise.onClick()
end)
main.OpenPopup = originalOpenPopup
main.ClosePopup = originalClosePopup

assert.is_true(ok, errMsg)
assert.are.equal(1, callbackCount)
end)
end)
end)
Loading
Loading