--[[ TheUndermineJournal addon, v 5.5 https://theunderminejournal.com/ You should be able to query this DB from other addons: o={} TUJMarketInfo(52719,o) print(o['market']) Prints the market price of Greater Celestial Essence. The item can be identified by anything GetItemInfo takes (itemid, itemstring, itemlink) or a battlepet itemstring/itemlink. Prices are returned in copper, but accurate to the last *silver* (with coppers always 0). o['input'] -> the item/battlepet parameter you just passed in, verbatim o['itemid'] -> the ID of the item you just passed in o['species'] -> the species of the battlepet you just passed in o['quality'] -> the numeric quality/rarity of the battlepet o['age'] -> number of seconds since data was compiled o['globalMedian'] -> median market price across all realms in this region o['globalMean'] -> mean market price across all realms in this region o['globalStdDev'] -> standard deviation of the market price across all realms in this region o['market'] -> average market price of the item on this AH over the past 14 days. o['stddev'] -> standard deviation of market price of the item on this AH over the past 14 days. o['recent'] -> average market price of the item on this AH over the past 3 days. o['days'] -> number of days since item was last seen on the auction house, when data was compiled. valid values 0 - 250. o['days'] = 251 means item was seen on this AH, but over 250 days ago o['days'] = 252 means the item is sold by vendors in unlimited quantities o['days'] = 255 means item was never seen on this AH (since 6.0 patch) You can also query and set whether the additional tooltip lines appear from this addon. This is useful for other addons (Auctioneer, TSM, etc) that have their own fancy tooltips to disable TUJ tooltips and use TUJ simply as a data source. TUJTooltip() -> returns a boolean whether TUJ tooltips are enabled TUJTooltip(true) -> enables TUJ tooltips TUJTooltip(false) -> disables TUJ tooltips ]] local floor = math.floor local tinsert, tonumber = tinsert, tonumber local function coins(money) local GOLD="ffd100" local SILVER="e6e6e6" local COPPER="c8602c" local GSC_3 = "|cff%s%d|cff999999.|cff%s%02d|cff999999.|cff%s%02d|r" local GSC_2 = "|cff%s%d|cff999999.|cff%s%02d|r" money = floor(tonumber(money) or 0) local g = floor(money / 10000) local s = floor(money % 10000 / 100) local c = money % 100 if (c > 0) then return GSC_3:format(GOLD, g, SILVER, s, COPPER, c) else return GSC_2:format(GOLD, g, SILVER, s) end end local function char2dec(s) local n, l = 0, string.len(s) for i=1,l,1 do n = n * 256 + string.byte(s,i) end return n end local function round(num) return floor(num + 0.5) end local addonName, addonTable = ... local prettyName = '|cFF33FF99The Undermine Journal|r' local function getSpeciesFromPetLink(link) local petString = string.match(link, "battlepet[%-?%d:]+") local _, speciesID, level, quality, health, power, speed = strsplit(":", petString) speciesID = tonumber(speciesID,10) level = tonumber(level,10) quality = tonumber(quality,10) health = tonumber(health,10) power = tonumber(power,10) speed = tonumber(speed,10) return speciesID, level, quality, health, power, speed end local marketInfoCache, marketInfoCacheKeys, marketInfoCacheMaxDepth = {}, {}, 16 local GetDetailedItemLevelInfo = addonTable.GetDetailedItemLevelInfo local function InfoCacheKeyComparitor(x,y) return marketInfoCache[x]['__queried'] < marketInfoCache[y]['__queried'] end --[[ pass a table as the second argument to wipe and reuse that table otherwise a new table will be created and returned ]] function TUJMarketInfo(item,...) if item == 0 then if addonTable.marketData then return true else return false end end local numargs = select('#', ...) local tr if (numargs > 0) and (type(select(1,...)) == 'table') then tr = select(1,...) wipe(tr) end if not addonTable.marketData then return tr end if marketInfoCache[item] then marketInfoCache[item]['__queried'] = GetTime() if not marketInfoCache[item]['input'] then return tr end if not tr then tr = {} end for k,v in pairs(marketInfoCache[item]) do tr[k] = v end tr['__queried'] = nil return tr end if #marketInfoCacheKeys >= marketInfoCacheMaxDepth then -- reuse oldest cache table sort(marketInfoCacheKeys, InfoCacheKeyComparitor) marketInfoCache[item] = marketInfoCache[marketInfoCacheKeys[1]] wipe(marketInfoCache[item]) while #marketInfoCacheKeys >= marketInfoCacheMaxDepth do marketInfoCache[marketInfoCacheKeys[1]] = nil table.remove(marketInfoCacheKeys, 1) end else -- add new table to cache marketInfoCache[item] = {} end table.insert(marketInfoCacheKeys, item) marketInfoCache[item]['__queried'] = GetTime() local _, link, dataKey local iid, pricingLevel, species, quality if (strfind(item, 'battlepet:')) then species, _, quality = getSpeciesFromPetLink(item) dataKey = 's'..species else local itemId, _, _, _, _, itemClass = GetItemInfoInstant(item) if not itemId then return tr end iid = itemId dataKey = tostring(iid) pricingLevel = 0 if (itemClass == 2) or (itemClass == 4) then local effectiveLevel, previewLevel, origLevel = GetDetailedItemLevelInfo(item) -- effectiveLevel may be nil when GetItemInfo didn't have the item readily available. if effectiveLevel then pricingLevel = effectiveLevel if not addonTable.marketData[dataKey .. 'x' .. pricingLevel] then local low, high = math.min(effectiveLevel, previewLevel or effectiveLevel, origLevel), math.max(effectiveLevel, previewLevel or effectiveLevel, origLevel) for i=low,high,1 do if addonTable.marketData[dataKey .. 'x' .. i] then pricingLevel = i end end end end end if pricingLevel > 0 then dataKey = dataKey .. 'x' .. pricingLevel end end local dta = addonTable.marketData[dataKey] if not dta then return tr end if not tr then tr = {} end tr['input'] = item if (iid) then tr['itemid'] = iid end if (species) then tr['species'] = species tr['quality'] = quality end if addonTable.dataAge then tr['age'] = time() - addonTable.dataAge end local priceSize = string.byte(dta, 1) local offset = 2 tr['globalMedian'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 if tr['globalMedian'] == 0 then tr['globalMedian'] = nil end offset = offset + priceSize tr['globalMean'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 offset = offset + priceSize tr['globalStdDev'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 offset = offset + priceSize tr['days'] = string.byte(dta, offset, offset) offset = offset + 1 tr['market'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 offset = offset + priceSize tr['stddev'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 offset = offset + priceSize tr['recent'] = round(char2dec(string.sub(dta, offset, offset+priceSize-1))) * 100 --offset = offset + priceSize for k,v in pairs(tr) do marketInfoCache[item][k] = v end return tr end --[[ enable/disable/query whether the TUJ tooltip additions are enabled ]] local tooltipsEnabled = true function TUJTooltip(...) if select('#', ...) >= 1 then tooltipsEnabled = not not select(1,...) --coerce into boolean local line = strmatch(debugstack(2, 1, 0), "[Aa][Dd][Dd][Oo][Nn][Ss]\\([^\\]+)") if line and line ~= addonName then local callingName, callingTitle = GetAddOnInfo(line) if callingName then callingName = callingTitle or callingName if tooltipsEnabled then line = 'enabled' else line = 'disabled' end print(prettyName .. " - Tooltip prices " .. line .. " by " .. callingName) end end end return tooltipsEnabled end local tooltipsSettings = {} local qualityRGB = { [0] = {0.616,0.616,0.616}, [1] = {1,1,1}, [2] = {0.118,1,0}, [3] = {0,0.439,0.867}, [4] = {0.639,0.208,0.933}, [5] = {1,0.502,0}, [6] = {0.898,0.8,0.502}, [7] = {0.898,0.8,0.502}, [8] = {0,0.8,1}, [9] = {0.443,0.835,1}, } local LibExtraTip = LibStub("LibExtraTip-1") local function buildExtraTip(tooltip, pricingData) local r,g,b = .9,.8,.5 LibExtraTip:AddLine(tooltip," ",r,g,b,true) if (pricingData['age'] > 3*24*60*60) and not tooltipsSettings['disable-age'] then LibExtraTip:AddLine(tooltip,"As of "..SecondsToTime(pricingData['age'],pricingData['age']>60).." ago:",r,g,b,true) end if pricingData['recent'] and not tooltipsSettings['disable-recent'] then LibExtraTip:AddDoubleLine(tooltip,"3-Day Price",coins(pricingData['recent']),r,g,b,nil,nil,nil,true) end if pricingData['market'] and not tooltipsSettings['disable-market'] then LibExtraTip:AddDoubleLine(tooltip,"14-Day Price",coins(pricingData['market']),r,g,b,nil,nil,nil,true) end if pricingData['stddev'] and not tooltipsSettings['disable-stddev'] then LibExtraTip:AddDoubleLine(tooltip,"14-Day Std Dev",coins(pricingData['stddev']),r,g,b,nil,nil,nil,true) end local regionName = addonTable.region or "Regional" if pricingData['globalMedian'] and not tooltipsSettings['disable-globalMedian'] then LibExtraTip:AddDoubleLine(tooltip,regionName.." Median",coins(pricingData['globalMedian']),r,g,b,nil,nil,nil,true) end if pricingData['globalMean'] and not tooltipsSettings['disable-globalMean'] then LibExtraTip:AddDoubleLine(tooltip,regionName.." Mean",coins(pricingData['globalMean']),r,g,b,nil,nil,nil,true) end if pricingData['globalStdDev'] and not tooltipsSettings['disable-globalStdDev'] then LibExtraTip:AddDoubleLine(tooltip,regionName.." Std Dev",coins(pricingData['globalStdDev']),r,g,b,nil,nil,nil,true) end if not tooltipsSettings['disable-lastSeen'] then if pricingData['days'] == 255 then LibExtraTip:AddLine(tooltip,"Never seen since WoD",r,g,b,true) elseif pricingData['days'] == 252 then LibExtraTip:AddLine(tooltip,"Sold by Vendors",r,g,b,true) elseif pricingData['days'] > 250 then LibExtraTip:AddLine(tooltip,"Last seen over 250 days ago",r,g,b,true) elseif pricingData['days'] > 1 then LibExtraTip:AddLine(tooltip,"Last seen "..SecondsToTime(pricingData['days']*24*60*60).." ago",r,g,b,true) end end end local function printHelp() local function getLineStatus(lineName) if tooltipsSettings['disable-' .. lineName] then return '(|cFFFF0000OFF|r)' else return '(|cFF00FF00ON|r)' end end local regionName = addonTable.region or "Regional" print(prettyName .. " - Arguments for |cFFFFFF78/tujtooltip|r are:") print("|cFFFFFF78on|r|||cFFFFFF78off|r - Enable/disable tooltip modifications.") print("|cFFFFFF78reset|r - Reset all preferences and enable all lines.") print("|cFFFFFF78quiet|r - Disable all lines.") print("|cFFFFFF78age|r - Toggle data age line. " .. getLineStatus('age')) print("|cFFFFFF78recent|r - Toggle 3-day price line. " .. getLineStatus('recent')) print("|cFFFFFF78market|r - Toggle 14-day price line. " .. getLineStatus('market')) print("|cFFFFFF78stddev|r - Toggle 14-day std dev line. " .. getLineStatus('stddev')) print("|cFFFFFF78region-median|r - Toggle " .. regionName .. " median line. " .. getLineStatus('globalMedian')) print("|cFFFFFF78region-mean|r - Toggle " .. regionName .. " mean line. " .. getLineStatus('globalMean')) print("|cFFFFFF78region-stddev|r - Toggle " .. regionName .. " std dev line. " .. getLineStatus('globalStdDev')) print("|cFFFFFF78lastseen|r - Toggle 'Last seen' line. " .. getLineStatus('lastSeen')) end local dataResults = {} local function onTooltipSetItem(tooltip, itemLink, quantity) if not addonTable.marketData then return end if not tooltipsEnabled then return end if not itemLink then return end TUJMarketInfo(itemLink, dataResults) if not (dataResults['input'] and (dataResults['input'] == itemLink)) then return end buildExtraTip(tooltip, dataResults) end local eventframe = CreateFrame("FRAME",addonName.."Events") local function onEvent(self,event,arg) if event == "PLAYER_ENTERING_WORLD" then eventframe:UnregisterEvent("PLAYER_ENTERING_WORLD") local realmId = LibStub("LibRealmInfo"):GetRealmInfo(GetRealmName()) if not realmId then local guid = UnitGUID("player") if guid then realmId = tonumber(strmatch(guid, "^Player%-(%d+)")) end end if not realmId then realmId = "nil" else for i=1,#addonTable.dataLoads,1 do addonTable.dataLoads[i](realmId) addonTable.dataLoads[i]=nil end end wipe(addonTable.dataLoads) collectgarbage("collect") -- lots of strings made and trunc'ed in MarketData if not addonTable.realmIndex then print(prettyName .. " - Warning: could not find data for realm ID "..realmId..", no data loaded!") elseif not addonTable.marketData then print(prettyName .. " - Warning: no data loaded!") else if not tooltipsEnabled then print(prettyName .. " - Tooltip prices disabled. Run |cFFFFFF78/tujtooltip on|r to enable.") end LibExtraTip:AddCallback({type = "item", callback = onTooltipSetItem}) LibExtraTip:AddCallback({type = "battlepet", callback = onTooltipSetItem}) LibExtraTip:RegisterTooltip(GameTooltip) LibExtraTip:RegisterTooltip(ItemRefTooltip) LibExtraTip:RegisterTooltip(BattlePetTooltip) LibExtraTip:RegisterTooltip(FloatingBattlePetTooltip) end elseif event == "ADDON_LOADED" and arg == addonName then tooltipsEnabled = not _G["TUJTooltipsHidden"] tooltipsSettings = _G["TUJTooltipsSettings"] or {} elseif event == "PLAYER_LOGOUT" then _G["TUJTooltipsHidden"] = not tooltipsEnabled _G["TUJTooltipsSettings"] = tooltipsSettings end end eventframe:RegisterEvent("PLAYER_ENTERING_WORLD") eventframe:RegisterEvent("ADDON_LOADED") eventframe:RegisterEvent("PLAYER_LOGOUT") eventframe:SetScript("OnEvent", onEvent) SLASH_THEUNDERMINEJOURNAL1 = '/tujtooltip' function SlashCmdList.THEUNDERMINEJOURNAL(msg) local lineNames = { ['age'] = 'age', ['recent'] = 'recent', ['3day'] = 'recent', ['3-day'] = 'recent', ['market'] = 'market', ['14day'] = 'market', ['14-day'] = 'market', ['stddev'] = 'stddev', ['14daysd'] = 'stddev', ['14-daysd'] = 'stddev', ['14-day-sd'] = 'stddev', ['standarddeviation'] = 'stddev', ['globalmedian'] = 'globalMedian', ['global-median'] = 'globalMedian', ['regionmedian'] = 'globalMedian', ['region-median'] = 'globalMedian', ['globalmean'] = 'globalMean', ['global-mean'] = 'globalMean', ['regionmean'] = 'globalMean', ['region-mean'] = 'globalMean', ['globalstddev'] = 'globalStdDev', ['global-stddev'] = 'globalStdDev', ['regionstddev'] = 'globalStdDev', ['region-stddev'] = 'globalStdDev', ['lastseen'] = 'lastSeen', ['last-seen'] = 'lastSeen', } local loweredMsg = string.lower(msg) if msg == 'reset' then wipe(tooltipsSettings) TUJTooltip(true) print(prettyName .. " - Preferences reset to defaults.") elseif msg == 'quiet' then for input, lineName in pairs(lineNames) do local settingName = 'disable-' .. lineName tooltipsSettings[settingName] = true end print(prettyName .. " - All lines disabled.") return elseif lineNames[loweredMsg] then local lineName = lineNames[loweredMsg] local settingName = 'disable-' .. lineName if tooltipsSettings[settingName] then tooltipsSettings[settingName] = nil; print(prettyName .. " - |cFFFFFF78" .. lineName .. "|r line enabled.") else tooltipsSettings[settingName] = true; print(prettyName .. " - |cFFFFFF78" .. lineName .. "|r line disabled.") end return elseif msg == 'on' then TUJTooltip(true) print(prettyName .. " - Tooltip additions enabled.") elseif msg == 'off' then TUJTooltip(false) print(prettyName .. " - Tooltip additions disabled.") else printHelp() end end local origGetAuctionBuyout = GetAuctionBuyout local getAuctionBuyoutTable = {} function GetAuctionBuyout(item) -- Tekkub's API local result = TUJMarketInfo(item, getAuctionBuyoutTable) if (result and result['input'] == item) then if (result['market']) then return result['market'] else return result['globalMedian'] end end if (origGetAuctionBuyout) then return origGetAuctionBuyout(item) end return nil end