@@ -29,48 +29,11 @@ function M.modLineValue(line)
2929 return tonumber (line :match (" [%d]+%.?[%d]*" )) or 0
3030end
3131
32- -- Helper: lazily build a reverse lookup from QueryMods tradeMod.text → tradeMod.id
33- local _tradeModLookup = nil
34- local function getTradeModLookup ()
35- if _tradeModLookup then return _tradeModLookup end
36- _tradeModLookup = {}
37- if not queryModsData then return _tradeModLookup end
38- for _groupName , mods in pairs (queryModsData ) do
39- for _modKey , modData in pairs (mods ) do
40- if type (modData ) == " table" and modData .tradeMod then
41- local text = modData .tradeMod .text
42- local modType = modData .tradeMod .type or " explicit"
43- local id = modData .tradeMod .id
44- local key = text .. " |" .. modType
45- _tradeModLookup [key ] = id
46- if not _tradeModLookup [text ] then
47- _tradeModLookup [text ] = id
48- end
49- -- Also store with template-converted text for mods with literal numbers
50- -- (e.g. "1 Added Passive Skill is X" → "# Added Passive Skill is X")
51- local template = M .modLineTemplate (text )
52- if template ~= text then
53- local templateKey = template .. " |" .. modType
54- if not _tradeModLookup [templateKey ] then
55- _tradeModLookup [templateKey ] = id
56- end
57- if not _tradeModLookup [template ] then
58- _tradeModLookup [template ] = id
59- end
60- end
61- end
62- end
63- end
64- return _tradeModLookup
65- end
66-
67- -- Helper: lazily fetch and cache the trade API stats for comprehensive mod matching
68- -- Covers mods not in QueryMods.lua (cluster enchants, unique-specific mods, etc.)
69- local _tradeStatsLookup = nil
32+ -- Helper: fetch and cache the trade API stats
33+ local _tradeStats = nil
7034local _tradeStatsFetched = false
7135local function getTradeStatsLookup ()
72- if _tradeStatsFetched then return _tradeStatsLookup end
73- _tradeStatsFetched = true
36+ if _tradeStats then return _tradeStats end
7437 local tradeStats = " "
7538 local easy = common .curl .easy ()
7639 if not easy then return nil end
@@ -82,24 +45,10 @@ local function getTradeStatsLookup()
8245 end )
8346 local ok = easy :perform ()
8447 easy :close ()
85- if not ok or tradeStats == " " then return nil end
48+ if not ok or tradeStats == " " then return {} end
8649 local parsed = dkjson .decode (tradeStats )
87- if not parsed or not parsed .result then return nil end
88- _tradeStatsLookup = {}
89- for _ , category in ipairs (parsed .result ) do
90- local catLabel = category .label
91- for _ , entry in ipairs (category .entries ) do
92- local stripped = entry .text :gsub (" [#()0-9%-%+%.]" , " " )
93- local key = stripped .. " |" .. catLabel
94- if not _tradeStatsLookup [key ] then
95- _tradeStatsLookup [key ] = entry
96- end
97- if not _tradeStatsLookup [stripped ] then
98- _tradeStatsLookup [stripped ] = entry
99- end
100- end
101- end
102- return _tradeStatsLookup
50+ _tradeStats = parsed .result
51+ return _tradeStats
10352end
10453
10554-- Map source types used in OpenBuySimilarPopup to trade API category labels
@@ -109,48 +58,83 @@ M.sourceTypeToCategory = {
10958 [" enchant" ] = " Enchant" ,
11059}
11160
112- -- Helper: find the trade stat ID for a mod line
113- function M .findTradeModId (modLine , modType )
114- -- Try QueryMods-based lookup
115- local lookup = getTradeModLookup ()
116- local template = M .modLineTemplate (modLine )
117- -- Try exact match with type first
118- local key = template .. " |" .. modType
119- if lookup [key ] then
120- return lookup [key ]
121- end
122- -- Try without leading +/- sign
123- local stripped = template :gsub (" ^[%+%-]" , " " )
124- key = stripped .. " |" .. modType
125- if lookup [key ] then
126- return lookup [key ]
127- end
128- -- Fallback: match by template text only (any type)
129- if lookup [template ] then
130- return lookup [template ]
131- end
132- if lookup [stripped ] then
133- return lookup [stripped ]
61+ function M .shouldBeInverted (tradeId , modLine , modType )
62+ local formattedLine = M .formatDatabaseText (M .formatDatabaseText (modLine ))
63+ for _ , category in ipairs (getTradeStatsLookup ()) do
64+ if category .id == modType then
65+ for _ , stat in ipairs (category .entries ) do
66+ if tradeId == stat .id then
67+ -- local modifiers don't seem to be inverted
68+ if stat .text :match (" (Local)" ) then
69+ return false
70+ end
71+ -- trade site sometimes has a + sign, sometimes not
72+ return not (formattedLine == stat .text or formattedLine :gsub (" ^%+" , " " ) == stat .text )
73+ end
74+ end
75+ end
13476 end
77+ end
13578
136- -- Try trade API stats (covers mods not in QueryMods)
137- local tradeStats = getTradeStatsLookup ()
138- if tradeStats then
139- local strippedLine = modLine :gsub (" [#()0-9%-%+%.]" , " " )
140- local category = M .sourceTypeToCategory [modType ]
141- if category then
142- local catKey = strippedLine .. " |" .. category
143- if tradeStats [catKey ] then
144- return tradeStats [catKey ].id
79+ -- Helper: normalise data texts to # format
80+ function M .formatDatabaseText (text )
81+ -- decimal -> integer
82+ text = text :gsub (" %d+%.%d+" , " 1" )
83+ -- (123-124) -> #
84+ text = text :gsub (" %(%d+%-%d+%)" , " #" )
85+ text = text :gsub (" %d+" , " #" )
86+ return text
87+ end
88+
89+ -- Helper: find the trade stat ID for a mod line
90+ function M .findTradeHash (item , modLine , modType )
91+ local formattedLine = M .formatDatabaseText (modLine )
92+ -- the data export splits some mods into different parts, even though they
93+ -- are technically just one stat. we handle that here
94+ function findStat (dbMod )
95+ local lineIdx = 1
96+ local statIdx = 1
97+ while dbMod .statOrder [lineIdx ] do
98+ local skipped = false
99+ while dbMod .statOrder [lineIdx ] == m_floor (dbMod .statOrder [lineIdx + 1 ] or - 1 ) do
100+ -- some stats are split, skip those for now
101+ lineIdx = lineIdx + 1
102+ skipped = true
103+ end
104+ if not skipped and dbMod [lineIdx ] then
105+ local dbFormatted = M .formatDatabaseText (dbMod [lineIdx ])
106+ if formattedLine == dbFormatted and item :GetModSpawnWeight (dbMod , nil , {default = true }) then
107+ return dbMod .tradeHashes [statIdx ]
108+ end
109+ end
110+ lineIdx = lineIdx + 1
111+ statIdx = statIdx + 1
112+ end
113+ end
114+ -- corruptions
115+ if modType == " enchant" then
116+ for _ , dbMod in pairs (data .itemMods .Corruption ) do
117+ local tradeHashMaybe = findStat (dbMod )
118+ if tradeHashMaybe then
119+ return tradeHashMaybe
145120 end
146121 end
147- -- Fallback: any category
148- if tradeStats [strippedLine ] then
149- return tradeStats [strippedLine ].id
122+ -- explicit
123+ elseif modType ~= " implicit" then
124+ for _ , dbMod in pairs (data .itemMods .Item ) do
125+ local tradeHashMaybe = findStat (dbMod )
126+ if tradeHashMaybe then
127+ return tradeHashMaybe
128+ end
150129 end
151130 end
152-
153- return nil
131+ -- implicit, and special explicit (e.g. unique and essence)
132+ for _ , dbMod in pairs (data .itemMods .Exclusive ) do
133+ local tradeHashMaybe = findStat (dbMod )
134+ if tradeHashMaybe then
135+ return tradeHashMaybe
136+ end
137+ end
154138end
155139
156140-- Map slot name + item type to (trade API category string, itemCategoryTags key).
@@ -164,6 +148,7 @@ function M.getTradeCategoryInfo(slotName, item)
164148 if itemType == " Shield" then return " armour.shield" , " Shield"
165149 elseif itemType == " Quiver" then return " armour.quiver" , " Quiver"
166150 elseif itemType == " Bow" then return " weapon.bow" , " Bow"
151+ elseif itemType == " Staff" and item .base .subType == " Warstaff" then return " weapon.warstaff" , " Staff"
167152 elseif itemType == " Staff" then return " weapon.staff" , " Staff"
168153 elseif itemType == " Two Handed Sword" then return " weapon.twosword" , " 2HSword"
169154 elseif itemType == " Two Handed Axe" then return " weapon.twoaxe" , " 2HAxe"
0 commit comments