--[[ Auctioneer Addon for World of Warcraft(tm). Version: 3.9.0.1000 (Kangaroo) Revision: $Id: AucUtil.lua 980 2006-08-31 05:29:48Z mentalpower $ Auctioneer utility functions. Functions to maniuplate items keys, signatures etc 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 getTimeLeftString, getSecondsLeftString, unpackSeconds, getGSC, getTextGSC, nilSafeString, colorTextWhite, getWarnColor, nullSafe, sanifyAHSnapshot, getAuctionKey, getOppositeKey, getNeutralKey, getHomeKey, isValidAlso, breakItemKey, split, findClass, getCatName, getCatNumberByName, getCatForKey, getKeyFromSig, getCatForSig, getItemLinks, getItems, getItemHyperlinks, loadCategories, loadCategoryClasses, loadCategorySubClasses, chatPrint, setFilterDefaults, protectAuctionFrame, priceForOne, round, delocalizeFilterVal, localizeFilterVal, getLocalizedFilterVal, delocalizeCommand, localizeCommand, findEmptySlot, containerFrameItemButtonOnClick -- return the string representation of the given timeLeft constant function getTimeLeftString(timeLeft) local timeLeftString = ""; if timeLeft == Auctioneer.Core.Constants.TimeLeft.Short then timeLeftString = _AUCT('TimeShort'); elseif timeLeft == Auctioneer.Core.Constants.TimeLeft.Medium then timeLeftString = _AUCT('TimeMed'); elseif timeLeft == Auctioneer.Core.Constants.TimeLeft.Long then timeLeftString = _AUCT('TimeLong'); elseif timeLeft == Auctioneer.Core.Constants.TimeLeft.VeryLong then timeLeftString = _AUCT('TimeVlong'); end return timeLeftString; end function getSecondsLeftString(secondsLeft) local timeLeft = nil; for i = table.getn(Auctioneer.Core.Constants.TimeLeft.Seconds), 1, -1 do if (secondsLeft >= Auctioneer.Core.Constants.TimeLeft.Seconds[i]) then timeLeft = i; break end end return getTimeLeftString(timeLeft); end function unpackSeconds(seconds) seconds = tonumber(seconds) if (not seconds) then return end local weeks local days local hours local minutes seconds = math.floor(seconds) if (seconds > 604800) then weeks = math.floor(seconds / 604800) seconds = math.floor(seconds - (weeks * 604800)) end if (seconds > 86400) then days = math.floor(seconds / 86400) seconds = math.floor(seconds - (days * 86400)) end if (seconds > 3600) then hours = math.floor(seconds / 3600) seconds = math.floor(seconds - (hours * 3600)) end if (seconds >= 60) then minutes = math.floor(seconds / 60) seconds = math.floor(seconds - (minutes * 60)) end return (weeks or 0), (days or 0), (hours or 0), (minutes or 0), (seconds or 0) end function getGSC(money) local g,s,c = EnhTooltip.GetGSC(money); return g,s,c; end function getTextGSC(money) return EnhTooltip.GetGSC(money); end -- return an empty string if str is nil function nilSafeString(str) return str or ""; end function colorTextWhite(text) if (not text) then text = ""; end local COLORING_START = "|cff%s%s|r"; local WHITE_COLOR = "e6e6e6"; return string.format(COLORING_START, WHITE_COLOR, ""..text); end function getWarnColor(warn) --Make "warn" a required parameter and verify that its a string if (not (type(warn) == "string")) then return nil end local cHex, cRed, cGreen, cBlue; if (Auctioneer.Command.GetFilter('warn-color')) then local FrmtWarnAbovemkt, FrmtWarnUndercut, FrmtWarnNocomp, FrmtWarnAbovemkt, FrmtWarnMarkup, FrmtWarnUser, FrmtWarnNodata, FrmtWarnMyprice FrmtWarnToolow = _AUCT('FrmtWarnToolow'); FrmtWarnNocomp = _AUCT('FrmtWarnNocomp'); FrmtWarnAbovemkt = _AUCT('FrmtWarnAbovemkt'); FrmtWarnUser = _AUCT('FrmtWarnUser'); FrmtWarnNodata = _AUCT('FrmtWarnNodata'); FrmtWarnMyprice = _AUCT('FrmtWarnMyprice'); FrmtWarnUndercut = string.format(_AUCT('FrmtWarnUndercut'), tonumber(Auctioneer.Command.GetFilterVal('pct-underlow'))); FrmtWarnMarkup = string.format(_AUCT('FrmtWarnMarkup'), tonumber(Auctioneer.Command.GetFilterVal('pct-markup'))); if (warn == FrmtWarnToolow) then --Color Red cHex = "ffff0000"; cRed = 1.0; cGreen = 0.0; cBlue = 0.0; elseif (warn == FrmtWarnUndercut) then --Color Yellow cHex = "ffffff00"; cRed = 1.0; cGreen = 1.0; cBlue = 0.0; elseif ((warn == FrmtWarnNocomp) or (warn == FrmtWarnAbovemkt)) then --Color Green cHex = "ff00ff00"; cRed = 0.0; cGreen = 1.0; cBlue = 0.0; elseif ((warn == FrmtWarnMarkup) or (warn == FrmtWarnUser) or (warn == FrmtWarnNodata) or (warn == FrmtWarnMyprice)) then --Color Gray cHex = "ff999999"; cRed = 0.6; cGreen = 0.6; cBlue = 0.6; end else --Color Orange cHex = "ffe66600"; cRed = 0.9; cGreen = 0.4; cBlue = 0.0; end return cHex, cRed, cGreen, cBlue end -- Used to convert variables that should be numbers but are nil to 0 function nullSafe(val) return tonumber(val) or 0; end -- Returns the current faction's auction signature, depending on location function getAuctionKey() local serverName = GetCVar("realmName"); local currentZone = GetMinimapZoneText(); local factionGroup; --Added the ability to record Neutral AH auctions in its own tables. if ((currentZone == "Gadgetzan") or (currentZone == "Everlook") or (currentZone == "Booty Bay")) then factionGroup = "Neutral" else factionGroup = UnitFactionGroup("player"); end return serverName.."-"..factionGroup; end -- Returns the current faction's opposing faction's auction signature function getOppositeKey() local serverName = GetCVar("realmName"); local factionGroup = UnitFactionGroup("player"); if (factionGroup == "Alliance") then factionGroup="Horde"; else factionGroup="Alliance"; end return serverName.."-"..factionGroup; end -- Returns the current server's neutral auction signature function getNeutralKey() local serverName = GetCVar("realmName"); return serverName.."-Neutral"; end -- Returns the current faction's auction signature function getHomeKey() local serverName = GetCVar("realmName"); local factionGroup = UnitFactionGroup("player"); return serverName.."-"..factionGroup; end -- function returns true, if the given parameter is a valid option for the also command, false otherwise function isValidAlso(also) if (type(also) ~= "string") then return false end if ((also == 'opposite') or (also == 'off') or (also == 'neutral') or (also == 'home')) then return true -- allow special keywords end -- check if string matches: "[realm]-[faction]" local s, e, r, f = string.find(also, "^(.+)-(.+)$") if (s == nil) then return false -- invalid string end -- check if faction = "Horde" or "Alliance" if (f == 'Horde') or (f == 'Alliance')or (f == 'Neutral') then return true end return true end -- Given an item key, breaks it into its itemID, randomProperty and enchantProperty function breakItemKey(itemKey) local i,j, itemID, randomProp, enchant = string.find(itemKey, "(%d+):(%d+):(%d+)"); return tonumber(itemID or 0), tonumber(randomProp or 0), tonumber(enchant or 0); end function split(str, at) local splut = {}; if (type(str) ~= "string") then return nil end if (not str) then str = "" end if (not at) then table.insert(splut, str) else for n, c in string.gfind(str, '([^%'..at..']*)(%'..at..'?)') do table.insert(splut, n); if (c == '') then break end end end return splut; end function findClass(cName, sName) if (AuctionConfig and AuctionConfig.classes) then for class, cData in pairs(AuctionConfig.classes) do if (cData.name == cName) then if (sName == nil) then return class, 0; end for sClass, sData in pairs(cData) do if (sClass ~= "name") and (sData == sName) then return class, sClass; end end return class, 0; end end end return 0,0; end function getCatName(number) if (number == 0) then return "" end; if (AuctionConfig.classes[number]) then return AuctionConfig.classes[number].name; end return nil; end function getCatNumberByName(name) if (not name) then return 0 end if (AuctionConfig and AuctionConfig.classes) then for cat, class in pairs(AuctionConfig.classes) do if (name == class.name) then return cat; end end end return 0; end function getCatForKey(itemKey) local info = Auctioneer.Core.GetInfo(itemKey); return info.category; end function getKeyFromSig(auctSig) local id, rprop, enchant = Auctioneer.Core.GetItemSignature(auctSig); return id..":"..rprop..":"..enchant; end function getCatForSig(auctSig) local itemKey = getKeyFromSig(auctSig); return getCatForKey(itemKey); end function getItemLinks(str) if (not (type(str) == "string")) then return end local itemList = {}; for link, item in string.gfind(str, "|Hitem:([^|]+)|h[[]([^]]+)[]]|h") do table.insert(itemList, item.." = "..link) end return itemList; end function getItems(str) if (not (type(str) == "string")) then return end local itemList = {}; local itemKey; for itemID, randomProp, enchant, uniqID in string.gfind(str, "|Hitem:(%d+):(%d+):(%d+):(%d+)|h") do itemKey = itemID..":"..randomProp..":"..enchant; table.insert(itemList, itemKey) end return itemList; end --Many thanks to the guys at irc://irc.datavertex.com/cosmostesters for their help in creating this function function getItemHyperlinks(str) if (not (type(str) == "string")) then return end local itemList = {}; for color, item, name in string.gfind(str, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r") do table.insert(itemList, "|c"..color.."|Hitem:"..item.."|h["..name.."]|h|r") end return itemList; end function loadCategories() if (not AuctionConfig.classes) then AuctionConfig.classes = {} end loadCategoryClasses(GetAuctionItemClasses()); end function loadCategoryClasses(...) for c=1, arg.n, 1 do AuctionConfig.classes[c] = {}; AuctionConfig.classes[c].name = arg[c]; loadCategorySubClasses(c, GetAuctionItemSubClasses(c)); end end function loadCategorySubClasses(c, ...) for s=1, arg.n, 1 do AuctionConfig.classes[c][s] = arg[s]; end end function chatPrint(text, cRed, cGreen, cBlue, cAlpha, holdTime) local frameIndex = Auctioneer.Command.GetFrameIndex(); if (cRed and cGreen and cBlue) then if getglobal("ChatFrame"..frameIndex) then getglobal("ChatFrame"..frameIndex):AddMessage(text, cRed, cGreen, cBlue, cAlpha, holdTime); elseif (DEFAULT_CHAT_FRAME) then DEFAULT_CHAT_FRAME:AddMessage(text, cRed, cGreen, cBlue, cAlpha, holdTime); end else if getglobal("ChatFrame"..frameIndex) then getglobal("ChatFrame"..frameIndex):AddMessage(text, 0.0, 1.0, 0.25); elseif (DEFAULT_CHAT_FRAME) then DEFAULT_CHAT_FRAME:AddMessage(text, 0.0, 1.0, 0.25); end end end function setFilterDefaults() if (not AuctionConfig.filters) then AuctionConfig.filters = {}; end for k,v in ipairs(Auctioneer.Core.Constants.FilterDefaults) do if (AuctionConfig.filters[k] == nil) then AuctionConfig.filters[k] = v; end end end -- Pass true to protect the Auction Frame from being undesireably closed, not true to disable this function protectAuctionFrame(enable) --Make sure we have an AuctionFrame before doing anything if (AuctionFrame) then --Handle enabling of protection if (enable and not Auctioneer_ProtectionEnabled and AuctionFrame:IsShown()) then --Remember that we are now protecting the frame Auctioneer_ProtectionEnabled = true; --If the frame is the current doublewide frame, then clear the doublewide if ( GetDoublewideFrame() == AuctionFrame ) then SetDoublewideFrame(nil) end --Remove the frame from the UI frame handling system UIPanelWindows["AuctionFrame"] = nil --If mobile frames is around, then remove AuctionFrame from Mobile Frames handling system if (MobileFrames_UIPanelWindowBackup) then MobileFrames_UIPanelWindowBackup.AuctionFrame = nil; end if (MobileFrames_UIPanelsVisible) then MobileFrames_UIPanelsVisible.AuctionFrame = nil; end --Hook the function to show the WorldMap, WorldMap has internal code that forces all these frames to close --so for it, we have to prevent it from showing at all if (not Auctioneer_ToggleWorldMap) then Auctioneer_ToggleWorldMap = ToggleWorldMap; end ToggleWorldMap = function () if ( ( not Auctioneer_ProtectionEnabled ) or ( not ( AuctionFrame and AuctionFrame:IsVisible() ) ) ) then Auctioneer_ToggleWorldMap(); else UIErrorsFrame:AddMessage(_AUCT('GuiNoWorldMap'), 0, 1, 0, 1.0, UIERRORS_HOLD_TIME) end end elseif (Auctioneer_ProtectionEnabled) then --Handle disabling of protection Auctioneer_ProtectionEnabled = nil; --If Mobile Frames is around, then put the frame back under its control if it is proper to do so if ( MobileFrames_UIPanelWindowBackup and MobileFrames_MasterEnableList and MobileFrames_MasterEnableList["AuctionFrame"] ) then MobileFrames_UIPanelWindowBackup.AuctionFrame = { area = "doublewide", pushable = 0 }; if ( MobileFrames_UIPanelsVisible and AuctionFrame:IsVisible() ) then MobileFrames_UIPanelsVisible.AuctionFrame = 0; end else --Put the frame back into the UI frame handling system UIPanelWindows["AuctionFrame"] = { area = "doublewide", pushable = 0 }; if ( AuctionFrame:IsVisible() ) then SetDoublewideFrame(AuctionFrame) end end end end end function priceForOne(price, count) price = nullSafe(price) count = math.max(nullSafe(count), 1) return math.ceil(price / count) end function round(x) local y = math.floor(x); if (x - y >= 0.5) then return y + 1; end return y; end ------------------------------------------------------------------------------- -- Localization functions ------------------------------------------------------------------------------- Auctioneer.Command.CommandMap = nil; Auctioneer.Command.CommandMapRev = nil; function delocalizeFilterVal(value) if (value == _AUCT('CmdOn')) then return 'on'; elseif (value == _AUCT('CmdOff')) then return 'off'; elseif (value == _AUCT('CmdDefault')) then return 'default'; elseif (value == _AUCT('CmdToggle')) then return 'toggle'; else return value; end end function localizeFilterVal(value) local result if (value == 'on') then result = _AUCT('CmdOn'); elseif (value == 'off') then result = _AUCT('CmdOff'); elseif (value == 'default') then result = _AUCT('CmdDefault'); elseif (value == 'toggle') then result = _AUCT('CmdToggle'); end if (result) then return result; else return value; end end function getLocalizedFilterVal(key) return localizeFilterVal(Auctioneer.Command.GetFilterVal(key)) end -- Turns a localized slash command into the generic English version of the command function delocalizeCommand(cmd) if (not Auctioneer.Command.CommandMap) then Auctioneer.Command.BuildCommandMap();end local result = Auctioneer.Command.CommandMap[cmd]; if (result) then return result; else return cmd; end end -- Translate a generic English slash command to the localized version, if available function localizeCommand(cmd) if (not Auctioneer.Command.CommandMapRev) then Auctioneer.Command.BuildCommandMap(); end local result = Auctioneer.Command.CommandMapRev[cmd]; if (result) then return result; else return cmd; end end ------------------------------------------------------------------------------- -- Inventory modifying functions ------------------------------------------------------------------------------- function findEmptySlot() local name, i for bag = 0, 4 do name = GetBagName(bag) i = string.find(name, '(Quiver|Ammo|Bandolier)') if not i then for slot = 1, GetContainerNumSlots(bag),1 do if not (GetContainerItemInfo(bag,slot)) then return bag, slot; end end end end end function containerFrameItemButtonOnClick(hookParams, returnValue, button, ignoreShift) --Auctioneer_ContainerFrameItemButton_OnClick local bag = this:GetParent():GetID() local slot = this:GetID() local texture, count, noSplit = GetContainerItemInfo(bag, slot) local link = GetContainerItemLink(bag, slot) if (count and count > 1 and not noSplit) then if (button == "RightButton") and (IsControlKeyDown()) then local splitCount = math.floor(count / 2) local emptyBag, emptySlot = findEmptySlot() if (emptyBag) then SplitContainerItem(bag, slot, splitCount) PickupContainerItem(emptyBag, emptySlot) else chatPrint("Can't split, all bags are full") end return "abort"; end end if (AuctionFrame and AuctionFrame:IsVisible()) then if (link) then if (button == "RightButton") and (IsAltKeyDown()) then AuctionFrameTab_OnClick(1) local itemID = EnhTooltip.BreakLink(link) if (itemID) then local itemName = GetItemInfo(tostring(itemID)) if (itemName) then BrowseName:SetText(itemName) BrowseMinLevel:SetText("") BrowseMaxLevel:SetText("") AuctionFrameBrowse.selectedInvtype = nil AuctionFrameBrowse.selectedInvtypeIndex = nil AuctionFrameBrowse.selectedClass = nil AuctionFrameBrowse.selectedClassIndex = nil AuctionFrameBrowse.selectedSubclass = nil AuctionFrameBrowse.selectedSubclassIndex = nil AuctionFrameFilters_Update() IsUsableCheckButton:SetChecked(0) UIDropDownMenu_SetSelectedValue(BrowseDropDown, -1) AuctionFrameBrowse_Search() BrowseNoResultsText:SetText(BROWSE_NO_RESULTS) end end return "abort"; end end end if (not CursorHasItem() and AuctionFrameAuctions and AuctionFrameAuctions:IsVisible() and IsAltKeyDown()) then PickupContainerItem(bag, slot) if (CursorHasItem() and Auctioneer.Command.GetFilter('auction-click')) then ClickAuctionSellItemButton() AuctionsFrameAuctions_ValidateAuction() local start = MoneyInputFrame_GetCopper(StartPrice) local buy = MoneyInputFrame_GetCopper(BuyoutPrice) local duration = AuctionFrameAuctions.duration local warn = AuctionInfoWarnText:GetText() if (AuctionsCreateAuctionButton:IsEnabled() and IsShiftKeyDown()) then local cHex, cRed, cGreen, cBlue = getWarnColor(warn) warn = ("|c"..cHex..warn.."|r") StartAuction(start, buy, duration); chatPrint(string.format(_AUCT('FrmtAutostart'), link, EnhTooltip.GetTextGSC(start), EnhTooltip.GetTextGSC(buy), duration/60, warn)); end return "abort"; end end if (not CursorHasItem() and AuctionFramePost and AuctionFramePost:IsVisible() and button == "LeftButton" and IsAltKeyDown()) then local _, count = GetContainerItemInfo(bag, slot); if (count) then if (count > 1 and IsShiftKeyDown()) then this.SplitStack = function(button, split) local _, _, _, _, name = EnhTooltip.BreakLink(link); AuctionFramePost:SetAuctionItem(bag, slot, split); end OpenStackSplitFrame(count, this, "BOTTOMRIGHT", "TOPRIGHT"); else local _, _, _, _, name = EnhTooltip.BreakLink(link); AuctionFramePost:SetAuctionItem(bag, slot, 1); end return "abort"; end end end Auctioneer.Util = { GetTimeLeftString = getTimeLeftString, GetSecondsLeftString = getSecondsLeftString, UnpackSeconds = unpackSeconds, GetGSC = getGSC, GetTextGSC = getTextGSC, NilSafeString = nilSafeString, ColorTextWhite = colorTextWhite, GetWarnColor = getWarnColor, NullSafe = nullSafe, SanifyAHSnapshot = sanifyAHSnapshot, GetAuctionKey = getAuctionKey, GetOppositeKey = getOppositeKey, GetNeutralKey = getNeutralKey, GetHomeKey = getHomeKey, IsValidAlso = isValidAlso, BreakItemKey = breakItemKey, Split = split, FindClass = findClass, GetCatName = getCatName, GetCatNumberByName = getCatNumberByName, GetCatForKey = getCatForKey, GetKeyFromSig = getKeyFromSig, GetCatForSig = getCatForSig, GetItemLinks = getItemLinks, GetItems = getItems, GetItemHyperlinks = getItemHyperlinks, LoadCategories = loadCategories, LoadCategoryClasses = loadCategoryClasses, LoadCategorySubClasses = loadCategorySubClasses, ChatPrint = chatPrint, SetFilterDefaults = setFilterDefaults, ProtectAuctionFrame = protectAuctionFrame, PriceForOne = priceForOne, Round = round, DelocalizeFilterVal = delocalizeFilterVal, LocalizeFilterVal = localizeFilterVal, GetLocalizedFilterVal = getLocalizedFilterVal, DelocalizeCommand = delocalizeCommand, LocalizeCommand = localizeCommand, FindEmptySlot = findEmptySlot, ContainerFrameItemButtonOnClick = containerFrameItemButtonOnClick, }