668 lines
25 KiB
Lua
668 lines
25 KiB
Lua
--[[
|
|
Auctioneer - StatPurchased
|
|
Version: 5.7.4568 (KillerKoala)
|
|
Revision: $Id: StatPurchased.lua 4840 2010-08-04 21:44:00Z Nechckn $
|
|
URL: http://auctioneeraddon.com/
|
|
|
|
This is an addon for World of Warcraft that adds statistical history to the auction data that is collected
|
|
when the auction is scanned, so that you can easily determine what price
|
|
you will be able to sell an item for at auction or at a vendor whenever you
|
|
mouse-over an item in the game
|
|
|
|
License:
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program(see GPL.txt); if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
Note:
|
|
This AddOn's source code is specifically designed to work with
|
|
World of Warcraft's interpreted AddOn system.
|
|
You have an implicit license to use this AddOn with these facilities
|
|
since that is its designated purpose as per:
|
|
http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
|
|
--]]
|
|
if not AucAdvanced then return end
|
|
|
|
local libType, libName = "Stat", "Purchased"
|
|
local lib,parent,private = AucAdvanced.NewModule(libType, libName)
|
|
if not lib then return end
|
|
|
|
-- AucAdvanced locals
|
|
local aucPrint,decode,_,_,replicate,empty,get,set,default,debugPrint,fill, _TRANS = AucAdvanced.GetModuleLocals()
|
|
local Const = AucAdvanced.Const
|
|
local GetFaction = AucAdvanced.GetFaction
|
|
|
|
-- globals -> locals
|
|
local assert = assert
|
|
local tinsert = tinsert
|
|
local sqrt = sqrt
|
|
local select,ipairs,pairs,unpack,type,wipe = select,ipairs,pairs,unpack,type,wipe
|
|
local tonumber = tonumber
|
|
local strsplit = strsplit
|
|
local time = time
|
|
local concat = table.concat
|
|
local strmatch = strmatch
|
|
|
|
-- Internal variables
|
|
local SPRealmData
|
|
|
|
local pricecache = setmetatable({}, {__mode="v"})
|
|
|
|
function private.ClearCache()
|
|
wipe(pricecache)
|
|
end
|
|
|
|
function lib.CommandHandler(command, ...)
|
|
local serverKey = GetFaction()
|
|
local _,_,keyText = AucAdvanced.SplitServerKey(serverKey)
|
|
if (command == "help") then
|
|
aucPrint(_TRANS('PURC_Help_SlashHelp1') )--Help for Auctioneer - Purchased
|
|
local line = AucAdvanced.Config.GetCommandLead(libType, libName)
|
|
aucPrint(line, "help}} - ".._TRANS('PURC_Help_SlashHelp2') ) --this Purchased help
|
|
aucPrint(line, "clear}} - ".._TRANS('PURC_Help_SlashHelp3'):format(keyText) ) --clear current {{%s}} Purchased price database
|
|
aucPrint(line, "push}} - ".._TRANS('PURC_Help_SlashHelp4'):format(keyText) ) --force the {{%s}} Purchased daily stats to archive (start a new day)
|
|
elseif (command == _TRANS('clear') ) then
|
|
lib.ClearData(serverKey)
|
|
elseif (command == _TRANS('push') ) then
|
|
aucPrint(_TRANS('PURC_Help_SlashHelp5'):format(keyText) ) --Archiving {{%s}} daily stats and starting a new day
|
|
private.PushStats(serverKey)
|
|
end
|
|
end
|
|
|
|
function lib.Processor(callbackType, ...)
|
|
if (callbackType == "tooltip") then
|
|
private.ProcessTooltip(...)
|
|
elseif (callbackType == "config") then
|
|
--Called when you should build your Configator tab.
|
|
private.SetupConfigGui(...)
|
|
elseif callbackType == "scanstats" then
|
|
private.ClearCache()
|
|
end
|
|
end
|
|
lib.Processors = {}
|
|
function lib.Processors.tooltip(callbackType, ...)
|
|
private.ProcessTooltip(...)
|
|
end
|
|
function lib.Processors.config(callbackType, ...)
|
|
--Called when you should build your Configator tab.
|
|
private.SetupConfigGui(...)
|
|
end
|
|
function lib.Processors.scanstats(callbackType, ...)
|
|
private.ClearCache()
|
|
end
|
|
|
|
|
|
|
|
lib.ScanProcessors = {}
|
|
function lib.ScanProcessors.delete(operation, itemData, oldData)
|
|
local price
|
|
|
|
local auctionmaxtime = Const.AucMinTimes[itemData.timeLeft] or 86400
|
|
if (time() - itemData.seenTime <= auctionmaxtime) then
|
|
-- Auction deleted earlier than expected expiry time
|
|
local buy = itemData.buyoutPrice
|
|
if buy and buy > 0 then
|
|
-- assume bought out
|
|
price = buy
|
|
end
|
|
--[[ disabled code
|
|
-- bid detection code temporarily disabled
|
|
-- assumed bids should probably not be treated the same as assumed buyouts with respect to market price
|
|
-- needs further development
|
|
else -- Auction deleted later than earliest expected expiry time
|
|
local bid = itemData.curBid
|
|
if bid and bid > 0 then
|
|
-- assume won on last bid we saw
|
|
price = bid
|
|
end
|
|
-- end disabled code]]
|
|
end
|
|
|
|
if not price then return end
|
|
|
|
price = price / itemData.stackSize
|
|
|
|
local pricedata = private.GetPriceData(GetFaction())
|
|
local itemType, itemId, property, factor = decode(itemData.link)
|
|
if (factor ~= 0) then property = property.."x"..factor end
|
|
if not pricedata.daily[itemId] then pricedata.daily[itemId] = "" end
|
|
local stats = private.UnpackStats(pricedata.daily[itemId])
|
|
if not stats[property] then stats[property] = { 0, 0 } end
|
|
stats[property][1] = stats[property][1] + price
|
|
stats[property][2] = stats[property][2] + 1
|
|
pricedata.daily[itemId] = private.PackStats(stats)
|
|
end
|
|
|
|
-- Determines the sample estimated standard deviation based on the deviation
|
|
-- of the daily, 3day, 7day, and 14day averages. This is not technically
|
|
-- correct because they are not independent samples (the 7 day average
|
|
-- includes data from the 3 day and daily averages, for example). Still
|
|
-- it provides a good estimation in the presence of lack of data. If you
|
|
-- want to discuss the math behind this estimation, find Shirik
|
|
-- @param hyperlink The item to look up
|
|
-- @param serverKey The realm-faction key from which to look up the data
|
|
-- @return The estimated population mean
|
|
-- @return The estimated population standard deviation
|
|
-- @return The number of views found to base the standard deviation upon
|
|
|
|
local dataset = {}
|
|
|
|
function private.EstimateStandardDeviation(hyperlink, serverKey)
|
|
local dayAverage, avg3, avg7, avg14, _, dayTotal, dayCount, seenDays, seenCount = lib.GetPrice(hyperlink, serverKey)
|
|
|
|
if not seenDays then return end
|
|
|
|
local count = 0
|
|
if dayAverage then --[[dayAverage should never be nil at this point. It may be 0 if item has not been seen today - does that mess up the stats?]]
|
|
count = count + 1
|
|
dataset[count] = dayAverage
|
|
end
|
|
if seenDays >= 3 then
|
|
count = count + 1
|
|
dataset[count] = avg3
|
|
if seenDays >= 7 then
|
|
count = count + 1
|
|
dataset[count] = avg7
|
|
if seenDays >= 14 then
|
|
count = count + 1
|
|
dataset[count] = avg14
|
|
end
|
|
end
|
|
end
|
|
|
|
if count == 0 then -- No data
|
|
aucPrint(_TRANS('PURC_Interface_WarningPurchasedEmpty'):format(hyperlink) )--Warning: Purchased dataset for %s is empty.
|
|
return
|
|
end
|
|
|
|
local mean = 0
|
|
for i=1,count do
|
|
mean = mean + dataset[count]
|
|
end
|
|
mean = mean / count
|
|
|
|
local variance = 0
|
|
for i=1,count do
|
|
variance = variance + (mean - dataset[count])^2
|
|
end
|
|
|
|
return mean, sqrt(variance), count
|
|
end
|
|
|
|
|
|
local bellCurve = AucAdvanced.API.GenerateBellCurve();
|
|
-- Gets the PDF curve for a given item. This curve indicates
|
|
-- the probability of an item's mean price. Uses an estimation
|
|
-- of the normally distributed bell curve by performing
|
|
-- calculations on the daily, 3-day, 7-day, and 14-day averages
|
|
-- stored by SIMP
|
|
-- @param hyperlink The item to generate the PDF curve for
|
|
-- @param serverKey The realm-faction key from which to look up the data
|
|
-- @return The PDF for the requested item, or nil if no data is available
|
|
-- @return The lower limit of meaningful data for the PDF (determined
|
|
-- as the mean minus 5 standard deviations)
|
|
-- @return The upper limit of meaningful data for the PDF (determined
|
|
-- as the mean plus 5 standard deviations)
|
|
function lib.GetItemPDF(hyperlink, serverKey)
|
|
-- TODO: This is an estimate. Can we touch this up later? Especially the stddev==0 case
|
|
if not get("stat.purchased.enable") then return end --disable purchased if desired
|
|
|
|
-- Calculate the SE estimated standard deviation & mean
|
|
local mean, stddev, count = private.EstimateStandardDeviation(hyperlink, serverKey)
|
|
|
|
if stddev ~= stddev or mean ~= mean or not mean or mean == 0 then
|
|
return ; -- No available data or cannot estimate
|
|
end
|
|
|
|
if not count or count == 0 then
|
|
aucPrint(mean)
|
|
aucPrint(stddev)
|
|
aucPrint(count)
|
|
aucPrint(_TRANS('PURC_Interface_CountBroken') ..hyperlink)--count broken! for
|
|
count = 1
|
|
end
|
|
-- If the standard deviation is zero, we'll have some issues, so we'll estimate it by saying
|
|
-- the std dev is 100% of the mean divided by square root of number of views
|
|
if stddev == 0 then stddev = mean / sqrt(count); end
|
|
|
|
|
|
-- Calculate the lower and upper bounds as +/- 3 standard deviations
|
|
local lower, upper = mean - 3*stddev, mean + 3*stddev;
|
|
|
|
bellCurve:SetParameters(mean, stddev);
|
|
return bellCurve, lower, upper;
|
|
end
|
|
|
|
function lib.GetPrice(hyperlink, serverKey)
|
|
if not get("stat.purchased.enable") then return end --disable purchased if desired
|
|
serverKey = serverKey or GetFaction()
|
|
|
|
local data = private.GetPriceData(serverKey)
|
|
|
|
local linkType,itemId,property,factor = decode(hyperlink)
|
|
if (linkType ~= "item") then return end
|
|
if (factor ~= 0) then property = property.."x"..factor end
|
|
|
|
local cachesig = serverKey..itemId..":"..property
|
|
if pricecache[cachesig] then
|
|
local dayAverage, avg3, avg7, avg14, dayTotal, dayCount, seenDays, seenCount = unpack(pricecache[cachesig], 1, 8)
|
|
return dayAverage, avg3, avg7, avg14, false, dayTotal, dayCount, seenDays, seenCount
|
|
end
|
|
|
|
local dayTotal, dayCount, dayAverage = 0,0,0
|
|
local seenDays, seenCount, avg3, avg7, avg14 = 0,0,0,0,0
|
|
|
|
if data.daily[itemId] then
|
|
local stats = private.UnpackStats(data.daily[itemId])
|
|
if stats[property] then
|
|
dayTotal, dayCount = unpack(stats[property])
|
|
dayAverage = dayTotal/dayCount
|
|
end
|
|
end
|
|
if data.means[itemId] then
|
|
local stats = private.UnpackStats(data.means[itemId])
|
|
if stats[property] then
|
|
seenDays, seenCount, avg3, avg7, avg14 = unpack(stats[property])
|
|
end
|
|
end
|
|
pricecache[cachesig] = {dayAverage, avg3, avg7, avg14, dayTotal, dayCount, seenDays, seenCount}
|
|
return dayAverage, avg3, avg7, avg14, false, dayTotal, dayCount, seenDays, seenCount
|
|
end
|
|
|
|
function lib.GetPriceColumns()
|
|
return "Daily Avg", "3 Day Avg", "7 Day Avg", "14 Day Avg", false, "Daily Total", "Daily Count", "Seen Days", "Seen Count"
|
|
end
|
|
|
|
local pricearray={} -- used to return stuff in
|
|
function lib.GetPriceArray(hyperlink, serverKey)
|
|
if not get("stat.purchased.enable") then return end --disable purchased if desired
|
|
wipe(pricearray)
|
|
|
|
-- Get our statistics
|
|
local dayAverage, avg3, avg7, avg14, _, dayTotal, dayCount, seenDays, seenCount = lib.GetPrice(hyperlink, serverKey)
|
|
|
|
-- pricearray.price and pricearray.seen are the ones that most algorithms will look for
|
|
pricearray.seen = seenCount
|
|
if not get("stat.purchased.reportsafe") then
|
|
pricearray.price = avg3 or dayAverage
|
|
else
|
|
-- Safe mode: prefer longer-running averages for low-volume items
|
|
if seenCount>100 and seenCount > seenDays*10 then
|
|
pricearray.price = avg3 or dayAverage
|
|
-- aucPrint(hyperlink..": seen "..seenCount.." over "..seenDays.. "days. going with avg3")
|
|
else
|
|
local a3 = avg3 or dayAverage
|
|
local a7 = avg7 or a3
|
|
local a14 = avg14 or a7
|
|
if seenCount >= seenDays*7 then
|
|
pricearray.price = (a3+a7)/2
|
|
-- aucPrint(hyperlink..": seen "..seenCount.." over "..seenDays.. "days. going with avg(a3,a7)")
|
|
else
|
|
local mix3 = seenCount / (seenDays*7*2) -- 0.07 for 1/1, 0.5 for 7/1
|
|
local mix14 = 0.5-mix3
|
|
local mix7 = 1-mix3-mix14 -- actually always==0.5 :-)
|
|
pricearray.price = a3*mix3 + a7*mix7 + a14*mix14
|
|
-- aucPrint(hyperlink..": seen "..seenCount.." over "..seenDays.. "days. mix3="..mix3.." mix7="..mix7.." mix14="..mix14)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- This is additional data
|
|
pricearray.avgday = dayAverage
|
|
pricearray.avg3 = avg3
|
|
pricearray.avg7 = avg7
|
|
pricearray.avg14 = avg14
|
|
pricearray.daytotal = dayTotal
|
|
pricearray.daycount = dayCount
|
|
pricearray.seendays = seenDays
|
|
|
|
return pricearray
|
|
end
|
|
|
|
function lib.OnLoad(addon)
|
|
if SPRealmData then return end
|
|
-- set defaults
|
|
default("stat.purchased.tooltip", false)
|
|
default("stat.purchased.avg3", false)
|
|
default("stat.purchased.avg7", false)
|
|
default("stat.purchased.avg14", false)
|
|
default("stat.purchased.quantmul", true)
|
|
default("stat.purchased.enable", true)
|
|
default("stat.purchased.reportsafe", false)
|
|
|
|
private.InitData()
|
|
end
|
|
|
|
function private.SetupConfigGui(gui)
|
|
local id = gui:AddTab(lib.libName, lib.libType.." Modules")
|
|
--gui:MakeScrollable(id)
|
|
|
|
gui:AddHelp(id, "what purchased stats",
|
|
_TRANS('PURC_Help_WhatPurchasedStats') ,--What are purchased stats?
|
|
_TRANS('PURC_Help_WhatPurchasedStatsAnswer') )--Purchased stats are the numbers that are generated by the Purchased module, the Purchased module attempts to determine if an auction was bought out or purchased on a bid. It also calculates a Moving Average (3/7/14).
|
|
|
|
--all options in here will be duplicated in the tooltip frame
|
|
function private.addTooltipControls(id)
|
|
gui:AddHelp(id, "what moving day average purchased",
|
|
_TRANS('PURC_Help_WhatMovingAverage') ,--What does 'moving average' mean?
|
|
_TRANS('PURC_Help_WhatMovingAverageAnswer') )--'Moving average means that it places more value on yesterday\'s moving average than today\'s average. The determined amount is then used for tomorrow\'s moving average calculation.
|
|
|
|
gui:AddHelp(id, "how day average calculated purchased",
|
|
_TRANS('PURC_Help_HowMovingAverage') ,--How is the moving day averages calculated exactly?
|
|
_TRANS('PURC_Help_HowMovingAverageAnswer') )--Todays Moving Average is ((X-1)*YesterdaysMovingAverage + TodaysAverage) / X, where X is the number of days (3,7, or 14).
|
|
|
|
gui:AddHelp(id, "no day saved purchased",
|
|
_TRANS('PURC_Help_DayAverage') ,--So you aren\'t saving a day-to-day average?
|
|
_TRANS('PURC_Help_DayAverageAnswer') )--No, that would not only take up space, but heavy calculations on each auction house scan.
|
|
|
|
gui:AddHelp(id, "why multiply stack size stddev",
|
|
_TRANS('PURC_Help_MultiplyStack') ,--Why have the option to multiply stack size?
|
|
_TRANS('PURC_Help_MultiplyStackAnswer') )--The original Stat-Purchased multiplied by the stack size of the item, but some like dealing on a per-item basis.
|
|
|
|
gui:AddHelp(id, "report safe safer price prices value low volume item items",
|
|
_TRANS('PURC_Help_SaferPrices') ,--How are the \'safer\' prices computed?
|
|
_TRANS('PURC_Help_SaferPricesAnswer') )--For anything seen more than 100 times and selling more than 10 items per day (on average), we simply use the 3 day average.\n\nFor others, we value the 7-day average at 50%, and the 3- and 14-day averages at between 0--50% and 50--0%, respectively, depending on how many are seen per day (between 1 and 7).
|
|
|
|
|
|
gui:AddControl(id, "Header", 0, libName.." options")
|
|
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
|
|
|
|
gui:AddControl(id, "Checkbox", 0, 1, "stat.purchased.enable", _TRANS('PURC_Interface_EnablePurchasedStats') )--Enable Purchased Stats
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_EnablePurchasedStats') )--Allow Stat Purchased to gather and return price data
|
|
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
|
|
|
|
gui:AddControl(id, "Checkbox", 0, 4, "stat.purchased.tooltip", _TRANS('PURC_Interface_ShowPurchased') )--Show purchased stats in the tooltips?
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_ShowPurchased') )--Toggle display of stats from the Purchased module on or off
|
|
|
|
gui:AddControl(id, "Checkbox", 0, 6, "stat.purchased.avg3", _TRANS('PURC_Interface_Toggle3Day') )--Display Moving 3 Day Average
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_Toggle3Day') )--Toggle display of 3-Day average from the Purchased module on or off
|
|
gui:AddControl(id, "Checkbox", 0, 6, "stat.purchased.avg7", _TRANS('PURC_Interface_Toggle7Day') )--Display Moving 7 Day Average
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_Toggle7Day') )--Toggle display of 7-Day average from the Purchased module on or off
|
|
gui:AddControl(id, "Checkbox", 0, 6, "stat.purchased.avg14", _TRANS('PURC_Interface_Toggle14Day') )--Display Moving 14 Day Average
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_Toggle14Day') )--Toggle display of 14-Day average from the Purchased module on or off
|
|
|
|
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
|
|
|
|
gui:AddControl(id, "Checkbox", 0, 4, "stat.purchased.reportsafe", _TRANS('PURC_Interface_ReportSaferPrices') )--Report safer prices for low volume items
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_ReportSaferPrices') )--Returns longer averages (7-day, or even 14-day) for low-volume items
|
|
gui:AddControl(id, "Checkbox", 0, 4, "stat.purchased.quantmul", _TRANS('PURC_Interface_MultiplyStack') )--Multiply by Stack Size
|
|
gui:AddTip(id, _TRANS('PURC_HelpTooltip_MultiplyStack') )--Multiplies by current Stack Size if on
|
|
gui:AddControl(id, "Note", 0, 1, nil, nil, " ")
|
|
end
|
|
--This is the Tooltip tab provided by aucadvnced so all tooltip configuration is in one place
|
|
local tooltipID = AucAdvanced.Settings.Gui.tooltipID
|
|
|
|
--now we create a duplicate of these in the tooltip frame
|
|
private.addTooltipControls(id)
|
|
if tooltipID then private.addTooltipControls(tooltipID) end
|
|
|
|
end
|
|
|
|
--[[ Local functions ]]--
|
|
function private.ProcessTooltip(tooltip, name, hyperlink, quality, quantity, cost)
|
|
if not get("stat.purchased.tooltip") then return end
|
|
|
|
if not quantity or quantity < 1 then quantity = 1 end
|
|
if not get("stat.purchased.quantmul") then quantity = 1 end
|
|
local dayAverage, avg3, avg7, avg14, _, dayTotal, dayCount, seenDays, seenCount = lib.GetPrice(hyperlink)
|
|
if (not dayAverage) then return end
|
|
|
|
if (seenDays + dayCount > 0) then
|
|
tooltip:AddLine(_TRANS('PURC_Tooltip_PurchasedPrices'))--Purchased prices:
|
|
|
|
if (seenDays > 0) then
|
|
if (dayCount>0) then seenDays = seenDays + 1 end
|
|
tooltip:AddLine(" ".._TRANS('PURC_Tooltip_SeenNumberDays'):format(seenCount+dayCount, seenDays) )--Seen {{%s}} over {{%s}} days:
|
|
end
|
|
if (seenDays > 6) and get("stat.purchased.avg14") then
|
|
tooltip:AddLine(" ".._TRANS('PURC_Tooltip_14DayAverage'), avg14*quantity)-- 14 day average
|
|
end
|
|
if (seenDays > 2) and get("stat.purchased.avg7") then
|
|
tooltip:AddLine(" ".._TRANS('PURC_Tooltip_7DayAverage'), avg7*quantity)-- 7 day average
|
|
end
|
|
if (seenDays > 0) and get("stat.purchased.avg3") then
|
|
tooltip:AddLine(" ".._TRANS('PURC_Tooltip_3DayAverage'), avg3*quantity)-- 3 day average
|
|
end
|
|
if (dayCount > 0) then
|
|
tooltip:AddLine(" ".._TRANS('PURC_Tooltip_SeenToday'):format(dayCount), dayAverage*quantity)--Seen {{%s}} today
|
|
end
|
|
end
|
|
end
|
|
|
|
-- This is a function which migrates the data from a daily average to the
|
|
-- Exponential Moving Averages over the 3, 7 and 14 day ranges.
|
|
function private.PushStats(serverKey)
|
|
local dailyAvg
|
|
|
|
local data = private.GetPriceData(serverKey)
|
|
|
|
local pdata, fdata
|
|
for itemId, stats in pairs(data.daily) do
|
|
if (itemId ~= "created") then
|
|
pdata = private.UnpackStats(stats)
|
|
fdata = private.UnpackStats(data.means[itemId] or "")
|
|
for property, info in pairs(pdata) do
|
|
dailyAvg = info[1] / info[2]
|
|
if not fdata[property] then
|
|
fdata[property] = {
|
|
1,
|
|
info[2],
|
|
("%0.01f"):format(dailyAvg),
|
|
("%0.01f"):format(dailyAvg),
|
|
("%0.01f"):format(dailyAvg),
|
|
}
|
|
else
|
|
fdata[property][1] = fdata[property][1] + 1
|
|
fdata[property][2] = fdata[property][2] + info[2]
|
|
fdata[property][3] = ("%0.01f"):format(((fdata[property][3] * 2) + dailyAvg)/3)
|
|
fdata[property][4] = ("%0.01f"):format(((fdata[property][4] * 6) + dailyAvg)/7)
|
|
fdata[property][5] = ("%0.01f"):format(((fdata[property][5] * 13) + dailyAvg)/14)
|
|
end
|
|
end
|
|
data.means[itemId] = private.PackStats(fdata)
|
|
end
|
|
end
|
|
data.daily = { created = time() }
|
|
private.ClearCache()
|
|
end
|
|
|
|
function private.UnpackStatIter(data, ...)
|
|
local c = select("#", ...)
|
|
local v
|
|
for i = 1, c do
|
|
v = select(i, ...)
|
|
local property, info = strsplit(":", v)
|
|
property = tonumber(property) or property
|
|
if (property and info) then
|
|
data[property] = { strsplit(";", info) }
|
|
local item
|
|
for i=1, #data[property] do
|
|
item = data[property][i]
|
|
data[property][i] = tonumber(item) or item
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function private.UnpackStats(dataItem)
|
|
local data = {}
|
|
private.UnpackStatIter(data, strsplit(",", dataItem))
|
|
return data
|
|
end
|
|
|
|
local tmp={}
|
|
function private.PackStats(data)
|
|
local n=0
|
|
for property, info in pairs(data) do
|
|
tmp[n+1]=property
|
|
tmp[n+2]=":"
|
|
tmp[n+3]=concat(info, ";")
|
|
tmp[n+4]=","
|
|
n=n+4
|
|
end
|
|
return concat(tmp, "", 1, n-1) -- n-1 to skip last ","
|
|
end
|
|
|
|
-- The following Functions are the routines used to access the permanent store data
|
|
|
|
function private.UpgradeDb()
|
|
private.UpgradeDb = nil
|
|
if type(AucAdvancedStatPurchasedData) == "table" and AucAdvancedStatPurchasedData.Version == "2.0" then return end
|
|
|
|
local newSave = { Version = "2.0", RealmData = {} }
|
|
|
|
if type(AucAdvancedStatPurchasedData) == "table" and AucAdvancedStatPurchasedData.Version == "1.0" then
|
|
-- convert from type "1.0" database to type "2.0"
|
|
for realm, realmData in pairs (AucAdvancedStatPurchasedData.RealmData) do
|
|
if type(realm) == "string" and type(realmData) == "table" then
|
|
for faction, data in pairs (realmData) do
|
|
if type(faction) == "string" and type(data) == "table" and strmatch(faction, "^%u%l+$") then
|
|
-- looks like a valid realm/faction combination
|
|
local serverKey = realm.."-"..faction
|
|
local stats = data.stats
|
|
if type(stats) == "table" then
|
|
if type(data.means) ~= "table" then
|
|
data.means = {}
|
|
end
|
|
if type(data.daily) ~= "table" then
|
|
data.daily = { created = time () }
|
|
elseif type(data.daily.created) ~= "number" then
|
|
data.daily.created = time ()
|
|
end
|
|
newSave.RealmData[serverKey] = stats
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
AucAdvancedStatPurchasedData = newSave
|
|
end
|
|
|
|
function lib.ClearData(serverKey)
|
|
serverKey = serverKey or GetFaction()
|
|
if AucAdvanced.API.IsKeyword(serverKey, "ALL") then
|
|
wipe(SPRealmData)
|
|
private.ClearCache()
|
|
aucPrint(_TRANS('PURC_Interface_ClearingPurchased').." {{".._TRANS("ADV_Interface_AllRealms").."}}") --Clearing Purchased stats for // All realms
|
|
elseif SPRealmData[serverKey] then
|
|
local _,_,keyText = AucAdvanced.SplitServerKey(serverKey)
|
|
SPRealmData[serverKey] = nil
|
|
private.ClearCache()
|
|
aucPrint(_TRANS('PURC_Interface_ClearingPurchased').." {{"..keyText.."}}")--Clearing Purchased stats for
|
|
end
|
|
end
|
|
|
|
function lib.ClearItem(hyperlink, serverKey)
|
|
local linkType,itemID,property,factor = decode(hyperlink)
|
|
if (linkType ~= "item") then return end
|
|
if (factor and factor ~= 0) then property = property.."x"..factor end
|
|
|
|
serverKey = serverKey or GetFaction ()
|
|
|
|
local data = private.GetPriceData(serverKey)
|
|
|
|
local cleareditem = false
|
|
|
|
if data.daily[itemID] then
|
|
local stats = private.UnpackStats (data.daily[itemID])
|
|
if stats[property] then
|
|
stats[property] = nil
|
|
cleareditem = true
|
|
data.daily[itemID] = private.PackStats (stats)
|
|
end
|
|
end
|
|
|
|
if data.means[itemID] then
|
|
local stats = private.UnpackStats (data.means[itemID])
|
|
if stats[property] then
|
|
stats[property] = nil
|
|
cleareditem = true
|
|
data.means[itemID] = private.PackStats (stats)
|
|
end
|
|
end
|
|
|
|
if cleareditem then
|
|
local _, _, keyText = AucAdvanced.SplitServerKey(serverKey)
|
|
aucPrint(_TRANS('PURC_Interface_ClearingPurchasedLink'):format(hyperlink, keyText) )--Stat - Purchased: clearing data for {{%s}} for {{%s}}
|
|
private.ClearCache()
|
|
end
|
|
end
|
|
|
|
function private.GetPriceData(serverKey)
|
|
local data = SPRealmData[serverKey]
|
|
if not data then
|
|
if not AucAdvanced.SplitServerKey(serverKey) then
|
|
error("Invalid serverKey passed to Stat-Purchased")
|
|
end
|
|
data = {means = {}, daily = {created = time()}}
|
|
SPRealmData[serverKey] = data
|
|
end
|
|
return data
|
|
end
|
|
|
|
function private.InitData()
|
|
private.InitData = nil
|
|
|
|
-- Load Data
|
|
private.UpgradeDb()
|
|
SPRealmData = AucAdvancedStatPurchasedData.RealmData
|
|
if not SPRealmData then
|
|
SPRealmData = {} -- dummy table to avoid errors in future events; data will not be saved
|
|
error("Error loading or creating Stat-Purchased database")
|
|
end
|
|
|
|
-- Data maintenance
|
|
for serverKey, data in pairs(SPRealmData) do
|
|
if type(serverKey) ~= "string" or not strmatch(serverKey, ".%-%u%l") then
|
|
-- not a valid serverKey - remove it
|
|
SPRealmData[serverKey] = nil
|
|
else
|
|
-- lots of checks to make sure we ONLY have valid data in this table
|
|
for key, _ in pairs (data) do
|
|
if key ~= "means" and key ~= "daily" then
|
|
data[key] = nil
|
|
end
|
|
end
|
|
if type(data.means) == "table" then
|
|
for id, packed in pairs(data.means) do
|
|
if type(id) ~= "number" or type(packed) ~= "string" then
|
|
data.means[id] = nil
|
|
end
|
|
end
|
|
else
|
|
data.means = {}
|
|
end
|
|
if type(data.daily) == "table" then
|
|
for id, packed in pairs(data.daily) do
|
|
if id ~= "created" and (type(id) ~= "number" or type(packed) ~= "string") then
|
|
data.daily[id] = nil
|
|
end
|
|
end
|
|
if type(data.daily.created) ~= "number" then
|
|
data.daily.created = time()
|
|
end
|
|
else
|
|
data.daily = {created = time()}
|
|
end
|
|
|
|
if time() - data.daily.created > 3600*16 then
|
|
-- This data is more than 16 hours old, we classify this as "yesterday's data"
|
|
private.PushStats(serverKey)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
AucAdvanced.RegisterRevision("$URL: http://svn.norganna.org/auctioneer/branches/5.9/Auc-Stat-Purchased/StatPurchased.lua $", "$Rev: 4840 $")
|