Skip to content

Commit be599ce

Browse files
vaisestbornaivankovicLocalIdentity
authored
Watcher's eye trade search (#9649)
* Watcher's eye trade search * Improvements per comments - move find button to separate slot instead of using exisitng jewel sockets - use exisitng Watcher's Eye slot(if available) for usage in weight calculations with test item - added option to include rest of applicable mods from Watcher's Eye mod pool that have weight 0 in final query * fix merge mistake * remove debugger setup -.- * Fix getting unweighted mods * Actually include corrupted mods * fix checkboxcontrol for watchers eye * show tooltips for watcher's eye search. either against all jewels or against an equipped eye * remove mirrored button from eye and megalomaniac search because it is useless * fix valid slot for watcher's eye * Move mods to correct places Moves the mods to their correct areas in ModParser Removes parsing for mods that we do not currently support calcs for * Fix crash when opening trader with empty jewel socket * Fix skill name parsing --------- Co-authored-by: Borna Ivankovic <borna.ivankovic92@gmail.com> Co-authored-by: LocalIdentity <localidentity2@gmail.com>
1 parent 9ba6e03 commit be599ce

5 files changed

Lines changed: 1505 additions & 36 deletions

File tree

src/Classes/TradeQuery.lua

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,14 @@ Highest Weight - Displays the order retrieved from trade]]
486486
return hideRowFunc(self, row_count)
487487
end
488488
row_count = row_count + 1
489+
-- Watcher's Eye
490+
self.slotTables[row_count] = { slotName = "Watcher's Eye", unique = true }
491+
self:PriceItemRowDisplay(row_count, top_pane_alignment_ref, row_vertical_padding, row_height)
492+
self.controls["name"..row_count].y = self.controls["name"..row_count].y + (row_height + row_vertical_padding)
493+
self.controls["name"..row_count].shown = function()
494+
return hideRowFunc(self, row_count) and self:findValidSlotForWatchersEye()
495+
end
496+
row_count = row_count + 1
489497

490498
local effective_row_count = row_count - ((scrollBarShown and #slotTables >= 19) and #slotTables-19 or 0) + 2 + 2 -- Two top menu rows, two bottom rows, slots after #19 overlap the other controls at the bottom of the pane
491499
self.effective_rows_height = row_height * (effective_row_count - #slotTables + (18 - (#slotTables > 37 and 3 or 0))) -- scrollBar height, "18 - slotTables > 37" logic is fine tuning whitespace after last row
@@ -870,12 +878,38 @@ function TradeQueryClass:addChaosEquivalentPriceToItems(items)
870878
return outputItems
871879
end
872880

881+
-- return valid slot for Watcher's Eye
882+
-- Tries to first return an existing watcher's eye slot if possible
883+
function TradeQueryClass:findValidSlotForWatchersEye()
884+
for _, socket in pairs(self.itemsTab.sockets) do
885+
local socketItem = self.itemsTab.items[socket.selItemId]
886+
if not socket.inactive and socketItem and socketItem.name and socketItem.name:find("Watcher's Eye") then
887+
return socket
888+
end
889+
end
890+
local tmpWE=nil
891+
for _,v in ipairs(data.uniques.generated) do
892+
if v:find("Watcher's Eye") then
893+
tmpWE= new("Item",v)
894+
break
895+
end
896+
end
897+
for _,v in pairs(self.itemsTab.sockets) do
898+
if not v.inactive and self.itemsTab:IsItemValidForSlot(tmpWE,v.slotName,self.itemsTab.activeItemSet) then
899+
return self.itemsTab.sockets[v.nodeId]
900+
end
901+
end
902+
end
903+
873904
-- Method to generate pane elements for each item slot
874905
function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, row_vertical_padding, row_height)
875906
local controls = self.controls
876907
local slotTbl = self.slotTables[row_idx]
877908
local activeSlotRef = slotTbl.nodeId and self.itemsTab.activeItemSet[slotTbl.nodeId] or self.itemsTab.activeItemSet[slotTbl.slotName]
878-
local activeSlot = slotTbl.nodeId and self.itemsTab.sockets[slotTbl.nodeId] or slotTbl.slotName and (self.itemsTab.slots[slotTbl.slotName] or slotTbl.fullName and self.itemsTab.slots[slotTbl.fullName]) -- fullName for Abyssal Sockets
909+
local activeSlot = slotTbl.nodeId and self.itemsTab.sockets[slotTbl.nodeId] or
910+
slotTbl.slotName and (self.itemsTab.slots[slotTbl.slotName] or
911+
slotTbl.slotName == "Watcher's Eye" and self:findValidSlotForWatchersEye() or
912+
slotTbl.fullName and self.itemsTab.slots[slotTbl.fullName]) -- fullName for Abyssal Sockets
879913
local nameColor = slotTbl.unique and colorCodes.UNIQUE or "^7"
880914
controls["name"..row_idx] = new("LabelControl", top_pane_alignment_ref, {0, row_idx*(row_height + row_vertical_padding), 100, row_height - 4}, nameColor..slotTbl.slotName)
881915
controls["bestButton"..row_idx] = new("ButtonControl", { "LEFT", controls["name"..row_idx], "LEFT"}, {100 + 8, 0, 80, row_height}, "Find best", function()
@@ -1013,7 +1047,16 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
10131047
local result = self.resultTbl[row_idx][pb_index]
10141048
local item = new("Item", result.item_string)
10151049
tooltip:Clear()
1016-
self.itemsTab:AddItemTooltip(tooltip, item, slotTbl)
1050+
if slotTbl.slotName == "Watcher's Eye" then
1051+
local firstValidSlot = self:findValidSlotForWatchersEye()
1052+
local currentItem = firstValidSlot.selItemId ~= 0 and self.itemsTab.items[firstValidSlot.selItemId]
1053+
local eyeEquipped = currentItem and currentItem.name:find("Watcher's Eye")
1054+
-- for watcher's eye we can compare to an already existing one, or
1055+
-- default to comparing with all active sockets
1056+
self.itemsTab:AddItemTooltip(tooltip, item, eyeEquipped and firstValidSlot or nil)
1057+
else
1058+
self.itemsTab:AddItemTooltip(tooltip, item, slotTbl)
1059+
end
10171060
addMegalomaniacCompareToTooltipIfApplicable(tooltip, pb_index)
10181061
tooltip:AddSeparator(10)
10191062
tooltip:AddLine(16, string.format("^7Price: %s %s", result.amount, result.currency))
@@ -1041,7 +1084,18 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
10411084
-- item.baseName is nil and throws error in the following AddItemTooltip func
10421085
-- if the item is unidentified
10431086
local item = new("Item", item_string)
1044-
self.itemsTab:AddItemTooltip(tooltip, item, slotTbl, true)
1087+
-- for watcher's eye we can compare to an already existing one, or
1088+
-- default to comparing with all active sockets
1089+
if slotTbl.slotName == "Watcher's Eye" then
1090+
local firstValidSlot = self:findValidSlotForWatchersEye()
1091+
local currentItem = firstValidSlot.selItemId ~= 0 and self.itemsTab.items[firstValidSlot.selItemId]
1092+
local eyeEquipped = currentItem and currentItem.name:find("Watcher's Eye")
1093+
-- for watcher's eye we can compare to an already existing one, or
1094+
-- default to comparing with all active sockets
1095+
self.itemsTab:AddItemTooltip(tooltip, item, eyeEquipped and firstValidSlot or nil, true)
1096+
else
1097+
self.itemsTab:AddItemTooltip(tooltip, item, slotTbl, true)
1098+
end
10451099
addMegalomaniacCompareToTooltipIfApplicable(tooltip, selected_result_index)
10461100
end
10471101
end

src/Classes/TradeQueryGenerator.lua

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ local tradeStatCategoryIndices = {
8080
["Exarch"] = 3,
8181
["Synthesis"] = 3,
8282
["PassiveNode"] = 2,
83+
["WatchersEye"] = 2,
8384
}
8485

8586
local influenceSuffixes = { "_shaper", "_elder", "_adjudicator", "_basilisk", "_crusader", "_eyrie"}
@@ -406,6 +407,7 @@ function TradeQueryGeneratorClass:InitMods()
406407
["Exarch"] = { },
407408
["Synthesis"] = { },
408409
["PassiveNode"] = { },
410+
["WatchersEye"] = { },
409411
}
410412

411413
-- originates from: https://www.pathofexile.com/api/trade/data/stats
@@ -464,6 +466,17 @@ function TradeQueryGeneratorClass:InitMods()
464466
end
465467
self:GenerateModData(clusterNotableMods, tradeQueryStatsParsed)
466468

469+
-- Watcher's Eye
470+
local watchersEyeMods = {}
471+
for _,v in pairs(data.uniqueMods["Watcher's Eye"]) do
472+
if v.Id:find("SublimeVision") or v.Id:find("SummonArbalist") then
473+
goto continue
474+
end
475+
watchersEyeMods[v.Id] = v.mod
476+
watchersEyeMods[v.Id].type = "WatchersEye"
477+
::continue::
478+
end
479+
self:GenerateModData(watchersEyeMods,tradeQueryStatsParsed,{ ["BaseJewel"] = true, ["AnyJewel"] = true },{["AnyJewel"]="AnyJewel"})
467480
-- Base item implicit mods. A lot of this code is duplicated from generateModData(), but with important small logical flow changes to handle the format differences
468481
local subTypeState = { }
469482
local function updateRangeSubType(range, entry)
@@ -727,6 +740,28 @@ function TradeQueryGeneratorClass:StartQuery(slot, options)
727740
calcNodesInsteadOfMods = true,
728741
}
729742
end
743+
if options.special.itemName == "Watcher's Eye" then
744+
special={
745+
queryExtra = {
746+
name = "Watcher's Eye"
747+
},
748+
queryFilters = {
749+
type_filters = {
750+
filters = {
751+
category = {
752+
option = "jewel"
753+
},
754+
rarity = {
755+
option = "unique"
756+
}
757+
}
758+
}
759+
},
760+
watchersEye = true
761+
}
762+
itemCategory = "AnyJewel"
763+
itemCategoryQueryStr = "jewel"
764+
end
730765
elseif slot.slotName:find("^Weapon %d") then
731766
if existingItem then
732767
if existingItem.type == "Shield" then
@@ -874,6 +909,13 @@ function TradeQueryGeneratorClass:ExecuteQuery()
874909
self:GeneratePassiveNodeWeights(self.modData.PassiveNode)
875910
return
876911
end
912+
if self.calcContext.special.watchersEye then
913+
self:GenerateModWeights(self.modData.WatchersEye)
914+
if self.calcContext.options.includeCorrupted then
915+
self:GenerateModWeights(self.modData["Corrupted"])
916+
end
917+
return
918+
end
877919
self:GenerateModWeights(self.modData["Explicit"])
878920
self:GenerateModWeights(self.modData["Implicit"])
879921
if self.calcContext.options.includeCorrupted then
@@ -891,6 +933,36 @@ function TradeQueryGeneratorClass:ExecuteQuery()
891933
end
892934
end
893935

936+
function TradeQueryGeneratorClass:addMoreWEMods()
937+
local function getTableOfTradeModIds(tbl)
938+
local tmpTable={}
939+
for _,val in ipairs(tbl) do
940+
table.insert(tmpTable,val.tradeModId)
941+
end
942+
return tmpTable
943+
end
944+
for _,skillGroup in ipairs(self.itemsTab.build.skillsTab.socketGroupList) do
945+
for _,gem in ipairs(skillGroup.gemList) do
946+
local tmpAura=""
947+
if not gem.enabled then
948+
goto continue
949+
elseif gem.nameSpec:find("Vaal") and gem.enableGlobal2 then
950+
tmpAura=gem.nameSpec:gsub("Vaal ",""):gsub("Impurity","Purity"):gsub("of","Of"):gsub(" ","")
951+
elseif gem.gemData and gem.gemData.tags.aura or gem.fromItem then
952+
tmpAura=gem.nameSpec:gsub("of","Of"):gsub(" ","")
953+
else
954+
goto continue
955+
end
956+
for id,mod in pairs(self.modData.WatchersEye) do
957+
if id:find(tmpAura) and not isValueInTable(getTableOfTradeModIds(self.modWeights),mod.tradeMod.id) then
958+
table.insert(self.modWeights,{invert=false,meanStatDiff=0,weight=0,tradeModId=mod.tradeMod.id})
959+
end
960+
end
961+
::continue::
962+
end
963+
end
964+
end
965+
894966
function TradeQueryGeneratorClass:FinishQuery()
895967
-- Calc original item Stats without anoint or enchant, and use that diff as a basis for default min sum.
896968
local originalItem = self.calcContext.slot and self.itemsTab.items[self.calcContext.slot.selItemId]
@@ -914,6 +986,10 @@ function TradeQueryGeneratorClass:FinishQuery()
914986
local originalOutput = originalItem and self.calcContext.calcFunc({ repSlotName = self.calcContext.slot.slotName, repItem = self.calcContext.testItem }) or self.calcContext.baseOutput
915987
local currentStatDiff = TradeQueryGeneratorClass.WeightedRatioOutputs(self.calcContext.baseOutput, originalOutput, self.calcContext.options.statWeights) * 1000 - (self.calcContext.baseStatValue or 0)
916988

989+
if self.calcContext.options.includeAllWEMods then
990+
self:addMoreWEMods()
991+
end
992+
917993
-- Sort by mean Stat diff rather than weight to more accurately prioritize stats that can contribute more
918994
table.sort(self.modWeights, function(a, b)
919995
if a.meanStatDiff == b.meanStatDiff then
@@ -1116,9 +1192,12 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb
11161192
options.special = { itemName = context.slotTbl.slotName }
11171193
end
11181194

1119-
controls.includeMirrored = new("CheckBoxControl", {"TOPRIGHT",lastItemAnchor,"BOTTOMRIGHT"}, {0, 5, 18}, "Mirrored items:", function(state) end)
1120-
controls.includeMirrored.state = (self.lastIncludeMirrored == nil or self.lastIncludeMirrored == true)
1121-
updateLastAnchor(controls.includeMirrored)
1195+
-- these unique items cannot be mirrored
1196+
if not context.slotTbl.unique then
1197+
controls.includeMirrored = new("CheckBoxControl", {"TOPRIGHT",lastItemAnchor,"BOTTOMRIGHT"}, {0, 5, 18}, "Mirrored items:", function(state) end)
1198+
controls.includeMirrored.state = (self.lastIncludeMirrored == nil or self.lastIncludeMirrored == true)
1199+
updateLastAnchor(controls.includeMirrored)
1200+
end
11221201

11231202
if not isJewelSlot and not isAbyssalJewelSlot and includeScourge then
11241203
controls.includeScourge = new("CheckBoxControl", {"TOPRIGHT",lastItemAnchor,"BOTTOMRIGHT"}, {0, 5, 18}, "Scourge Mods:", function(state) end)
@@ -1138,12 +1217,12 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb
11381217
updateLastAnchor(controls.includeEldritch)
11391218
end
11401219

1141-
if isJewelSlot then
1220+
if isJewelSlot and context.slotTbl.slotName ~= "Watcher's Eye" then
11421221
controls.jewelType = new("DropDownControl", {"TOPLEFT",lastItemAnchor,"BOTTOMLEFT"}, {0, 5, 100, 18}, { "Any", "Base", "Abyss" }, function(index, value) end)
11431222
controls.jewelType.selIndex = self.lastJewelType or 1
11441223
controls.jewelTypeLabel = new("LabelControl", {"RIGHT",controls.jewelType,"LEFT"}, {-5, 0, 0, 16}, "Jewel Type:")
11451224
updateLastAnchor(controls.jewelType)
1146-
elseif slot and not isAbyssalJewelSlot then
1225+
elseif slot and not isAbyssalJewelSlot and context.slotTbl.slotName ~= "Watcher's Eye" then
11471226
controls.influence1 = new("DropDownControl", {"TOPLEFT",lastItemAnchor,"BOTTOMLEFT"}, {0, 5, 100, 18}, influenceDropdownNames, function(index, value) end)
11481227
controls.influence1.selIndex = self.lastInfluence1 or 1
11491228
controls.influence1Label = new("LabelControl", {"RIGHT",controls.influence1,"LEFT"}, {-5, 0, 0, 16}, "Influence 1:")
@@ -1213,6 +1292,13 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb
12131292
end
12141293
popupHeight = popupHeight + 4
12151294

1295+
if context.slotTbl.slotName == "Watcher's Eye" then
1296+
controls.includeAllWEMods = new("CheckBoxControl", {"TOPRIGHT",lastItemAnchor,"BOTTOMRIGHT"}, {0, 5, 18}, "Include all Watcher's Eye mods:", function(state) end)
1297+
controls.includeAllWEMods.tooltipText = "Include mods that could not have a weight calculated for them at weight 0."
1298+
lastItemAnchor = controls.includeAllWEMods
1299+
popupHeight = popupHeight + 23
1300+
end
1301+
12161302
controls.generateQuery = new("ButtonControl", { "BOTTOM", nil, "BOTTOM" }, {-45, -10, 80, 20}, "Execute", function()
12171303
main:ClosePopup()
12181304

@@ -1265,6 +1351,9 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb
12651351
if controls.links and controls.links.buf then
12661352
options.links = tonumber(controls.links.buf)
12671353
end
1354+
if controls.includeAllWEMods then
1355+
options.includeAllWEMods = controls.includeAllWEMods.state
1356+
end
12681357
options.statWeights = statWeights
12691358

12701359
self:StartQuery(slot, options)

0 commit comments

Comments
 (0)