Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timeless Jewel implementation #4527

Merged
merged 39 commits into from Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2e6738f
WIP: start of Timeless Jewel implementation
Nostrademous Jul 4, 2022
cf3ac64
QoL minor edit
Nostrademous Jul 4, 2022
a7251af
Feat: add auto-addition of timeless stats to Notables for 'add' case
Nostrademous Jul 4, 2022
83a2797
Feat: added Militant Faith; made additions to Notables on separate line
Nostrademous Jul 4, 2022
f99722a
Feat: Add Elegant Hubris, add support for 'replace'
Nostrademous Jul 5, 2022
b05fff3
Fix: remove a print; add a print
Nostrademous Jul 5, 2022
7b42311
Fix: added change recommendations from Lothrik
Nostrademous Jul 5, 2022
ca99e60
Fix: fix things that broke in last commit
Nostrademous Jul 5, 2022
aeb5a67
fix correct file (#11)
Regisle Jul 5, 2022
6fb79f0
Fix Militant Faith
Jul 5, 2022
d768d16
Remove all remaining editedNode logic and add timeless jewel search U…
Lothrik Jul 5, 2022
7405be1
move handling of result out of read function
Regisle Jul 5, 2022
6aa56e0
swap to using numerical IDs and move seed range check
Regisle Jul 5, 2022
5223ffa
fix issues
Regisle Jul 5, 2022
b2d1aa7
Merge branch 'Timesless2' into Timeless
Jul 5, 2022
6dcf82a
Glorious Vanity
Jul 5, 2022
9fdd4a8
WIP: GV stuff
Nostrademous Jul 5, 2022
1e800d8
WIP: more GV processing fixes
Nostrademous Jul 5, 2022
19f50d7
WIP: more fixes
Nostrademous Jul 5, 2022
1eda478
Fix: reading the GV file fully
Nostrademous Jul 5, 2022
8d6169b
Fix: Glorious Vanity timeless implemenation - still need to set roll …
Nostrademous Jul 6, 2022
61843e0
Second pass on Timeless Jewel search UI (#15)
Lothrik Jul 6, 2022
7056dfa
add handling of small and might_legacy of the vaal
Regisle Jul 6, 2022
365bd50
add stats to might and legacy of the vaal
Regisle Jul 6, 2022
6efc48a
add bias to better determine node type
Regisle Jul 6, 2022
f95252e
add stat ranges for might and legacy of the vaal
Regisle Jul 6, 2022
5e7269c
Implement timeless jewel search function (#16)
Lothrik Jul 6, 2022
36d1894
remove no-op as its unused now
Regisle Jul 6, 2022
8fa25ff
Update to use 1 NodeIndex file
Jul 6, 2022
91a7878
fix additions conflict
Regisle Jul 6, 2022
f3681f4
jewel data conflict
Regisle Jul 6, 2022
576a113
Merge branch 'Timesless2' into Timeless
Jul 6, 2022
3ecfabb
Merge branch 'Timeless' into add_Timeless-Jewel-Support
Jul 6, 2022
d286fc9
Move Glorious Vanity to zip file
Jul 6, 2022
40d3c3e
Fix Elegant Hubris seeds in jewel search tool (#4528)
Lothrik Jul 6, 2022
08b3131
Fix integer Glorious Vanity notables, load LUTs from compressed files…
Wires77 Jul 9, 2022
aed02e5
Further timeless jewel search improvements (#4529)
Lothrik Jul 9, 2022
b1826fb
Merge remote-tracking branch 'fork/dev' into add_Timeless-Jewel-Support
Wires77 Jul 10, 2022
9c788d7
Further Timeless Jewel search improvements (#4546)
Lothrik Jul 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
285 changes: 164 additions & 121 deletions src/Classes/PassiveSpec.lua
Expand Up @@ -119,46 +119,6 @@ function PassiveSpecClass:Load(xml, dbFileName)
elseif url then
self:DecodeURL(url)
end
for _, node in pairs(xml) do
if type(node) == "table" then
if node.elem == "EditedNodes" then
for _, child in ipairs(node) do
if not child.attrib.nodeId then
launch:ShowErrMsg("^1Error parsing '%s': 'EditedNode' element missing 'nodeId' attribute", dbFileName)
return true
end
if not child.attrib.editorSeed then
launch:ShowErrMsg("^1Error parsing '%s': 'EditedNode' element missing 'editorSeed' attribute", dbFileName)
return true
end

local editorSeed = tonumber(child.attrib.editorSeed)
local nodeId = tonumber(child.attrib.nodeId)
if not self.tree.legion.editedNodes then
self.tree.legion.editedNodes = { }
end
if not self.tree.legion.editedNodes[editorSeed] then
self.tree.legion.editedNodes[editorSeed] = { }
end
self.tree.legion.editedNodes[editorSeed][nodeId] = copyTable(self.nodes[nodeId], true)
self.tree.legion.editedNodes[editorSeed][nodeId].id = nodeId
self.tree.legion.editedNodes[editorSeed][nodeId].dn = child.attrib.nodeName
self.tree.legion.editedNodes[editorSeed][nodeId].icon = child.attrib.icon
if self.tree.legion.nodes[child.attrib.spriteId] then
self.tree.legion.editedNodes[editorSeed][nodeId].spriteId = child.attrib.spriteId
self.tree.legion.editedNodes[editorSeed][nodeId].sprites = self.tree.legion.nodes[child.attrib.spriteId].sprites
end
local modCount = 0
for _, modLine in ipairs(child) do
for line in string.gmatch(modLine .. "\r\n", "([^\r\n\t]*)\r?\n") do
self:NodeAdditionOrReplacementFromString(self.tree.legion.editedNodes[editorSeed][nodeId], line, modCount == 0)
modCount = modCount + 1
end
end
end
end
end
end
self:ResetUndo()
end

Expand All @@ -171,33 +131,6 @@ function PassiveSpecClass:Save(xml)
for mastery, effect in pairs(self.masterySelections) do
t_insert(masterySelections, "{"..mastery..","..effect.."}")
end
local editedNodes = {
elem = "EditedNodes"
}
if self.tree.legion.editedNodes then
for seed, nodes in pairs(self.tree.legion.editedNodes) do
for nodeId, node in pairs(nodes) do
local editedNode = { elem = "EditedNode", attrib = { nodeId = tostring(nodeId), editorSeed = tostring(seed), nodeName = node.dn, icon = node.icon, spriteId = node.spriteId } }
for _, modLine in ipairs(node.sd) do
t_insert(editedNode, modLine)
end
-- Do not save current editedNode data unless the current node is conquered
if self.nodes[nodeId] and self.nodes[nodeId].conqueredBy then
-- Do not save current editedNode data unless the current node is anointed or allocated
if self.build.calcsTab.mainEnv.grantedPassives[nodeId] then
t_insert(editedNodes, editedNode)
else
for allocNodeId in pairs(self.allocNodes) do
if nodeId == allocNodeId then
t_insert(editedNodes, editedNode)
end
end
end
end
end
end
end
t_insert(xml, editedNodes)
xml.attrib = {
title = self.title,
treeVersion = self.treeVersion,
Expand Down Expand Up @@ -739,67 +672,177 @@ function PassiveSpecClass:BuildAllDependsAndPaths()
if node.conqueredBy and node.type ~= "Socket" then
local conqueredBy = node.conqueredBy
local legionNodes = self.tree.legion.nodes
local legionAdditions = self.tree.legion.additions

-- FIXME - continue implementing
local jewelType = 5
if conqueredBy.conqueror.type == "vaal" then
jewelType = 1
elseif conqueredBy.conqueror.type == "karui" then
jewelType = 2
elseif conqueredBy.conqueror.type == "maraketh" then
jewelType = 3
elseif conqueredBy.conqueror.type == "templar" then
jewelType = 4
end
local seed = conqueredBy.id
if jewelType == 5 then
seed = seed / 20
end

local replaceHelperFunc = function(statToFix, statKey, statMod, value)
if statMod.fmt == "g" then -- note the only one we actualy care about is "Ritual of Flesh" life regen
if statKey:find("per_minute") then
value = round(value / 60, 1)
elseif statKey:find("permyriad") then
value = value / 100
elseif statKey:find("_ms") then
value = value / 1000
end
end
--if statMod.fmt == "d" then -- only ever d or g, and we want both past here
if statMod.min ~= statMod.max then
return statToFix:gsub("%("..statMod.min.."%-"..statMod.max.."%)", value)
elseif statMod.min ~= value then -- only true for might/legacy of the vaal which can combine stats
return statToFix:gsub(statMod.min, value)
end
return statToFix -- if it doesn't need to be changed
end

-- Replace with edited node if applicable
if self.tree.legion.editedNodes and self.tree.legion.editedNodes[conqueredBy.id] and self.tree.legion.editedNodes[conqueredBy.id][node.id] then
local editedNode = self.tree.legion.editedNodes[conqueredBy.id][node.id]
node.dn = editedNode.dn
node.sd = editedNode.sd
node.sprites = editedNode.sprites
node.mods = editedNode.mods
node.modList = editedNode.modList
node.modKey = editedNode.modKey
node.icon = editedNode.icon
node.spriteId = editedNode.spriteId
else
if node.type == "Keystone" then
local legionNode = legionNodes[conqueredBy.conqueror.type.."_keystone_"..conqueredBy.conqueror.id]
self:ReplaceNode(node, legionNode)
elseif conqueredBy.conqueror.type == "eternal" and node.type == "Normal" then
local legionNode = legionNodes["eternal_small_blank"]
self:ReplaceNode(node,legionNode)
elseif conqueredBy.conqueror.type == "eternal" and node.type == "Notable" then
local legionNode = legionNodes["eternal_notable_fire_resistance_1"]
node.dn = "Eternal Empire notable node"
node.sd = {"Right click to set mod"}
node.sprites = legionNode.sprites
node.mods = {""}
node.modList = new("ModList")
node.modKey = ""
node.reminderText = { }
if node.type == "Notable" then
local jewelDataTbl = { }
if seed ~= m_max(m_min(seed, data.timelessJewelSeedMax[jewelType]), data.timelessJewelSeedMin[jewelType]) then
ConPrintf("ERROR: Seed " .. seed .. " is outside of valid range [" .. data.timelessJewelSeedMin[jewelType] .. " - " .. data.timelessJewelSeedMax[jewelType] .. "] for jewel type: " .. data.timelessJewelTypes[jewelType])
else
jewelDataTbl = data.readLUT(conqueredBy.id, node.id, jewelType)
end
--print("Need to Update: " .. node.id .. " [" .. node.dn .. "]")
if not next(jewelDataTbl) then
ConPrintf("Missing LUT: " .. data.timelessJewelTypes[jewelType])
else
if jewelType == 1 then
local headerSize = #jewelDataTbl
-- FIXME: complete implementation of this. Need to set roll values for stats
-- based on their `fmt` specification
if headerSize == 2 or headerSize == 3 then
self:ReplaceNode(node, legionNodes[jewelDataTbl[1] - 94])

for i, repStat in ipairs(legionNodes[jewelDataTbl[1] - 94].sd) do
local statKey = legionNodes[jewelDataTbl[1] - 94].sortedStats[i]
local statMod = legionNodes[jewelDataTbl[1] - 94].stats[statKey]
repStat = replaceHelperFunc(repStat, statKey, statMod, jewelDataTbl[statMod.index + 1])
self:NodeAdditionOrReplacementFromString(node, repStat, i == 1) -- wipe mods on first run
end
-- should fix the stat values here (note headerSize == 3 has 2 values)
elseif headerSize == 6 or headerSize == 8 then
local bias = 0
for i,val in ipairs(jewelDataTbl) do
if i > (headerSize / 2) then
break
elseif val <= 21 then
bias = bias + 1
else
bias = bias - 1
end
end
if bias >= 0 then
self:ReplaceNode(node, legionNodes[76]) -- might of the vaal
else
self:ReplaceNode(node, legionNodes[77]) -- legacy of the vaal
end
local additions = {}
for i,val in ipairs(jewelDataTbl) do
if i <= (headerSize / 2) then
local roll = jewelDataTbl[i + headerSize / 2]
if not additions[val] then
additions[val] = roll
else
additions[val] = additions[val] + roll
end
else
break
end
end
for add,val in pairs(additions) do
local addition = legionAdditions[add]
for _, addStat in ipairs(addition.sd) do
for k,statMod in pairs(addition.stats) do -- should only be 1 big, these didnt get changed so cant just grab index
addStat = replaceHelperFunc(addStat, k, statMod, val)
end
self:NodeAdditionOrReplacementFromString(node, addStat)
end
end
else
ConPrintf("Unhandled Glorious Vanity headerSize: " .. headerSize)
end
else
for _, jewelData in ipairs(jewelDataTbl) do
if jewelData >= 94 then -- replace
jewelData = jewelData - 94
local legionNode = legionNodes[jewelData]
if legionNode then
self:ReplaceNode(node, legionNode)
else
ConPrintf("Unhandled 'replace' ID: " .. jewelData)
end
elseif jewelData then -- add
local addition = legionAdditions[jewelData]
for _, addStat in ipairs(addition.sd) do
self:NodeAdditionOrReplacementFromString(node, " \n" .. addStat)
end
elseif next(jewelData) then
ConPrintf("Unhandled OP: " .. jewelData)
end
end
end
end
elseif node.type == "Keystone" then
local matchStr = conqueredBy.conqueror.type .. "_keystone_" .. conqueredBy.conqueror.id
for _, legionNode in ipairs(legionNodes) do
if legionNode.id == matchStr then
self:ReplaceNode(node, legionNode)
break
end
end
elseif node.type == "Normal" then
if conqueredBy.conqueror.type == "vaal" then
local jewelDataTbl = { }
if seed ~= m_max(m_min(seed, data.timelessJewelSeedMax[jewelType]), data.timelessJewelSeedMin[jewelType]) then
ConPrintf("ERROR: Seed " .. seed .. " is outside of valid range [" .. data.timelessJewelSeedMin[jewelType] .. " - " .. data.timelessJewelSeedMax[jewelType] .. "] for jewel type: " .. data.timelessJewelTypes[jewelType])
else
jewelDataTbl = data.readLUT(conqueredBy.id, node.id, jewelType)
end
print("Need to Update: " .. node.id .. " [" .. node.dn .. "]")
if not next(jewelDataTbl) then
ConPrintf("Missing LUT: " .. data.timelessJewelTypes[jewelType])
else
self:ReplaceNode(node, legionNodes[jewelDataTbl[1] - 94])
for i, repStat in ipairs(node.sd) do
local statKey = legionNodes[jewelDataTbl[1] - 94].sortedStats[i]
local statMod = legionNodes[jewelDataTbl[1] - 94].stats[statKey]
repStat = replaceHelperFunc(repStat, statKey, statMod, jewelDataTbl[2])
self:NodeAdditionOrReplacementFromString(node, repStat, true)
end
end
elseif conqueredBy.conqueror.type == "karui" then
local str = isValueInArray(attributes, node.dn) and "2" or "4"
self:NodeAdditionOrReplacementFromString(node, " \n+" .. str .. " to Strength")
elseif conqueredBy.conqueror.type == "maraketh" then
local dex = isValueInArray(attributes, node.dn) and "2" or "4"
self:NodeAdditionOrReplacementFromString(node, " \n+" .. dex .. " to Dexterity")
elseif conqueredBy.conqueror.type == "templar" then
if isValueInArray(attributes, node.dn) then
local legionNode =legionNodes["templar_devotion_node"]
self:ReplaceNode(node,legionNode)
local legionNode = legionNodes[90] -- templar_devotion_node
self:ReplaceNode(node, legionNode)
else
self:NodeAdditionOrReplacementFromString(node,"+5 to Devotion")
self:NodeAdditionOrReplacementFromString(node, " \n+5 to Devotion")
end
elseif conqueredBy.conqueror.type == "maraketh" and node.type == "Normal" then
local dex = isValueInArray(attributes, node.dn) and "2" or "4"
self:NodeAdditionOrReplacementFromString(node,"+"..dex.." to Dexterity")
elseif conqueredBy.conqueror.type == "karui" and node.type == "Normal" then
local str = isValueInArray(attributes, node.dn) and "2" or "4"
self:NodeAdditionOrReplacementFromString(node,"+"..str.." to Strength")
elseif conqueredBy.conqueror.type == "vaal" and node.type == "Normal" then
local legionNode =legionNodes["vaal_small_fire_resistance"]
node.dn = "Vaal small node"
node.sd = {"Right click to set mod"}
node.sprites = legionNode.sprites
node.mods = {""}
node.modList = new("ModList")
node.modKey = ""
elseif conqueredBy.conqueror.type == "vaal" and node.type == "Notable" then
local legionNode =legionNodes["vaal_notable_curse_1"]
node.dn = "Vaal notable node"
node.sd = {"Right click to set mod"}
node.sprites = legionNode.sprites
node.mods = {""}
node.modList = new("ModList")
node.modKey = ""
node.reminderText = { }
elseif conqueredBy.conqueror.type == "eternal" then
local legionNode = legionNodes[109] -- eternal_small_blank
self:ReplaceNode(node, legionNode)
end
self:ReconnectNodeToClassStart(node)
end
self:ReconnectNodeToClassStart(node)
end
end

Expand Down
21 changes: 0 additions & 21 deletions src/Classes/PassiveTreeView.lua
Expand Up @@ -292,19 +292,6 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
build.itemsTab:SelectControl(slot)
build.viewMode = "ITEMS"
end

--[[ Only allow node editing in these situations:
Vaal (Glorious Vanity): any non-keystone
Maraketh (Brutal Restraint): only notables, +dex already set
Eternal (Elegant Hubris): only notables, other passives are blank
Karui (Lethal Pride): only notables, +str already set
Templar (Militant Faith): any non-keystone, non-notables add devotion or replace with devotion
]]--
elseif hoverNode and hoverNode.conqueredBy and hoverNode.type ~= "Keystone" and
(hoverNode.conqueredBy.conqueror.type == "vaal"
or hoverNode.isNotable) then
build.treeTab:ModifyNodePopup(hoverNode, viewPort)
build.buildFlag = true
elseif hoverNode and hoverNode.alloc and hoverNode.type == "Mastery" and hoverNode.masteryEffects then
build.treeTab:OpenMasteryPopup(hoverNode, viewPort)
build.buildFlag = true
Expand Down Expand Up @@ -1009,14 +996,6 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build)
end
end

-- Conqueror node editing
if node and node.conqueredBy and node.type ~= "Keystone" and
(node.conqueredBy.conqueror.type == "vaal"
or node.isNotable) then
tooltip:AddSeparator(14)
tooltip:AddLine(14, colorCodes.TIP.."Tip: Right click to edit the modifiers for this node")
end

-- Mod differences
if self.showStatDifferences then
local calcFunc, calcBase = build.calcsTab:GetMiscCalculator(build)
Expand Down