Skip to content

Commit ff10f69

Browse files
author
LocalIdentity
committed
Merge branch 'dev' into timeless-memes
2 parents aa99cbb + 636e7cb commit ff10f69

36 files changed

Lines changed: 741 additions & 295 deletions

.github/workflows/test.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ jobs:
1313
- name: Checkout
1414
uses: actions/checkout@v4
1515
- name: Run tests
16-
run: busted --lua=luajit
17-
- name: Report coverage
18-
continue-on-error: true # May fail on server errors (of coveralls.io)
19-
run: cd src; luacov-coveralls --repo-token=${{ secrets.github_token }} -e TestData -e Data -e runtime
16+
run: busted --lua=luajit --no-coverage
2017
check_modcache:
2118
runs-on: ubuntu-latest
2219
container: ghcr.io/pathofbuildingcommunity/pathofbuilding-tests:latest

src/Classes/CalcsTab.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ function CalcsTabClass:PowerBuilder()
614614
end
615615

616616
function CalcsTabClass:CalculatePowerStat(selection, original, modified)
617-
if modified.Minion and not selection.stat == "FullDPS" then
617+
if modified.Minion and selection.stat ~= "FullDPS" then
618618
original = original.Minion
619619
modified = modified.Minion
620620
end

src/Classes/ConfigTab.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,18 @@ local ConfigTabClass = newClass("ConfigTab", "UndoHandler", "ControlHost", "Cont
330330
return out
331331
end))
332332
end
333+
if varData.ifCondTrue then
334+
t_insert(shownFuncs, listOrSingleIfOption(varData.ifCondTrue, function(ifOption)
335+
return self.build.calcsTab.mainEnv.player.modDB.conditions[ifOption]
336+
end))
337+
t_insert(tooltipFuncs, listOrSingleIfTooltip(varData.ifCondTrue, function(ifOption)
338+
if not launch.devModeAlt then
339+
return
340+
end
341+
local out = "Condition state: " .. ifOption .. "=" .. tostring(self.build.calcsTab.mainEnv.player.modDB.conditions[ifOption])
342+
return out
343+
end))
344+
end
333345
if varData.ifMult then
334346
t_insert(shownFuncs, listOrSingleIfOption(varData.ifMult, function(ifOption)
335347
if implyCond(varData) then

src/Classes/FolderListControl.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ local t_insert = table.insert
99
local FolderListClass = newClass("FolderListControl", "ListControl", function(self, anchor, rect, subPath, onChange)
1010
self.ListControl(anchor, rect, 16, "VERTICAL", false, { })
1111
self.subPath = subPath or ""
12+
self.sortMode = "NAME"
1213
self.onChangeCallback = onChange
1314

1415
self.controls.path = new("PathControl", {"BOTTOM",self,"TOP"}, {0, -2, self.width, 24}, main.buildPath, self.subPath, function(newSubPath)
@@ -25,7 +26,7 @@ end)
2526

2627
function FolderListClass:SortList()
2728
if not self.list then return end
28-
local sortMode = main.buildSortMode or "NAME"
29+
local sortMode = self.sortMode
2930

3031
table.sort(self.list, function(a, b)
3132
if sortMode == "EDITED" then
@@ -91,4 +92,4 @@ function FolderListClass:OnSelDelete(index, folder)
9192
self.selIndex = nil
9293
self.selValue = nil
9394
end
94-
end
95+
end

src/Classes/GemSelectControl.lua

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ local m_max = math.max
1212
local m_floor = math.floor
1313

1414
local toolTipText = "Prefix tag searches with a colon and exclude tags with a dash. e.g. :fire:lightning:-cold:area"
15-
local nonLegacyAwakened = {
16-
["SupportAwakenedEmpower"] = true,
17-
["SupportAwakenedEnlighten"] = true,
18-
["SupportAwakenedEnhance"] = true,
19-
}
2015
local altQualMap = {
2116
["Default"] = "",
2217
["Alternate1"] = "Anomalous ",
@@ -121,7 +116,7 @@ function GemSelectClass:PopulateGemList()
121116
local levelRequirement = gemData.grantedEffect.levels[1].levelRequirement or 1
122117
if characterLevel >= levelRequirement or not matchLevel then
123118
if (showExceptional or showAll) and gemData.grantedEffect.plusVersionOf then
124-
if self.skillsTab.showLegacyGems or nonLegacyAwakened[gemData.grantedEffectId] or not gemData.name:match("^Awakened") then
119+
if self.skillsTab.showLegacyGems or not gemData.grantedEffect.legacy then
125120
self.gems["Default:" .. gemId] = gemData
126121
end
127122
elseif showNormal or showAll then
@@ -144,7 +139,7 @@ end
144139

145140
function GemSelectClass:FilterSupport(gemId, gemData)
146141
local showSupportTypes = self.skillsTab.showSupportGemTypes
147-
if gemData.name:match("^Awakened") and not self.skillsTab.showLegacyGems and not nonLegacyAwakened[gemData.grantedEffectId] then
142+
if gemData.grantedEffect.legacy and not self.skillsTab.showLegacyGems then
148143
return false
149144
end
150145
return (not gemData.grantedEffect.support
@@ -615,6 +610,11 @@ function GemSelectClass:AddGemTooltip(gemInstance)
615610
local grantedEffect = gemInstance.gemData.grantedEffect
616611
self.tooltip:AddLine(fontSizeTitle, colorCodes.GEM .. altQualMap[gemInstance.qualityId]..grantedEffect.name, "FONTIN SC")
617612
self.tooltip:AddSeparator(10)
613+
if grantedEffect.legacy then
614+
self.tooltip:AddLine(fontSizeTitle, colorCodes.WARNING .. "Legacy Gem", "FONTIN SC")
615+
self.tooltip:AddLine(fontSizeBig, colorCodes.WARNING .. "Gem only exists in Standard League", "FONTIN SC")
616+
self.tooltip:AddSeparator(10)
617+
end
618618
self.tooltip:AddLine(fontSizeBig, "^x7F7F7F" .. gemInstance.gemData.tagString, "FONTIN SC")
619619
self:AddCommonGemInfo(gemInstance, grantedEffect, true, secondary and secondary.support and secondary)
620620
end

src/Classes/Item.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
15681568
if self.base.flask.life or self.base.flask.mana then
15691569
-- Recovery flask
15701570
flaskData.instantPerc = calcLocal(modList, "FlaskInstantRecovery", "BASE", 0)
1571+
flaskData.instantLowLifePerc = calcLocal(modList, "FlaskLowLifeInstantRecovery", "BASE", 0)
15711572
local recoveryMod = 1 + calcLocal(modList, "FlaskRecovery", "INC", 0) / 100
15721573
local rateMod = 1 + calcLocal(modList, "FlaskRecoveryRate", "INC", 0) / 100
15731574
flaskData.duration = round(self.base.flask.duration * (1 + durationInc / 100) / rateMod * durationMore, 1)

src/Classes/ModStore.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ function ModStoreClass:GetStat(stat, cfg)
300300
if stat == "ManaUnreserved" and self.actor.output[stat] ~= self.actor.output[stat] then
301301
-- 0% reserved = total mana
302302
return self.actor.output["Mana"]
303-
elseif stat == "ManaUnreserved" and not self.actor.output[stat] == nil and self.actor.output[stat] < 0 then
303+
elseif stat == "ManaUnreserved" and self.actor.output[stat] ~= nil and self.actor.output[stat] < 0 then
304304
-- This reverse engineers how much mana is unreserved before efficiency for accurate Arcane Cloak calcs
305305
local reservedPercentBeforeEfficiency = (math.abs(self.actor.output["ManaUnreservedPercent"]) + 100) * ((100 + self.actor["ManaEfficiency"]) / 100)
306306
return self.actor.output["Mana"] * (math.ceil(reservedPercentBeforeEfficiency) / 100);

src/Classes/SkillsTab.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ Awakened gems default to their highest valid non-corrupted gem level.]],
5050
This hides gems with a minimum level requirement above your character level, preventing them from showing up in the dropdown list.]],
5151
gemLevel = "characterLevel",
5252
},
53+
{
54+
label = "Level 1",
55+
description = "All gems default to level 1.",
56+
gemLevel = "levelOne",
57+
},
5358
}
5459

5560
local showSupportGemTypeList = {
@@ -1053,6 +1058,8 @@ function SkillsTabClass:ProcessGemLevel(gemData)
10531058
end
10541059
elseif self.defaultGemLevel == "normalMaximum" then
10551060
return naturalMaxLevel
1061+
elseif self.defaultGemLevel == "levelOne" then
1062+
return 1
10561063
else -- self.defaultGemLevel == "characterLevel"
10571064
local maxGemLevel = naturalMaxLevel
10581065
if not grantedEffect.levels[maxGemLevel] then

src/Classes/TradeQueryGenerator.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,9 @@ function TradeQueryGeneratorClass:FinishQuery()
916916

917917
-- Sort by mean Stat diff rather than weight to more accurately prioritize stats that can contribute more
918918
table.sort(self.modWeights, function(a, b)
919+
if a.meanStatDiff == b.meanStatDiff then
920+
return math.abs(a.weight) > math.abs(b.weight)
921+
end
919922
return a.meanStatDiff > b.meanStatDiff
920923
end)
921924

@@ -968,9 +971,6 @@ function TradeQueryGeneratorClass:FinishQuery()
968971

969972
local effective_max = MAX_FILTERS - num_extra
970973

971-
-- Prioritize top mods by abs(weight)
972-
table.sort(self.modWeights, function(a, b) return math.abs(a.weight) > math.abs(b.weight) end)
973-
974974
local prioritizedMods = {}
975975
for _, entry in ipairs(self.modWeights) do
976976
if #prioritizedMods < effective_max then

src/Classes/TreeTab.lua

Lines changed: 44 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,31 +2349,32 @@ function TreeTabClass:FindTimelessJewel()
23492349
end
23502350
curNodeId = "totalStat"
23512351
end
2352-
if jewelDataTbl[1] >= data.timelessJewelAdditions and not isValueInTable(protectedNodes, treeData.nodes[targetNode].dn) then -- replace
2353-
curNode = legionNodes[jewelDataTbl[1] + 1 - data.timelessJewelAdditions]
2354-
curNodeId = curNode and legionNodes[jewelDataTbl[1] + 1 - data.timelessJewelAdditions].id or nil
2355-
else -- add
2356-
curNode = legionAdditions[jewelDataTbl[1] + 1]
2357-
curNodeId = curNode and legionAdditions[jewelDataTbl[1] + 1].id or nil
2358-
end
2359-
if desiredNodes["totalStat"] and reverseTotalModIDs[curNodeId] then
2360-
curNodeId = "totalStat"
2361-
end
2362-
if timelessData.jewelType.id == 1 then
2363-
local headerSize = #jewelDataTbl
2364-
if headerSize == 2 or headerSize == 3 then
2365-
if desiredNodes[curNodeId] then
2366-
resultNodes[curSeed][curNodeId] = resultNodes[curSeed][curNodeId] or { targetNodeNames = { }, totalWeight = 0 }
2367-
local statMod1 = curNode.stats[curNode.sortedStats[1]]
2368-
local weight = desiredNodes[curNodeId].nodeWeight * jewelDataTbl[statMod1.index + 1]
2369-
local statMod2 = curNode.stats[curNode.sortedStats[2]]
2370-
if statMod2 then
2371-
weight = weight + desiredNodes[curNodeId].nodeWeight2 * jewelDataTbl[statMod2.index + 1]
2372-
end
2373-
t_insert(resultNodes[curSeed][curNodeId], targetNode)
2374-
t_insert(resultNodes[curSeed][curNodeId].targetNodeNames, treeData.nodes[targetNode].name)
2375-
resultNodes[curSeed][curNodeId].totalWeight = resultNodes[curSeed][curNodeId].totalWeight + weight
2376-
seedWeights[curSeed] = seedWeights[curSeed] + weight
2352+
end
2353+
end
2354+
local seedWeights = { }
2355+
local seedMultiplier = timelessData.jewelType.id == 5 and 20 or 1 -- Elegant Hubris
2356+
for curSeed = data.timelessJewelSeedMin[timelessData.jewelType.id] * seedMultiplier, data.timelessJewelSeedMax[timelessData.jewelType.id] * seedMultiplier, seedMultiplier do
2357+
seedWeights[curSeed] = 0
2358+
resultNodes[curSeed] = { }
2359+
for targetNode in pairs(targetNodes) do
2360+
local jewelDataTbl = data.readLUT(curSeed, targetNode, timelessData.jewelType.id)
2361+
if not next(jewelDataTbl) then
2362+
ConPrintf("Missing LUT: " .. timelessData.jewelType.label)
2363+
else
2364+
local curNode = nil
2365+
local curNodeId = nil
2366+
if (timelessData.jewelType.id == 4 and isValueInTable(protectedNodes, treeData.nodes[targetNode].dn)) then -- protected
2367+
if jewelDataTbl[1] >= data.timelessJewelAdditions then -- protected node is a replacement, invalidate seed
2368+
resultNodes[curSeed] = nil
2369+
break
2370+
end
2371+
if not desiredNodes["totalStat"] then -- only add if user has not entered their own Devotion to the table
2372+
desiredNodes["totalStat"] = {
2373+
nodeWeight = 0.1, -- keeps total score low to let desired stats decide sort
2374+
nodeWeight2 = 0,
2375+
displayName = "Devotion",
2376+
desiredIdx = desiredIdx + 1
2377+
}
23772378
end
23782379
elseif headerSize == 6 or headerSize == 8 then
23792380
for i, jewelData in ipairs(jewelDataTbl) do
@@ -2401,74 +2402,18 @@ function TreeTabClass:FindTimelessJewel()
24012402
seedWeights[curSeed] = seedWeights[curSeed] + desiredNodes[curNodeId].nodeWeight
24022403
end
24032404
end
2404-
end
2405-
if desiredNodes["totalStat"] then
2406-
resultNodes[curSeed]["totalStat"] = resultNodes[curSeed]["totalStat"] or { targetNodeNames = { }, totalWeight = 0 }
2407-
if timelessData.jewelType.id == 4 then -- Militant Faith
2408-
local addedWeight = desiredNodes["totalStat"].nodeWeight * (5 * targetSmallNodes.otherSmalls + 10 * targetSmallNodes.attributeSmalls)
2409-
addedWeight = addedWeight + resultNodes[curSeed]["totalStat"].totalWeight * 4
2410-
resultNodes[curSeed]["totalStat"].totalWeight = resultNodes[curSeed]["totalStat"].totalWeight + addedWeight
2411-
seedWeights[curSeed] = seedWeights[curSeed] + addedWeight
2412-
else
2413-
local addedWeight = desiredNodes["totalStat"].nodeWeight * (4 * targetSmallNodes.otherSmalls + 2 * targetSmallNodes.attributeSmalls)
2414-
addedWeight = addedWeight + resultNodes[curSeed]["totalStat"].totalWeight * 19
2415-
resultNodes[curSeed]["totalStat"].totalWeight = resultNodes[curSeed]["totalStat"].totalWeight + addedWeight
2416-
seedWeights[curSeed] = seedWeights[curSeed] + addedWeight
2417-
end
2418-
end
2419-
-- check minimum weights
2420-
for _, val in ipairs(minimumWeights) do
2421-
if (resultNodes[curSeed][val.reqNode] and resultNodes[curSeed][val.reqNode].totalWeight or 0) < val.weight then
2422-
resultNodes[curSeed] = nil
2423-
break
2424-
end
2425-
end
2426-
end
2427-
2428-
return {
2429-
resultNodes = resultNodes,
2430-
seedWeights = seedWeights,
2431-
desiredNodes = desiredNodes,
2432-
socketInfo = socketInfo
2433-
}
2434-
end
2435-
2436-
local function formatSearchValue(input)
2437-
local matchPattern1 = " 0"
2438-
local replacePattern1 = " "
2439-
local matchPattern2 = ".0 "
2440-
local replacePattern2 = " "
2441-
local matchPattern3 = " %."
2442-
local replacePattern3 = "0."
2443-
local matchPattern4 = "%.([0-9])0"
2444-
local replacePattern4 = ".%1 "
2445-
return (" " .. s_format("%006.2f", input))
2446-
:gsub(matchPattern1, replacePattern1):gsub(matchPattern1, replacePattern1)
2447-
:gsub(matchPattern2, replacePattern2):gsub(matchPattern2, replacePattern2)
2448-
:gsub(matchPattern3, replacePattern3)
2449-
:gsub(matchPattern4, replacePattern4)
2450-
end
2451-
2452-
local function formatResults(resultNodes, seedWeights, desiredNodes, socketInfo)
2453-
local results = { }
2454-
for seedMatch, seedData in pairs(resultNodes) do
2455-
-- filter out the results so that only the ones that beat the total minimum weight parameter remain in search results
2456-
local passesMin = (not timelessData.totalMinimumWeight) or (seedWeights[seedMatch] >= timelessData.totalMinimumWeight)
2457-
if seedWeights[seedMatch] > 0 and passesMin then
2458-
local labelPrefix = socketInfo and (socketInfo.label .. " | ") or ""
2459-
local result = {
2460-
label = labelPrefix .. seedMatch .. ":",
2461-
seed = seedMatch,
2462-
total = seedWeights[seedMatch]
2463-
}
2464-
if socketInfo then
2465-
result.socketId = socketInfo.id
2466-
result.socketLabel = socketInfo.label
2467-
end
2468-
if timelessData.jewelType.id == 1 or timelessData.jewelType.id == 3 then
2469-
-- Glorious Vanity [100-8000], Brutal Restraint [500-8000]
2470-
if seedMatch < 1000 then
2471-
result.label = " " .. result.label
2405+
if resultNodes[curSeed] and desiredNodes["totalStat"] then
2406+
resultNodes[curSeed]["totalStat"] = resultNodes[curSeed]["totalStat"] or { targetNodeNames = { }, totalWeight = 0 }
2407+
if timelessData.jewelType.id == 4 then -- Militant Faith
2408+
local addedWeight = desiredNodes["totalStat"].nodeWeight * (5 * targetSmallNodes.otherSmalls + 10 * targetSmallNodes.attributeSmalls)
2409+
addedWeight = addedWeight + resultNodes[curSeed]["totalStat"].totalWeight * 4
2410+
resultNodes[curSeed]["totalStat"].totalWeight = resultNodes[curSeed]["totalStat"].totalWeight + addedWeight
2411+
seedWeights[curSeed] = seedWeights[curSeed] + addedWeight
2412+
else
2413+
local addedWeight = desiredNodes["totalStat"].nodeWeight * (4 * targetSmallNodes.otherSmalls + 2 * targetSmallNodes.attributeSmalls)
2414+
addedWeight = addedWeight + resultNodes[curSeed]["totalStat"].totalWeight * 19
2415+
resultNodes[curSeed]["totalStat"].totalWeight = resultNodes[curSeed]["totalStat"].totalWeight + addedWeight
2416+
seedWeights[curSeed] = seedWeights[curSeed] + addedWeight
24722417
end
24732418
elseif timelessData.jewelType.id == 4 then
24742419
-- Militant Faith [2000-10000]
@@ -2483,18 +2428,13 @@ function TreeTabClass:FindTimelessJewel()
24832428
result.label = " " .. result.label
24842429
end
24852430
end
2486-
local sortedNodeArray = { }
2487-
for legionId, desiredNode in pairs(desiredNodes) do
2488-
if seedData[legionId] then
2489-
if desiredNode.desiredIdx == 8 then
2490-
sortedNodeArray[8] = " ..."
2491-
elseif desiredNode.desiredIdx < 8 then
2492-
sortedNodeArray[desiredNode.desiredIdx] = formatSearchValue(seedData[legionId].totalWeight)
2431+
if resultNodes[curSeed] then
2432+
-- check minimum weights
2433+
for _, val in ipairs(minimumWeights) do
2434+
if (resultNodes[curSeed][val.reqNode] and resultNodes[curSeed][val.reqNode].totalWeight or 0) < val.weight then
2435+
resultNodes[curSeed] = nil
2436+
break
24932437
end
2494-
result[legionId] = result[legionId] or { }
2495-
result[legionId].targetNodeNames = seedData[legionId].targetNodeNames
2496-
elseif desiredNode.desiredIdx < 8 then
2497-
sortedNodeArray[desiredNode.desiredIdx] = " 0 "
24982438
end
24992439
end
25002440
result.label = result.label .. t_concat(sortedNodeArray)

0 commit comments

Comments
 (0)