vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[
        Auctioneer Addon for World of Warcraft(tm).
        Version: 3.9.0.1000 (Kangaroo)
        Revision: $Id: AucCore.lua 997 2006-09-12 02:07:48Z mentalpower $

        Auctioneer core functions and variables.
        Functions central to the major operation of Auctioneer.

        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.
]]

--Local function prototypes
local getItemData, getItemDataByID, storeMedianList, loadMedianList, getAuctionPriceItem, saveAuctionPriceItem, getAuctionBuyoutHistory, getAuctionPrices, getItemSignature, getItemCategory, isPlayerMade, getInfo, getSnapshot, getSnapshotFromData, getSnapshotInfo, getSnapshotInfoFromData, saveSnapshot, saveSnapshotInfo, addonLoaded, hookAuctionHouse, lockAndLoad;

--Local variables

-- Counter to count the total number of auctions scanned
local totalAuctionsScannedCount = 0;
local newAuctionsCount = 0;
local oldAuctionsCount = 0;
local defunctAuctionsCount = 0;

-- Auction scan start time counter
local auctionScanStart = 0;

-- Temp table that is copied into AHSnapshotItemPrices only when a scan fully completes
local snapshotItemPrices = {};

--Local constants
local maxAllowedFormatInt = 2000000000; -- numbers much greater than this overflow when using format("%d") --MAX_ALLOWED_FORMAT_INT

-- Auction time constants
--Auctioneer.Core.Constants.TimeLeft.
local timeLeft = {
        Short = 1;              --TIME_LEFT_SHORT
        Medium = 2;             --TIME_LEFT_MEDIUM
        Long = 3;               --TIME_LEFT_LONG
        VeryLong = 4;   --TIME_LEFT_VERY_LONG

        Seconds = {             --TIME_LEFT_SECONDS
                [0] = 0,                -- Could expire any second... the current bid is relatively accurate.
                [1] = 1800,             -- If it disappears within 30 mins of last seing it, it was BO'd
                [2] = 7200,             -- Ditto but for 2 hours.
                [3] = 28800,    -- 8 hours.
                [4] = 86400,    -- 24 hours.
        }
}

-- Item quality constants
--Auctioneer.Core.Constants.Quality
local quality = {
        Legendary       =       5;      --QUALITY_LEGENDARY
        Epic            =       4;      --QUALITY_EPIC
        Rare            =       3;      --QUALITY_RARE
        Uncommon        =       2;      --QUALITY_UNCOMMON
        Common          =       1;      --QUALITY_COMMON
        Poor            =       0;      --QUALITY_POOR
}


-- The maximum number of elements we store in our buyout prices history table
local maxBuyoutHistorySize = 35;

-- Min median buyout price for an item to show up in the list of items below median
local minProfitMargin = 5000; --MIN_PROFIT_MARGIN

-- Min median buyout price for an item to show up in the list of items below median
local defaultCompeteLess = 5; --DEFAULT_COMPETE_LESS

-- Min times an item must be seen before it can show up in the list of items below median
local minBuyoutSeenCount = 5; --MIN_BUYOUT_SEEN_COUNT

-- Max buyout price for an auction to display as a good deal item
local maxBuyoutPrice = 800000; --MAX_BUYOUT_PRICE

-- The default percent less, only find auctions that are at a minimum this percent less than the median
local minPercentLessThanHSP = 60; -- 60% default --MIN_PERCENT_LESS_THAN_HSP

-- The minimum profit/price percent that an auction needs to be displayed as a resellable auction
local minProfitPricePercent = 30; -- 30% default --MIN_PROFIT_PRICE_PERCENT

-- The minimum percent of bids placed on an item to be considered an "in-demand" enough item to be traded, this is only applied to Weapons and Armor and Recipies
local minBidPercent = 10; --MIN_BID_PERCENT

-- categories that the brokers and HSP look at the bid data for
--  1 = weapon
--  2 = armor
--  3 = container
--  4 = dissipatable
--  5 = tradeskillitems
--  6 = projectile
--  7 = quiver
--  8 = recipe
--  9 = reagence
-- 10 = miscellaneous
local bidBasedCategories = {[1]=true, [2]=true, [8]=true, [10]=true} --BID_BASED_CATEGORIES

--[[ SavedVariables --]]
AuctionConfig = {};                     --Table that stores config settings
Auction_DoneItems = {};         --Table to keep a record of auction items that have been scanned
AuctionBackup = {}                      --Table to backup old data which can't be converted at once
AuctionConfig.version = 30600;

-- Table to store our cached HSP values (since they're expensive to calculate)
Auctioneer_HSPCache = {};
Auctioneer_Lowests = {};

-- Default filter configuration
local filterDefaults = { --Auctioneer_FilterDefaults
        ["all"]                                         =       "on",
        ["autofill"]                            =       "on",
        ["embed"]                                       =       "off",
        ["also"]                                        =       "off",
        ["auction-click"]                       =       "on",
        ["show-link"]                           =       "off",
        ["show-embed-blankline"]        =       "off",
        ["show-verbose"]                        =       "on",
        ["show-stats"]                          =       "on",
        ["show-average"]                        =       "on",
        ["show-median"]                         =       "on",
        ["show-suggest"]                        =       "on",
        ["show-warning"]                        =       "on",
        ["scan-class1"]                         =       "on",
        ["scan-class2"]                         =       "on",
        ["scan-class3"]                         =       "on",
        ["scan-class4"]                         =       "on",
        ["scan-class5"]                         =       "on",
        ["scan-class6"]                         =       "on",
        ["scan-class7"]                         =       "on",
        ["scan-class8"]                         =       "on",
        ["scan-class9"]                         =       "on",
        ["scan-class10"]                        =       "on",
        ["warn-color"]                          =       "on",
        ["finish-sound"]                        =       "on",
        ["printframe"]                          =       1,
        ["last-auction-duration"]       =       1440,
        ["auction-duration"]            =       3,
        ["protect-window"]                      =       1,
        ["finish"]                                      =       0,
        ["pct-bidmarkdown"]                     =       20,
        ["pct-markup"]                          =       300,
        ["pct-maxless"]                         =       30,
        ["pct-nocomp"]                          =       2,
        ["pct-underlow"]                        =       5,
        ["pct-undermkt"]                        =       20,
        ["locale"]                                      =       "default",

        --AskPrice related commands
        ["askprice"]                            =       "on",
        ["askprice-vendor"]                     =       "off",
        ["askprice-guild"]                      =       "off",
        ["askprice-party"]                      =       "off",
        ["askprice-smart"]                      =       "off",
        ["askprice-trigger"]            =       "?",
        ["askprice-ad"]                         =       "on",
        ["askprice-whispers"]           =       "on",
        ["askprice-word1"]                      =       _AUCT('CmdAskPriceSmartWord1', "enUS"), --Initially set these two filters to match the stock english custom words
        ["askprice-word2"]                      =       _AUCT('CmdAskPriceSmartWord2', "enUS"),

        -- Auction House tab UI
        ["bid-limit"]                           =       1,
        ["update-price"]                        =       "off",
}

function getItemData(itemKey)
        local itemID, itemRand, enchant = Auctioneer.Util.BreakItemKey(itemKey);
        if (Informant) then
                return Informant.GetItem(itemID);
        end
        return nil;
end

function getItemDataByID(itemID)
        if (Informant) then
                return Informant.GetItem(itemID);
        end
        return nil;
end

function storeMedianList(list)
        local hist = "";
        local function GrowList(last, n)
                if (n == 1) then
                        if (hist == "") then hist = last;
                        else hist = string.format("%s:%d", hist, last); end
                elseif (n ~= 0) then
                        if (hist == "") then hist = string.format("%dx%d", last, n);
                        else hist = string.format("%s:%dx%d", hist, last, n); end
                end
        end
        local n = 0;
        local last = 0;
        for pos, hPrice in pairs(list) do
                if (pos == 1) then
                        last = hPrice;
                elseif (hPrice ~= last) then
                        GrowList(last, n)
                        last = hPrice;
                        n = 0;
                end
                n = n + 1
        end
        GrowList(last, n)
        return hist;
end

function loadMedianList(str)
        local splut = {};
        if (str) then
                for x,c in string.gfind(str, '([^%:]*)(%:?)') do
                        local _,_,y,n = string.find(x, '(%d*)x(%d*)')
                        if (y == nil) then
                                table.insert(splut, tonumber(x));
                        else
                                for i = 1,n do
                                        table.insert(splut, tonumber(y));
                                end
                        end
                        if (c == '') then break end
                end
        end
        return splut;
end

-- Returns an AuctionConfig.data item from the table based on an item name
function getAuctionPriceItem(itemKey, from)
        local serverFaction;
        local auctionPriceItem, data,info;

        if (from ~= nil) then serverFaction = from;
        else serverFaction = Auctioneer.Util.GetAuctionKey(); end;

        EnhTooltip.DebugPrint("Getting data from/for", serverFaction, itemKey);
        if (AuctionConfig.data == nil) then AuctionConfig.data = {}; end
        if (AuctionConfig.info == nil) then AuctionConfig.info = {}; end
        if (AuctionConfig.data[serverFaction] == nil) then
                EnhTooltip.DebugPrint("Data from serverfaction is nil");
                AuctionConfig.data[serverFaction] = {};
        else
                data = AuctionConfig.data[serverFaction][itemKey];
                info = AuctionConfig.info[itemKey];
        end

        auctionPriceItem = {};
        if (data) then
                local dataItem = Auctioneer.Util.Split(data, "|");
                auctionPriceItem.data = dataItem[1];
                auctionPriceItem.buyoutPricesHistoryList = loadMedianList(dataItem[2]);
        end
        if (info) then
                local infoItem = Auctioneer.Util.Split(info, "|");
                auctionPriceItem.category = infoItem[1];
                auctionPriceItem.name = infoItem[2];
        end

        local playerMade, reqSkill, reqLevel = isPlayerMade(itemKey);
        auctionPriceItem.playerMade = playerMade;
        auctionPriceItem.reqSkill = reqSkill;
        auctionPriceItem.reqLevel = reqLevel;

        return auctionPriceItem;
end

function saveAuctionPriceItem(auctKey, itemKey, iData)
        if (not auctKey) then return end
        if (not itemKey) then return end
        if (not iData) then return end

        if (not AuctionConfig.info) then AuctionConfig.info = {}; end
        if (not AuctionConfig.data) then AuctionConfig.data = {}; end
        if (not AuctionConfig.data[auctKey]) then AuctionConfig.data[auctKey] = {}; end

        local hist = storeMedianList(iData.buyoutPricesHistoryList);

        AuctionConfig.data[auctKey][itemKey] = string.format("%s|%s", iData.data, hist);
        AuctionConfig.info[itemKey] = string.format("%s|%s", iData.category, iData.name);
        Auctioneer_Lowests = nil;

        -- save median to the savedvariablesfile
        Auctioneer.Storage.SetHistMed(auctKey, itemKey, Auctioneer.Statistic.GetMedian(iData.buyoutPricesHistoryList))
end

-- Returns the auction buyout history for this item
function getAuctionBuyoutHistory(itemKey, auctKey)
        local auctionItem = getAuctionPriceItem(itemKey, auctKey);
        local buyoutHistory = {};
        if (auctionItem) then
                buyoutHistory = auctionItem.buyoutPricesHistoryList;
        end
        return buyoutHistory;
end

-- Returns the parsed auction price data
function getAuctionPrices(priceData)
        if (not priceData) then return 0,0,0,0,0,0,0 end
        local i,j, count,minCount,minPrice,bidCount,bidPrice,buyCount,buyPrice = string.find(priceData, "^(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)");
        return Auctioneer.Util.NullSafe(count),Auctioneer.Util.NullSafe(minCount),Auctioneer.Util.NullSafe(minPrice),Auctioneer.Util.NullSafe(bidCount),Auctioneer.Util.NullSafe(bidPrice),Auctioneer.Util.NullSafe(buyCount),Auctioneer.Util.NullSafe(buyPrice);
end

-- Parse the data from the auction signature
function getItemSignature(sigData)
        if (not sigData) then return nil end
        for id,rprop,enchant,name,count,min,buyout,uniq in string.gfind(sigData, "(%d+):(%d+):(%d+):(.-):(%d+):(.-):(%d+):(.+)") do
                if (name == nil) then name = ""; end
                return tonumber(id),tonumber(rprop),tonumber(enchant),name,tonumber(count),tonumber(min),tonumber(buyout),tonumber(uniq);
        end
        return nil;
end

-- Returns the category i.e. 1, 2 for an item
function getItemCategory(itemKey)
        local category;
        local auctionItem = getAuctionPriceItem(itemKey);
        if auctionItem then
                category = auctionItem.category;
        end

        return category;
end

function isPlayerMade(itemKey, itemData)
        if (not itemData) and (Informant) then
                local itemID, itemRand, enchant = Auctioneer.Util.BreakItemKey(itemKey)
                itemData = Informant.GetItem(itemID)
        end

        local reqSkill = 0
        local reqLevel = 0
        if (itemData) then
                reqSkill = itemData.reqSkill
                reqLevel = itemData.reqLevel
        end
        return (reqSkill ~= 0), reqSkill, reqLevel
end

function getInfo(itemKey)
        if (not AuctionConfig.info[itemKey]) then return {}; end
        local info = AuctionConfig.info[itemKey];
        local infosplit = Auctioneer.Util.Split(info, "|");
        local cat = tonumber(infosplit[1]);
        local name = infosplit[2];
        return {
                category = cat,
                name = name,
        };
end

function getSnapshot(auctKey, catID, auctSig)
        if (not catID) then catID = 0 end

        if (not AuctionConfig.snap) then
                AuctionConfig.snap = {};
        end
        if (not AuctionConfig.snap[auctKey]) then
                AuctionConfig.snap[auctKey] = {};
        end
        if (not AuctionConfig.snap[auctKey][catID]) then
                AuctionConfig.snap[auctKey][catID] = {};
        end
        if (not AuctionConfig.snap[auctKey][catID][auctSig]) then
                return nil;
        end

        local snap = AuctionConfig.snap[auctKey][catID][auctSig];
        return getSnapshotFromData(snap);
end

function getSnapshotFromData(snap)
        if (not snap) then return nil end

        for dirty,bid,level,quality,left,fseen,last,link,owner in string.gfind(snap, "(%d+);(%d+);(%d+);(%d+);(%d+);(%d+);(%d+);([^;]+);(.+)") do
                return {
                        bidamount = tonumber(bid),
                        owner = owner,
                        dirty = dirty,
                        lastSeenTime = tonumber(last),
                        itemLink = link,
                        category = cat,
                        initialSeenTime = tonumber(fseen),
                        level = level,
                        timeLeft = tonumber(left),
                        quality = quality,
                };
        end
        return nil;
end

function getSnapshotInfo(auctKey, itemKey)
        if (not AuctionConfig.sbuy) then AuctionConfig.sbuy = {}; end
        if (not AuctionConfig.sbuy[auctKey]) then AuctionConfig.sbuy[auctKey] = {}; end
        if (not AuctionConfig.sbuy[auctKey][itemKey]) then return nil; end

        local buy = AuctionConfig.sbuy[auctKey][itemKey];
        return getSnapshotInfoFromData(buy);
end

function getSnapshotInfoFromData(buy)
        local buysplit = loadMedianList(buy);
        return {
                buyoutPrices = buysplit,
        };
end

function saveSnapshot(auctKey, cat, sig, iData)
        local bid = iData.bidamount;
        local owner = iData.owner;
        local dirty = iData.dirty;
        local last = iData.lastSeenTime;
        local link = iData.itemLink;
        local fseen = iData.initialSeenTime;
        local level = iData.level;
        local left = iData.timeLeft;
        local qual = iData.quality;

        if (not cat) then cat = 0 end

        if (not AuctionConfig.snap) then
                AuctionConfig.snap = {};
        end
        if (not AuctionConfig.snap[auctKey]) then
                AuctionConfig.snap[auctKey] = {};
        end
        if (not AuctionConfig.snap[auctKey][cat]) then
                AuctionConfig.snap[auctKey][cat] = {};
        end
        if (dirty~=nil and bid~=nil and level~=nil and qual~=nil and left~=nil and fseen~=nil and last~=nil and link~=nil and owner~=nil) then
                local saveData = string.format("%d;%d;%d;%d;%d;%d;%d;%s;%s", dirty, bid, level, qual, left, fseen, last, link, owner);
                EnhTooltip.DebugPrint("Saving", auctKey, cat, sig, "as", saveData);
                AuctionConfig.snap[auctKey][cat][sig] = saveData;
                local itemKey = Auctioneer.Util.GetKeyFromSig(sig);
                Auctioneer_Lowests = nil;
                Auctioneer.Storage.SetSnapMed(auctKey, itemKey, nil)
        else
                EnhTooltip.DebugPrint("Not saving", auctKey, cat, sig, "because", dirty, bid, level, qual, left, fseen, last, link, owner);
        end
end

function saveSnapshotInfo(auctKey, itemKey, iData)
        AuctionConfig.sbuy[auctKey][itemKey] = storeMedianList(iData.buyoutPrices);
        Auctioneer_Lowests = nil;

        Auctioneer.Storage.SetSnapMed(auctKey, itemKey, Auctioneer.Statistic.GetMedian(iData.buyoutPrices))
end


function addonLoaded()
        -- Load the category and subcategory id's
        Auctioneer.Util.LoadCategories();

        Auctioneer.Util.SetFilterDefaults();

        if (not AuctionConfig.version) then AuctionConfig.version = 30000; end
        if (AuctionConfig.version < 30600) then
                StaticPopupDialogs["CONVERT_AUCTIONEER"] = {
                        text = _AUCT('MesgConvert'),
                        button1 = _AUCT('MesgConvertYes'),
                        button2 = _AUCT('MesgConvertNo'),
                        OnAccept = function()
                                Auctioneer.Convert.Convert();
                        end,
                        OnCancel = function()
                                Auctioneer.Util.ChatPrint(_AUCT('MesgNotconverting'));
                        end,
                        timeout = 0,
                        whileDead = 1,
                        exclusive = 1
                };
                StaticPopup_Show("CONVERT_AUCTIONEER", "","");
        end

        lockAndLoad();
end

-- This is the old (local) hookAuctionHouse() function
function hookAuctionHouse()
        Stubby.RegisterFunctionHook("AuctionFrame_Show", 200, Auctioneer.Scanner.AuctHouseShow);
        Stubby.RegisterEventHook("NEW_AUCTION_UPDATE", "Auctioneer", Auctioneer.Scanner.NewAuction);
        Stubby.RegisterEventHook("AUCTION_HOUSE_CLOSED", "Auctioneer", Auctioneer.Scanner.AuctHouseClose);
        Stubby.RegisterEventHook("AUCTION_ITEM_LIST_UPDATE", "Auctioneer", Auctioneer.Scanner.AuctHouseUpdate);

        Stubby.RegisterFunctionHook("Auctioneer.Event.ScanAuction", 200, Auctioneer.Scanner.AuctionEntryHook);
        Stubby.RegisterFunctionHook("Auctioneer.Event.StartAuctionScan", 200, Auctioneer.Scanner.AuctionStartHook);
        Stubby.RegisterFunctionHook("Auctioneer.Event.FinishedAuctionScan", 200, Auctioneer.Scanner.FinishedAuctionScanHook);

        Stubby.RegisterFunctionHook("StartAuction", 200, Auctioneer.Scanner.StartAuction)
        Stubby.RegisterFunctionHook("PlaceAuctionBid", 200, Auctioneer.Scanner.PlaceAuctionBid)
        Stubby.RegisterFunctionHook("FilterButton_SetType", 200, Auctioneer.Scanner.FilterButtonSetType)
        Stubby.RegisterFunctionHook("QueryAuctionItems", 200, Auctioneer.Scanning.QueryAuctionItemsHook)
        Stubby.RegisterFunctionHook("AuctionsRadioButton_OnClick", 200, Auctioneer.Scanner.OnChangeAuctionDuration);
        Stubby.RegisterFunctionHook("AuctionFrameFilters_UpdateClasses", 200, Auctioneer.Scanner.AuctionFrameFiltersUpdateClasses);

end

function lockAndLoad()
        Stubby.RegisterFunctionHook("AuctionFrame_LoadUI", 200, Auctioneer.Scanner.ConfigureAH);
        Stubby.RegisterFunctionHook("ContainerFrameItemButton_OnClick", -200, Auctioneer.Util.ContainerFrameItemButtonOnClick);

        SLASH_AUCTIONEER1 = "/auctioneer";
        SLASH_AUCTIONEER2 = "/auction";
        SLASH_AUCTIONEER3 = "/auc";
        SlashCmdList["AUCTIONEER"] = Auctioneer.Command.MainHandler;

        -- Rearranges elements in the AH window.
        Auctioneer.Scanner.ConfigureAH();

        --GUI Registration code added by MentalPower
        Auctioneer.Command.Register();

        --Init AskPrice
        Auctioneer.AskPrice.Init();

        Auctioneer.Util.ChatPrint(string.format(_AUCT('FrmtWelcome'), Auctioneer.Version), 0.8, 0.8, 0.2);

        collectgarbage() --Cleanup after that massive mem spike
end

Auctioneer.Core = {
        Variables = {},
        Constants = {},
        GetItemData = getItemData,
        GetItemDataByID = getItemDataByID,
        StoreMedianList = storeMedianList,
        LoadMedianList = loadMedianList,
        GetAuctionPriceItem = getAuctionPriceItem,
        SaveAuctionPriceItem = saveAuctionPriceItem,
        GetAuctionBuyoutHistory = getAuctionBuyoutHistory,
        GetAuctionPrices = getAuctionPrices,
        GetItemSignature = getItemSignature,
        GetItemCategory = getItemCategory,
        IsPlayerMade = isPlayerMade,
        GetInfo = getInfo,
        GetSnapshot = getSnapshot,
        GetSnapshotFromData = getSnapshotFromData,
        GetSnapshotInfo = getSnapshotInfo,
        GetSnapshotInfoFromData = getSnapshotInfoFromData,
        SaveSnapshot = saveSnapshot,
        SaveSnapshotInfo = saveSnapshotInfo,
        AddonLoaded = addonLoaded,
        HookAuctionHouse = hookAuctionHouse,
        LockAndLoad = lockAndLoad,
}

Auctioneer.Core.Variables = {
        TotalAuctionsScannedCount = totalAuctionsScannedCount,
        NewAuctionsCount = newAuctionsCount,
        OldAuctionsCount = oldAuctionsCount,
        DefunctAuctionsCount = defunctAuctionsCount,
        AuctionScanStart = auctionScanStart,
        SnapshotItemPrices = snapshotItemPrices,
}

Auctioneer.Core.Constants = {
        MaxAllowedFormatInt = maxAllowedFormatInt,
        TimeLeft = timeLeft,
        Quality = quality,
        MaxBuyoutHistorySize = maxBuyoutHistorySize,
        MinProfitMargin = minProfitMargin,
        DefaultCompeteLess = defaultCompeteLess,
        MinBuyoutSeenCount = minBuyoutSeenCount,
        MaxBuyoutPrice = maxBuyoutPrice,
        MinPercentLessThanHSP = minPercentLessThanHSP,
        MinProfitPricePercent = minProfitPricePercent,
        MinBidPercent = minBidPercent,
        BidBasedCategories = bidBasedCategories,
        FilterDefaults = filterDefaults,
}