--[[ BagSync.lua A item tracking addon that works with practically any bag addon available. This addon has been heavily rewritten several times since it's creation back in 2007. This addon was inspired by Tuller and his Bagnon addon. (Thanks Tuller!) Author: Xruptor --]] local L = BAGSYNC_L local lastItem local lastDisplayed = {} local currentPlayer local currentRealm local playerClass local playerFaction local crossRealmNames = {} local NUM_EQUIPMENT_SLOTS = 19 local BS_DB local BS_GD local BS_TD local BS_CD local BS_BL local MAX_GUILDBANK_SLOTS_PER_TAB = 98 local doTokenUpdate = 0 local guildTabQueryQueue = {} local atBank = false local atVoidBank = false local atGuildBank = false local isCheckingMail = false local SILVER = '|cffc7c7cf%s|r' local MOSS = '|cFF80FF00%s|r' local TTL_C = '|cFFF4A460%s|r' local GN_C = '|cFF65B8C0%s|r' local debugf = tekDebug and tekDebug:GetFrame("BagSync") local function Debug(...) if debugf then debugf:AddMessage(string.join(", ", tostringall(...))) end end ------------------------------ -- LibDataBroker-1.1 -- ------------------------------ local ldb = LibStub:GetLibrary("LibDataBroker-1.1") local dataobj = ldb:NewDataObject("BagSyncLDB", { type = "data source", --icon = "Interface\\Icons\\INV_Misc_Bag_12", icon = "Interface\\AddOns\\BagSync\\media\\icon", label = "BagSync", text = "BagSync", OnClick = function(self, button) if button == 'LeftButton' and BagSync_SearchFrame then if BagSync_SearchFrame:IsVisible() then BagSync_SearchFrame:Hide() else BagSync_SearchFrame:Show() end elseif button == 'RightButton' and BagSync_TokensFrame then if bgsMinimapDD then ToggleDropDownMenu(1, nil, bgsMinimapDD, 'cursor', 0, 0) end end end, OnTooltipShow = function(self) self:AddLine("BagSync") self:AddLine(L["Left Click = Search Window"]) self:AddLine(L["Right Click = BagSync Menu"]) end }) ------------------------------ -- MAIN OBJ -- ------------------------------ local BagSync = CreateFrame("Frame", "BagSync", UIParent) BagSync:SetScript('OnEvent', function(self, event, ...) if self[event] then self[event](self, event, ...) end end) function BagSync:Debug(...) Debug(...) end if IsLoggedIn() then BagSync:PLAYER_LOGIN() else BagSync:RegisterEvent('PLAYER_LOGIN') end ---------------------- -- DB Functions -- ---------------------- local function StartupDB() BagSyncOpt = BagSyncOpt or {} if BagSyncOpt.showTotal == nil then BagSyncOpt.showTotal = true end if BagSyncOpt.showGuildNames == nil then BagSyncOpt.showGuildNames = false end if BagSyncOpt.enableGuild == nil then BagSyncOpt.enableGuild = true end if BagSyncOpt.enableMailbox == nil then BagSyncOpt.enableMailbox = true end if BagSyncOpt.enableUnitClass == nil then BagSyncOpt.enableUnitClass = false end if BagSyncOpt.enableMinimap == nil then BagSyncOpt.enableMinimap = true end if BagSyncOpt.enableFaction == nil then BagSyncOpt.enableFaction = true end if BagSyncOpt.enableAuction == nil then BagSyncOpt.enableAuction = true end if BagSyncOpt.tooltipOnlySearch == nil then BagSyncOpt.tooltipOnlySearch = false end if BagSyncOpt.enableTooltips == nil then BagSyncOpt.enableTooltips = true end if BagSyncOpt.enableTooltipSeperator == nil then BagSyncOpt.enableTooltipSeperator = true end if BagSyncOpt.enableCrossRealmsItems == nil then BagSyncOpt.enableCrossRealmsItems = true end if BagSyncOpt.enableBNetAccountItems == nil then BagSyncOpt.enableBNetAccountItems = false end --new format, get rid of old if not BagSyncOpt.dbversion or not tonumber(BagSyncOpt.dbversion) or tonumber(BagSyncOpt.dbversion) < 7 then BagSyncDB = {} BagSyncGUILD_DB = {} print("|cFFFF0000BagSync: You have been updated to latest database version! You will need to rescan all your characters again!|r") end BagSyncDB = BagSyncDB or {} BagSyncDB[currentRealm] = BagSyncDB[currentRealm] or {} BagSyncDB[currentRealm][currentPlayer] = BagSyncDB[currentRealm][currentPlayer] or {} BS_DB = BagSyncDB[currentRealm][currentPlayer] BagSyncGUILD_DB = BagSyncGUILD_DB or {} BagSyncGUILD_DB[currentRealm] = BagSyncGUILD_DB[currentRealm] or {} BS_GD = BagSyncGUILD_DB[currentRealm] BagSyncTOKEN_DB = BagSyncTOKEN_DB or {} BagSyncTOKEN_DB[currentRealm] = BagSyncTOKEN_DB[currentRealm] or {} BS_TD = BagSyncTOKEN_DB[currentRealm] BagSyncCRAFT_DB = BagSyncCRAFT_DB or {} BagSyncCRAFT_DB[currentRealm] = BagSyncCRAFT_DB[currentRealm] or {} BagSyncCRAFT_DB[currentRealm][currentPlayer] = BagSyncCRAFT_DB[currentRealm][currentPlayer] or {} BS_CD = BagSyncCRAFT_DB[currentRealm][currentPlayer] BagSyncBLACKLIST_DB = BagSyncBLACKLIST_DB or {} BagSyncBLACKLIST_DB[currentRealm] = BagSyncBLACKLIST_DB[currentRealm] or {} BS_BL = BagSyncBLACKLIST_DB[currentRealm] end function BagSync:FixDB_Data(onlyChkGuild) --Removes obsolete character information --Removes obsolete guild information --Removes obsolete characters from tokens db --Removes obsolete profession information --Will only check guild related information if the paramater is passed as true --Adds realm name to characters profiles if missing, v8.6 local storeUsers = {} local storeGuilds = {} for realm, rd in pairs(BagSyncDB) do --realm storeUsers[realm] = storeUsers[realm] or {} storeGuilds[realm] = storeGuilds[realm] or {} for k, v in pairs(rd) do --users storeUsers[realm][k] = storeUsers[realm][k] or 1 if v.realm == nil then v.realm = realm end --Adds realm name to characters profiles if missing, v8.6 for q, r in pairs(v) do if q == 'guild' then storeGuilds[realm][r] = true end end end end --guildbank data for realm, rd in pairs(BagSyncGUILD_DB) do --realm for k, v in pairs(rd) do --users if not storeGuilds[realm][k] then --delete the guild because no one has it BagSyncGUILD_DB[realm][k] = nil end end end --token data and profession data, only do if were not doing a guild check --also display fixdb message only if were not doing a guild check if not onlyChkGuild then --fix tokens for realm, rd in pairs(BagSyncTOKEN_DB) do --realm if not storeUsers[realm] then --if it's not a realm that ANY users are on then delete it BagSyncTOKEN_DB[realm] = nil else --delete old db information for tokens if it exists if BagSyncTOKEN_DB[realm] and BagSyncTOKEN_DB[realm][1] then BagSyncTOKEN_DB[realm][1] = nil end if BagSyncTOKEN_DB[realm] and BagSyncTOKEN_DB[realm][2] then BagSyncTOKEN_DB[realm][2] = nil end for k, v in pairs(rd) do for x, y in pairs(v) do if x ~= "icon" and x ~= "header" then if not storeUsers[realm][x] then --if the user doesn't exist then delete data BagSyncTOKEN_DB[realm][k][x] = nil end end end end end end --fix professions for realm, rd in pairs(BagSyncCRAFT_DB) do --realm if not storeUsers[realm] then --if it's not a realm that ANY users are on then delete it BagSyncCRAFT_DB[realm] = nil else for k, v in pairs(rd) do if not storeUsers[realm][k] then --if the user doesn't exist then delete data BagSyncCRAFT_DB[realm][k] = nil end end end end DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33BagSync:|r |cFFFF9900"..L["A FixDB has been performed on BagSync! The database is now optimized!"].."|r") end end function BagSync:getFilteredDB() local xIndex = {} --add more realm names if necessary based on BNet or Cross Realms if BagSyncOpt.enableBNetAccountItems then for k, v in pairs(BagSyncDB) do for q, r in pairs(v) do --we do this incase there are multiple characters with same name xIndex[q.."^"..k] = r end end elseif BagSyncOpt.enableCrossRealmsItems then for k, v in pairs(BagSyncDB) do if k == currentRealm or crossRealmNames[k] then for q, r in pairs(v) do ----we do this incase there are multiple characters with same name xIndex[q.."^"..k] = r end end end else xIndex = BagSyncDB[currentRealm] end return xIndex end function BagSync:getCharacterRealmInfo(charName, charRealm) local yName, yRealm = strsplit('^', charName) --add Cross-Realm and BNet identifiers to Characters not on same realm if BagSyncOpt.enableBNetAccountItems then if charRealm and charRealm ~= currentRealm then if not crossRealmNames[charRealm] then charName = yName.." |cff3588ff[BNet-"..charRealm.."]|r" else charName = yName.." |cffff7d0a[XR-"..charRealm.."]|r" end else charName = yName end elseif BagSyncOpt.enableCrossRealmsItems then if charRealm and charRealm ~= currentRealm then charName = yName.." |cffff7d0a[XR-"..charRealm.."]|r" else charName = yName end else --to cover our buttocks lol, JUST IN CASE charName = yName end return charName end function BagSync:getGuildRealmInfo(guildName, guildRealm) --add Cross-Realm and BNet identifiers to Guilds not on same realm if BagSyncOpt.enableBNetAccountItems then if guildRealm and guildRealm ~= currentRealm then if not crossRealmNames[guildRealm] then guildName = guildName.." |cff3588ff[BNet-"..guildRealm.."]|r" else guildName = guildName.." |cffff7d0a[XR-"..guildRealm.."]|r" end else guildName = guildName end elseif BagSyncOpt.enableCrossRealmsItems then if guildRealm and guildRealm ~= currentRealm then guildName = guildName.." |cffff7d0a[XR-"..guildRealm.."]|r" else guildName = guildName end else --to cover our buttocks lol, JUST IN CASE guildName = guildName end return guildName end ---------------------- -- Local -- ---------------------- local function doRegularTradeSkill(numIndex, dbIdx) local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(numIndex) if name and skillLevel then BS_CD[dbIdx] = format('%s,%s', name, skillLevel) end end local function ToShortLink(link) if not link then return nil end return link:match("item:(%d+):") or nil end ---------------------- -- Bag Functions -- ---------------------- local function SaveBag(bagname, bagid) if not bagname or not bagid then return nil end if not BS_DB then StartupDB() end BS_DB[bagname] = BS_DB[bagname] or {} --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} if GetContainerNumSlots(bagid) > 0 then local slotItems = {} for slot = 1, GetContainerNumSlots(bagid) do local _, count, _,_,_,_, link = GetContainerItemInfo(bagid, slot) if ToShortLink(link) then count = (count > 1 and count) or nil if count then slotItems[slot] = format('%s,%d', ToShortLink(link), count) else slotItems[slot] = ToShortLink(link) end end end BS_DB[bagname][bagid] = slotItems else BS_DB[bagname][bagid] = nil end end local function SaveEquipment() --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} if not BS_DB then StartupDB() end BS_DB['equip'] = BS_DB['equip'] or {} local slotItems = {} --start at 1, 0 used to be the old range slot (not needed anymore) for slot = 1, NUM_EQUIPMENT_SLOTS do local link = GetInventoryItemLink('player', slot) if link and ToShortLink(link) then local count = GetInventoryItemCount('player', slot) count = (count and count > 1) or nil if count then slotItems[slot] = format('%s,%d', ToShortLink(link), count) else slotItems[slot] = ToShortLink(link) end end end BS_DB['equip'][0] = slotItems end local function ScanEntireBank() --force scan of bank bag -1, since blizzard never sends updates for it SaveBag('bank', BANK_CONTAINER) for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do SaveBag('bank', i) end if IsReagentBankUnlocked() then SaveBag('reagentbank', REAGENTBANK_CONTAINER) end end local function ScanVoidBank() if VoidStorageFrame and VoidStorageFrame:IsShown() then if not BS_DB then StartupDB() end BS_DB['void'] = BS_DB['void'] or {} --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} local numTabs = 2 local index = 0 local slotItems = {} for tab = 1, numTabs do for i = 1, 80 do local itemID, textureName, locked, recentDeposit, isFiltered = GetVoidItemInfo(tab, i) if (itemID) then index = index + 1 slotItems[index] = itemID and tostring(itemID) or nil end end end BS_DB['void'][0] = slotItems end end local function ScanGuildBank() --GetCurrentGuildBankTab() if not IsInGuild() then return end if not BS_GD then StartupDB() end BS_GD[BS_DB.guild] = BS_GD[BS_DB.guild] or {} --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} local numTabs = GetNumGuildBankTabs() local index = 0 local slotItems = {} for tab = 1, numTabs do local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(tab) --if we don't check for isViewable we get a weirdo permissions error for the player when they attempt it if isViewable then for slot = 1, MAX_GUILDBANK_SLOTS_PER_TAB do local link = GetGuildBankItemLink(tab, slot) if link and ToShortLink(link) then index = index + 1 local _, count = GetGuildBankItemInfo(tab, slot) count = (count > 1 and count) or nil if count then slotItems[index] = format('%s,%d', ToShortLink(link), count) else slotItems[index] = ToShortLink(link) end end end end end BS_GD[BS_DB.guild] = slotItems end local function ScanMailbox() --this is to prevent buffer overflow from the CheckInbox() function calling ScanMailbox too much :) if isCheckingMail then return end isCheckingMail = true --used to initiate mail check from server, for some reason GetInboxNumItems() returns zero sometimes --even though the user has mail in the mailbox. This can be attributed to lag. CheckInbox() if not BS_DB then StartupDB() end BS_DB['mailbox'] = BS_DB['mailbox'] or {} local slotItems = {} local mailCount = 0 local numInbox = GetInboxNumItems() --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} --scan the inbox if (numInbox > 0) then for mailIndex = 1, numInbox do for i=1, ATTACHMENTS_MAX_RECEIVE do local name, itemID, itemTexture, count, quality, canUse = GetInboxItem(mailIndex, i) local link = GetInboxItemLink(mailIndex, i) if name and link and ToShortLink(link) then mailCount = mailCount + 1 count = (count > 1 and count) or nil if count then slotItems[mailCount] = format('%s,%d', ToShortLink(link), count) else slotItems[mailCount] = ToShortLink(link) end end end end end BS_DB['mailbox'][0] = slotItems isCheckingMail = false end local function ScanAuctionHouse() if not BS_DB then StartupDB() end BS_DB['auction'] = BS_DB['auction'] or {} local slotItems = {} local ahCount = 0 local numActiveAuctions = GetNumAuctionItems("owner") --reset our tooltip data since we scanned new items (we want current data not old) lastItem = nil lastDisplayed = {} --scan the auction house if (numActiveAuctions > 0) then for ahIndex = 1, numActiveAuctions do local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner, saleStatus = GetAuctionItemInfo("owner", ahIndex) if name then local link = GetAuctionItemLink("owner", ahIndex) local timeLeft = GetAuctionItemTimeLeft("owner", ahIndex) if link and ToShortLink(link) and timeLeft then ahCount = ahCount + 1 count = (count or 1) slotItems[ahCount] = format('%s,%s,%s', ToShortLink(link), count, timeLeft) end end end end BS_DB['auction'][0] = slotItems BS_DB.AH_Count = ahCount end --this method is global for all toons, removes expired auctions on login local function RemoveExpiredAuctions() local timestampChk = { 30*60, 2*60*60, 12*60*60, 48*60*60 } for realm, rd in pairs(BagSyncDB) do --realm for k, v in pairs(rd) do --users k=name, v=values if BagSyncDB[realm][k].AH_LastScan and BagSyncDB[realm][k].AH_Count then --only proceed if we have an auction house time to work with --check to see if we even have something to work with if BagSyncDB[realm][k]['auction'] then --we do so lets do a loop local bVal = BagSyncDB[realm][k].AH_Count --do a loop through all of them and check to see if any expired for x = 1, bVal do if BagSyncDB[realm][k]['auction'][0][x] then --check for expired and remove if necessary --it's okay if the auction count is showing more then actually stored, it's just used as a means --to scan through all our items. Even if we have only 3 and the count is 6 it will just skip the last 3. local dblink, dbcount, dbtimeleft = strsplit(',', BagSyncDB[realm][k]['auction'][0][x]) --only proceed if we have everything to work with, otherwise this auction data is corrupt if dblink and dbcount and dbtimeleft then if tonumber(dbtimeleft) < 1 or tonumber(dbtimeleft) > 4 then dbtimeleft = 4 end --just in case --now do the time checks local diff = time() - BagSyncDB[realm][k].AH_LastScan if diff > timestampChk[tonumber(dbtimeleft)] then --technically this isn't very realiable. but I suppose it's better the nothing BagSyncDB[realm][k]['auction'][0][x] = nil end else --it's corrupt delete it BagSyncDB[realm][k]['auction'][0][x] = nil end end end end end end end end ------------------------ -- Money Tooltip -- ------------------------ local function buildMoneyString(money, color) local iconSize = 14 local goldicon = string.format("\124TInterface\\MoneyFrame\\UI-GoldIcon:%d:%d:1:0\124t ", iconSize, iconSize) local silvericon = string.format("\124TInterface\\MoneyFrame\\UI-SilverIcon:%d:%d:1:0\124t ", iconSize, iconSize) local coppericon = string.format("\124TInterface\\MoneyFrame\\UI-CopperIcon:%d:%d:1:0\124t ", iconSize, iconSize) local moneystring local g,s,c local neg = false if(money <0) then neg = true money = money * -1 end g=floor(money/10000) s=floor((money-(g*10000))/100) c=money-s*100-g*10000 moneystring = g..goldicon..s..silvericon..c..coppericon if(neg) then moneystring = "-"..moneystring end if(color) then if(neg) then moneystring = "|cffff0000"..moneystring.."|r" elseif(money ~= 0) then moneystring = "|cff44dd44"..moneystring.."|r" end end return moneystring end function BagSync:ShowMoneyTooltip() local tooltip = _G["BagSyncMoneyTooltip"] or nil if (not tooltip) then tooltip = CreateFrame("GameTooltip", "BagSyncMoneyTooltip", UIParent, "GameTooltipTemplate") local closeButton = CreateFrame("Button", nil, tooltip, "UIPanelCloseButton") closeButton:SetPoint("TOPRIGHT", tooltip, 1, 0) tooltip:SetToplevel(true) tooltip:EnableMouse(true) tooltip:SetMovable(true) tooltip:SetClampedToScreen(true) tooltip:SetScript("OnMouseDown",function(self) self.isMoving = true self:StartMoving(); end) tooltip:SetScript("OnMouseUp",function(self) if( self.isMoving ) then self.isMoving = nil self:StopMovingOrSizing() end end) end local usrData = {} tooltip:SetOwner(UIParent, 'ANCHOR_NONE') tooltip:ClearLines() tooltip:ClearAllPoints() tooltip:SetPoint("CENTER",UIParent,"CENTER",0,0) tooltip:AddLine("BagSync") tooltip:AddLine(" ") --loop through our characters local xDB = BagSync:getFilteredDB() for k, v in pairs(xDB) do if v.gold then k = BagSync:getCharacterRealmInfo(k, v.realm) table.insert(usrData, { name=k, gold=v.gold } ) end end table.sort(usrData, function(a,b) return (a.name < b.name) end) local gldTotal = 0 for i=1, table.getn(usrData) do tooltip:AddDoubleLine(usrData[i].name, buildMoneyString(usrData[i].gold, false), 1, 1, 1, 1, 1, 1) gldTotal = gldTotal + usrData[i].gold end if BagSyncOpt.showTotal and gldTotal > 0 then tooltip:AddLine(" ") tooltip:AddDoubleLine(format(TTL_C, L["Total:"]), buildMoneyString(gldTotal, false), 1, 1, 1, 1, 1, 1) end tooltip:AddLine(" ") tooltip:Show() end ------------------------ -- Tokens -- ------------------------ local function IsInBG() if (GetNumBattlefieldScores() > 0) then return true end return false end local function IsInArena() local a,b = IsActiveBattlefieldArena() if not a then return false end return true end local function ScanTokens() --LETS AVOID TOKEN SPAM AS MUCH AS POSSIBLE if doTokenUpdate == 1 then return end if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then --avoid (Honor point spam), avoid (arena point spam), if it's world PVP...well then it sucks to be you doTokenUpdate = 1 BagSync:RegisterEvent('PLAYER_REGEN_ENABLED') return end local lastHeader local limit = GetCurrencyListSize() for i=1, limit do local name, isHeader, isExpanded, _, _, count, icon = GetCurrencyListInfo(i) --extraCurrencyType = 1 for arena points, 2 for honor points; 0 otherwise (an item-based currency). if name then if(isHeader and not isExpanded) then ExpandCurrencyList(i,1) lastHeader = name limit = GetCurrencyListSize() elseif isHeader then lastHeader = name end if (not isHeader) then if BS_TD then BS_TD = BS_TD or {} BS_TD[name] = BS_TD[name] or {} BS_TD[name].icon = icon BS_TD[name].header = lastHeader BS_TD[name][currentPlayer] = count end end end end --we don't want to overwrite tokens, because some characters may have currency that the others dont have end hooksecurefunc("BackpackTokenFrame_Update", ScanTokens) ------------------------ -- Tooltip! -- -- (Special thanks to tuller) ------------------------ --a function call to reset these local variables outside the scope ;) function BagSync:resetTooltip() lastDisplayed = {} lastItem = nil end local function CountsToInfoString(countTable) local info local total = 0 if countTable['bag'] > 0 then info = L["Bags: %d"]:format(countTable['bag']) total = total + countTable['bag'] end if countTable['bank'] > 0 then local count = L["Bank: %d"]:format(countTable['bank']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['bank'] end if countTable['reagentbank'] > 0 then local count = L["Reagent: %d"]:format(countTable['reagentbank']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['reagentbank'] end if countTable['equip'] > 0 then local count = L["Equip: %d"]:format(countTable['equip']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['equip'] end if countTable['guild'] > 0 and BagSyncOpt.enableGuild and not BagSyncOpt.showGuildNames then local count = L["Guild: %d"]:format(countTable['guild']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['guild'] --add the guild count only if we don't have showguildnames on, otherwise it's counted twice end if countTable['mailbox'] > 0 and BagSyncOpt.enableMailbox then local count = L["Mail: %d"]:format(countTable['mailbox']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['mailbox'] end if countTable['void'] > 0 then local count = L["Void: %d"]:format(countTable['void']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['void'] end if countTable['auction'] > 0 and BagSyncOpt.enableAuction then local count = L["AH: %d"]:format(countTable['auction']) if info then info = strjoin(', ', info, count) else info = count end total = total + countTable['auction'] end if info and info ~= "" then --check to see if we show multiple items or just a single one per character local totalPass = false for q, v in pairs(countTable) do if v == total then totalPass = true break end end if not totalPass then local totalStr = format(MOSS, total) return totalStr .. format(SILVER, format(' (%s)', info)) else return format(MOSS, info) end end end --sort by key element rather then value local function pairsByKeys (t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end local function rgbhex(r, g, b) if type(r) == "table" then if r.r then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end end return string.format("|cff%02x%02x%02x", (r or 1) * 255, (g or 1) * 255, (b or 1) * 255) end local function getNameColor(sName, sClass) if not BagSyncOpt.enableUnitClass then return format(MOSS, sName) else if sName ~= "Unknown" and sClass and RAID_CLASS_COLORS[sClass] then return rgbhex(RAID_CLASS_COLORS[sClass])..sName.."|r" end end return format(MOSS, sName) end local function getPlayerNameColor(sName) if BagSyncDB[currentRealm][sName] then local sClass = BagSyncDB[currentRealm][sName].class return getNameColor(sName, sClass) end return format(MOSS, sName) end local function AddCurrencyToTooltip(frame, currencyName) if BS_TD and currencyName and BS_TD[currencyName] then if BagSyncOpt.enableTooltipSeperator then frame:AddLine(" ") end for charName, count in pairsByKeys(BS_TD[currencyName]) do if charName ~= "icon" and charName ~= "header" and count > 0 then frame:AddDoubleLine(getPlayerNameColor(charName), count) end end frame:Show() end end local function AddItemToTooltip(frame, link) --workaround --if we can't convert the item link then lets just ignore it altogether local itemLink = ToShortLink(link) if not itemLink then frame:Show() return end --only show tooltips in search frame if the option is enabled if BagSyncOpt.tooltipOnlySearch and frame:GetOwner() and frame:GetOwner():GetName() and string.sub(frame:GetOwner():GetName(), 1, 16) ~= "BagSyncSearchRow" then frame:Show() return end --ignore the hearthstone and blacklisted items if itemLink and tonumber(itemLink) and (tonumber(itemLink) == 6948 or tonumber(itemLink) == 110560 or tonumber(itemLink) == 140192 or BS_BL[tonumber(itemLink)]) then frame:Show() return end --lag check (check for previously displayed data) if so then display it if lastItem and itemLink and itemLink == lastItem then for i = 1, #lastDisplayed do local ename, ecount = strsplit('@', lastDisplayed[i]) if ename and ecount then frame:AddDoubleLine(ename, ecount) end end frame:Show() return end --reset our last displayed lastDisplayed = {} lastItem = itemLink --this is so we don't scan the same guild multiple times local previousGuilds = {} local grandTotal = 0 local first = true local xDB = BagSync:getFilteredDB() --loop through our characters --k = player, v = stored data for player for k, v in pairs(xDB) do local allowList = { ["bag"] = 0, ["bank"] = 0, ["reagentbank"] = 0, ["equip"] = 0, ["mailbox"] = 0, ["void"] = 0, ["auction"] = 0, ["guild"] = 0, } local infoString local pFaction = v.faction or playerFaction --just in case ;) if we dont know the faction yet display it anyways --check if we should show both factions or not if BagSyncOpt.enableFaction or pFaction == playerFaction then --now count the stuff for the user --q = bag name, r = stored data for bag name for q, r in pairs(v) do --only loop through table items we want if allowList[q] and type(r) == "table" then --bagID = bag name bagID, bagInfo = data of specific bag with bagID for bagID, bagInfo in pairs(r) do --slotID = slotid for specific bagid, itemValue = data of specific slotid if type(bagInfo) == "table" then for slotID, itemValue in pairs(bagInfo) do local dblink, dbcount = strsplit(',', itemValue) if dblink and dblink == itemLink then allowList[q] = allowList[q] + (dbcount or 1) grandTotal = grandTotal + (dbcount or 1) end end end end end end if BagSyncOpt.enableGuild then local guildN = v.guild or nil --check the guild bank if the character is in a guild if BagSyncGUILD_DB and guildN and BagSyncGUILD_DB[v.realm][guildN] then --check to see if this guild has already been done through this run (so we don't do it multiple times) --check for XR/B.Net support local gName = BagSync:getGuildRealmInfo(guildN, v.realm) if not previousGuilds[gName] then --we only really need to see this information once per guild local tmpCount = 0 for q, r in pairs(BagSyncGUILD_DB[v.realm][guildN]) do local dblink, dbcount = strsplit(',', r) if dblink and dblink == itemLink then allowList["guild"] = allowList["guild"] + (dbcount or 1) tmpCount = tmpCount + (dbcount or 1) grandTotal = grandTotal + (dbcount or 1) end end previousGuilds[gName] = tmpCount end end end --get class for the unit if there is one local pClass = v.class or nil infoString = CountsToInfoString(allowList) if infoString and infoString ~= '' then k = BagSync:getCharacterRealmInfo(k, v.realm) table.insert(lastDisplayed, getNameColor(k or 'Unknown', pClass).."@"..(infoString or 'unknown')) end end end --sort it table.sort(lastDisplayed, function(a,b) return (a < b) end) --show guildnames last if BagSyncOpt.enableGuild and BagSyncOpt.showGuildNames then for k, v in pairsByKeys(previousGuilds) do --only print stuff higher then zero if v > 0 then table.insert(lastDisplayed, format(GN_C, k).."@"..format(SILVER, v)) end end end --show grand total if we have something --don't show total if there is only one item if BagSyncOpt.showTotal and grandTotal > 0 and getn(lastDisplayed) > 1 then table.insert(lastDisplayed, format(TTL_C, L["Total:"]).."@"..format(SILVER, grandTotal)) end --now check for seperater and only add if we have something in the table already if table.getn(lastDisplayed) > 0 and BagSyncOpt.enableTooltipSeperator then table.insert(lastDisplayed, 1 , " @ ") end --add it all together now for i = 1, #lastDisplayed do local ename, ecount = strsplit('@', lastDisplayed[i]) if ename and ecount then frame:AddDoubleLine(ename, ecount) end end frame:Show() end --simplified tooltip function, similar to the past HookTip that was used before Jan 06, 2011 (commit:a89046f844e24585ab8db60d10f2f168498b9af4) --Honestly we aren't going to care about throttleing or anything like that anymore. The lastdisplay array token should take care of that --Special thanks to Tuller for tooltip hook function local function hookTip(tooltip) local modified = false tooltip:HookScript("OnHide", function(self) modified = false self.lastHyperLink = nil end) tooltip:HookScript('OnTooltipCleared', function(self) modified = false end) tooltip:HookScript('OnTooltipSetItem', function(self) if modified or not BagSyncOpt.enableTooltips then return end local name, link = self:GetItem() if link and ToShortLink(link) then modified = true AddItemToTooltip(self, link) return end --sometimes we have a tooltip but no link because GetItem() returns nil, this is the case for recipes --so lets try something else to see if we can get the link. Doesn't always work! Thanks for breaking GetItem() Blizzard... you ROCK! :P if not modified and self.lastHyperLink then local xName, xLink = GetItemInfo(self.lastHyperLink) --local title = _G[tooltip:GetName().."TextLeft1"] -- if xName and xLink and title and title:GetText() and title:GetText() == xName and ToShortLink(xLink) then --only show info if the tooltip text matches the link -- modified = true -- AddItemToTooltip(self, xLink) -- end if xLink and ToShortLink(xLink) then --only show info if the tooltip text matches the link modified = true AddItemToTooltip(self, xLink) end end end) --------------------------------- --Special thanks to GetItem() being broken we need to capture the ItemLink before the tooltip shows sometimes hooksecurefunc(tooltip, 'SetBagItem', function(self, tab, slot) if not BagSyncOpt.enableTooltips then return end local link = GetContainerItemLink(tab, slot) if link and ToShortLink(link) then self.lastHyperLink = link end end) hooksecurefunc(tooltip, 'SetInventoryItem', function(self, tab, slot) if not BagSyncOpt.enableTooltips then return end local link = GetInventoryItemLink(tab, slot) if link and ToShortLink(link) then self.lastHyperLink = link end end) hooksecurefunc(tooltip, 'SetGuildBankItem', function(self, tab, slot) if not BagSyncOpt.enableTooltips then return end local link = GetGuildBankItemLink(tab, slot) if link and ToShortLink(link) then self.lastHyperLink = link end end) hooksecurefunc(tooltip, 'SetHyperlink', function(self, link) if modified or not BagSyncOpt.enableTooltips then return end if link and ToShortLink(link) then --I'm pretty sure there is a better way to do this but since Recipes fire OnTooltipSetItem with empty/nil GetItem(). There is really no way to my knowledge to grab the current itemID --without storing the ItemLink from the bag parsing or at least grabbing the current SetHyperLink. if tooltip:IsVisible() then modified = true end --only do the modifier if the tooltip is showing, because this interferes with ItemRefTooltip if someone clicks it twice in chat AddItemToTooltip(self, link) end end) --------------------------------- --lets hook other frames so we can show tooltips there as well hooksecurefunc(tooltip, 'SetRecipeReagentItem', function(self, recipeID, reagentIndex) if modified or not BagSyncOpt.enableTooltips then return end local link = C_TradeSkillUI.GetRecipeReagentItemLink(recipeID, reagentIndex) if link and ToShortLink(link) then modified = true AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, 'SetRecipeResultItem', function(self, recipeID) if modified or not BagSyncOpt.enableTooltips then return end local link = C_TradeSkillUI.GetRecipeItemLink(recipeID) if link and ToShortLink(link) then modified = true AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, 'SetQuestLogItem', function(self, itemType, index) if modified or not BagSyncOpt.enableTooltips then return end local link = GetQuestLogItemLink(itemType, index) if link and ToShortLink(link) then modified = true AddItemToTooltip(self, link) end end) hooksecurefunc(tooltip, 'SetQuestItem', function(self, itemType, index) if modified or not BagSyncOpt.enableTooltips then return end local link = GetQuestItemLink(itemType, index) if link and ToShortLink(link) then modified = true AddItemToTooltip(self, link) end end) -- hooksecurefunc(tooltip, 'SetItemByID', function(self, link) -- if modified or not BagSyncOpt.enableTooltips then return end -- if link and ToShortLink(link) then -- modified = true -- AddItemToTooltip(self, link) -- end -- end) -------------------------------------------------- hooksecurefunc(tooltip, 'SetCurrencyToken', function(self, index) if modified or not BagSyncOpt.enableTooltips then return end modified = true local currencyName = GetCurrencyListInfo(index) AddCurrencyToTooltip(self, currencyName) end) hooksecurefunc(tooltip, 'SetCurrencyByID', function(self, id) if modified or not BagSyncOpt.enableTooltips then return end modified = true local currencyName = GetCurrencyInfo(id) AddCurrencyToTooltip(self, currencyName) end) hooksecurefunc(tooltip, 'SetBackpackToken', function(self, index) if modified or not BagSyncOpt.enableTooltips then return end modified = true local currencyName = GetBackpackCurrencyInfo(index) AddCurrencyToTooltip(self, currencyName) end) -- hooksecurefunc(tooltip, 'SetTradeSkillReagentInfo', function(self, index) -- if modified or not BagSyncOpt.enableTooltips then return end -- modified = true -- local currencyName = GetTradeSkillReagentInfo(index,1) -- AddCurrencyToTooltip(self, currencyName) -- end) end hookTip(GameTooltip) hookTip(ItemRefTooltip) ------------------------------ -- LOGIN HANDLER -- ------------------------------ function BagSync:PLAYER_LOGIN() BINDING_HEADER_BAGSYNC = "BagSync" BINDING_NAME_BAGSYNCTOGGLESEARCH = L["Toggle Search"] BINDING_NAME_BAGSYNCTOGGLETOKENS = L["Toggle Tokens"] BINDING_NAME_BAGSYNCTOGGLEPROFILES = L["Toggle Profiles"] BINDING_NAME_BAGSYNCTOGGLECRAFTS = L["Toggle Professions"] BINDING_NAME_BAGSYNCTOGGLEBLACKLIST = L["Toggle Blacklist"] local ver = GetAddOnMetadata("BagSync","Version") or 0 --load our player info after login currentPlayer = UnitName('player') currentRealm = GetRealmName() playerClass = select(2, UnitClass("player")) playerFaction = UnitFactionGroup("player") local autoCompleteRealms = GetAutoCompleteRealms() or { currentRealm } for k, v in pairs(autoCompleteRealms) do if v ~= currentRealm then crossRealmNames[v] = true end end --initiate the db StartupDB() --do DB cleanup check by version number if not BagSyncOpt.dbversion or BagSyncOpt.dbversion ~= ver then self:FixDB_Data() BagSyncOpt.dbversion = ver end --save the current user money (before bag update) BS_DB.gold = GetMoney() --save the class information BS_DB.class = playerClass --save the faction information --"Alliance", "Horde" or nil BS_DB.faction = playerFaction --save player Realm for quick access later BS_DB.realm = currentRealm --check for player not in guild if IsInGuild() or GetNumGuildMembers(true) > 0 then GuildRoster() elseif BS_DB.guild then BS_DB.guild = nil self:FixDB_Data(true) end --save all inventory data, including backpack(0) for i = BACKPACK_CONTAINER, BACKPACK_CONTAINER + NUM_BAG_SLOTS do SaveBag('bag', i) end --force an equipment scan SaveEquipment() --force token scan ScanTokens() --clean up old auctions RemoveExpiredAuctions() --check for minimap toggle if BagSyncOpt.enableMinimap and BagSync_MinimapButton and not BagSync_MinimapButton:IsVisible() then BagSync_MinimapButton:Show() elseif not BagSyncOpt.enableMinimap and BagSync_MinimapButton and BagSync_MinimapButton:IsVisible() then BagSync_MinimapButton:Hide() end self:RegisterEvent('PLAYER_MONEY') self:RegisterEvent('BANKFRAME_OPENED') self:RegisterEvent('BANKFRAME_CLOSED') self:RegisterEvent('GUILDBANKFRAME_OPENED') self:RegisterEvent('GUILDBANKFRAME_CLOSED') self:RegisterEvent('GUILDBANKBAGSLOTS_CHANGED') self:RegisterEvent('PLAYERREAGENTBANKSLOTS_CHANGED') self:RegisterEvent('BAG_UPDATE') self:RegisterEvent('PLAYERBANKSLOTS_CHANGED') self:RegisterEvent('UNIT_INVENTORY_CHANGED') self:RegisterEvent('GUILD_ROSTER_UPDATE') self:RegisterEvent('MAIL_SHOW') self:RegisterEvent('MAIL_INBOX_UPDATE') self:RegisterEvent("AUCTION_HOUSE_SHOW") self:RegisterEvent("AUCTION_OWNED_LIST_UPDATE") --currency self:RegisterEvent('CURRENCY_DISPLAY_UPDATE') --void storage self:RegisterEvent('VOID_STORAGE_OPEN') self:RegisterEvent('VOID_STORAGE_CLOSE') self:RegisterEvent("VOID_STORAGE_UPDATE") self:RegisterEvent("VOID_STORAGE_CONTENTS_UPDATE") self:RegisterEvent("VOID_TRANSFER_DONE") --this will be used for getting the tradeskill link self:RegisterEvent("TRADE_SKILL_SHOW") SLASH_BAGSYNC1 = "/bagsync" SLASH_BAGSYNC2 = "/bgs" SlashCmdList["BAGSYNC"] = function(msg) local a,b,c=strfind(msg, "(%S+)"); --contiguous string of non-space characters if a then if c and c:lower() == L["search"] then if BagSync_SearchFrame:IsVisible() then BagSync_SearchFrame:Hide() else BagSync_SearchFrame:Show() end return true elseif c and c:lower() == L["gold"] then self:ShowMoneyTooltip() return true elseif c and c:lower() == L["tokens"] then if BagSync_TokensFrame:IsVisible() then BagSync_TokensFrame:Hide() else BagSync_TokensFrame:Show() end return true elseif c and c:lower() == L["profiles"] then if BagSync_ProfilesFrame:IsVisible() then BagSync_ProfilesFrame:Hide() else BagSync_ProfilesFrame:Show() end return true elseif c and c:lower() == L["professions"] then if BagSync_CraftsFrame:IsVisible() then BagSync_CraftsFrame:Hide() else BagSync_CraftsFrame:Show() end return true elseif c and c:lower() == L["blacklist"] then if BagSync_BlackListFrame:IsVisible() then BagSync_BlackListFrame:Hide() else BagSync_BlackListFrame:Show() end return true elseif c and c:lower() == L["fixdb"] then self:FixDB_Data() return true elseif c and c:lower() == L["config"] then InterfaceOptionsFrame_OpenToCategory("BagSync") return true elseif c and c:lower() ~= "" then --do an item search if BagSync_SearchFrame then if not BagSync_SearchFrame:IsVisible() then BagSync_SearchFrame:Show() end BagSync_SearchFrame.SEARCHBTN:SetText(msg) BagSync_SearchFrame:initSearch() end return true end end DEFAULT_CHAT_FRAME:AddMessage("BAGSYNC") DEFAULT_CHAT_FRAME:AddMessage(L["/bgs [itemname] - Does a quick search for an item"]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs search - Opens the search window"]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs gold - Displays a tooltip with the amount of gold on each character."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs tokens - Opens the tokens/currency window."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs profiles - Opens the profiles window."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs professions - Opens the professions window."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs blacklist - Opens the blacklist window."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs fixdb - Runs the database fix (FixDB) on BagSync."]) DEFAULT_CHAT_FRAME:AddMessage(L["/bgs config - Opens the BagSync Config Window"] ) end DEFAULT_CHAT_FRAME:AddMessage("|cFF99CC33BagSync|r [v|cFFDF2B2B"..ver.."|r] /bgs, /bagsync") --we deleted someone with the Profile Window, display name of user deleted if BagSyncOpt.delName then print("|cFFFF0000BagSync: "..L["Profiles"].." "..L["Delete"].." ["..BagSyncOpt.delName.."]!|r") BagSyncOpt.delName = nil end self:UnregisterEvent("PLAYER_LOGIN") self.PLAYER_LOGIN = nil end ------------------------------ -- Event Handlers -- ------------------------------ function BagSync:CURRENCY_DISPLAY_UPDATE() if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then return end doTokenUpdate = 0 ScanTokens() end function BagSync:PLAYER_REGEN_ENABLED() if IsInBG() or IsInArena() or InCombatLockdown() or UnitAffectingCombat("player") then return end self:UnregisterEvent("PLAYER_REGEN_ENABLED") --were out of an arena or battleground scan the points doTokenUpdate = 0 ScanTokens() end function BagSync:GUILD_ROSTER_UPDATE() if not IsInGuild() and BS_DB.guild then BS_DB.guild = nil self:FixDB_Data(true) elseif IsInGuild() then --if they don't have guild name store it or update it if GetGuildInfo("player") then if not BS_DB.guild or BS_DB.guild ~= GetGuildInfo("player") then BS_DB.guild = GetGuildInfo("player") self:FixDB_Data(true) end end end end function BagSync:PLAYER_MONEY() BS_DB.gold = GetMoney() end ------------------------------ -- BAG UPDATES -- ------------------------------ function BagSync:BAG_UPDATE(event, bagid) -- -1 happens to be the primary bank slot ;) if (bagid > BANK_CONTAINER) then --this will update the bank/bag slots local bagname --get the correct bag name based on it's id, trying NOT to use numbers as Blizzard may change bagspace in the future --so instead I'm using constants :) if ((bagid >= NUM_BAG_SLOTS + 1) and (bagid <= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS)) then bagname = 'bank' elseif (bagid >= BACKPACK_CONTAINER) and (bagid <= BACKPACK_CONTAINER + NUM_BAG_SLOTS) then bagname = 'bag' else return end if bagname == 'bank' and not atBank then return; end --now save the item information in the bag from bagupdate, this could be bag or bank SaveBag(bagname, bagid) end end function BagSync:UNIT_INVENTORY_CHANGED(event, unit) if unit == 'player' then SaveEquipment() end end ------------------------------ -- BANK -- ------------------------------ function BagSync:BANKFRAME_OPENED() atBank = true ScanEntireBank() end function BagSync:BANKFRAME_CLOSED() atBank = false end function BagSync:PLAYERBANKSLOTS_CHANGED(event, slotid) --Remove atBank when/if Blizzard allows Bank access without being at the bank if atBank then SaveBag('bank', BANK_CONTAINER) end end ------------------------------ -- REAGENT BANK -- ------------------------------ function BagSync:PLAYERREAGENTBANKSLOTS_CHANGED() SaveBag('reagentbank', REAGENTBANK_CONTAINER) end ------------------------------ -- VOID BANK -- ------------------------------ function BagSync:VOID_STORAGE_OPEN() atVoidBank = true ScanVoidBank() end function BagSync:VOID_STORAGE_CLOSE() atVoidBank = false end function BagSync:VOID_STORAGE_UPDATE() ScanVoidBank() end function BagSync:VOID_STORAGE_CONTENTS_UPDATE() ScanVoidBank() end function BagSync:VOID_TRANSFER_DONE() ScanVoidBank() end ------------------------------ -- GUILD BANK -- ------------------------------ function BagSync:GUILDBANKFRAME_OPENED() atGuildBank = true if not BagSyncOpt.enableGuild then return end local numTabs = GetNumGuildBankTabs() for tab = 1, numTabs do -- add this tab to the queue to refresh; if we do them all at once the server bugs and sends massive amounts of events local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(tab) if isViewable then guildTabQueryQueue[tab] = true end end end function BagSync:GUILDBANKFRAME_CLOSED() atGuildBank = false end function BagSync:GUILDBANKBAGSLOTS_CHANGED() if not BagSyncOpt.enableGuild then return end if atGuildBank then -- check if we need to process the queue local tab = next(guildTabQueryQueue) if tab then QueryGuildBankTab(tab) guildTabQueryQueue[tab] = nil else -- the bank is ready for reading ScanGuildBank() end end end ------------------------------ -- MAILBOX -- ------------------------------ function BagSync:MAIL_SHOW() if isCheckingMail then return end if not BagSyncOpt.enableMailbox then return end ScanMailbox() end function BagSync:MAIL_INBOX_UPDATE() if isCheckingMail then return end if not BagSyncOpt.enableMailbox then return end ScanMailbox() end ------------------------------ -- AUCTION HOUSE -- ------------------------------ function BagSync:AUCTION_HOUSE_SHOW() if not BagSyncOpt.enableAuction then return end ScanAuctionHouse() end function BagSync:AUCTION_OWNED_LIST_UPDATE() if not BagSyncOpt.enableAuction then return end BS_DB.AH_LastScan = time() ScanAuctionHouse() end ------------------------------ -- PROFESSION -- ------------------------------ function BagSync:TRADE_SKILL_SHOW() --IsTradeSkillLinked() returns true only if trade window was opened from chat link (meaning another player) if (not C_TradeSkillUI.IsTradeSkillLinked()) then local tradename = C_TradeSkillUI.GetTradeSkillLine() local prof1, prof2, archaeology, fishing, cooking, firstAid = GetProfessions() local iconProf1 = prof1 and select(2, GetProfessionInfo(prof1)) local iconProf2 = prof2 and select(2, GetProfessionInfo(prof2)) --list of tradeskills with NO skill link but can be used as primaries (ex. a person with two gathering skills) local noLinkTS = { ["Interface\\Icons\\Trade_Herbalism"] = true, --this is Herbalism ["Interface\\Icons\\INV_Misc_Pelt_Wolf_01"] = true, --this is Skinning ["Interface\\Icons\\INV_Pick_02"] = true, --this is Mining } --prof1 if prof1 and (GetProfessionInfo(prof1) == tradename) and C_TradeSkillUI.GetTradeSkillListLink() then local skill = select(3, GetProfessionInfo(prof1)) BS_CD[1] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif prof1 and iconProf1 and noLinkTS[iconProf1] then --only store if it's herbalism, skinning, or mining doRegularTradeSkill(prof1, 1) elseif not prof1 and BS_CD[1] then --they removed a profession BS_CD[1] = nil end --prof2 if prof2 and (GetProfessionInfo(prof2) == tradename) and C_TradeSkillUI.GetTradeSkillListLink() then local skill = select(3, GetProfessionInfo(prof2)) BS_CD[2] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif prof2 and iconProf2 and noLinkTS[iconProf2] then --only store if it's herbalism, skinning, or mining doRegularTradeSkill(prof2, 2) elseif not prof2 and BS_CD[2] then --they removed a profession BS_CD[2] = nil end --archaeology if archaeology then doRegularTradeSkill(archaeology, 3) elseif not archaeology and BS_CD[3] then --they removed a profession BS_CD[3] = nil end --fishing if fishing then doRegularTradeSkill(fishing, 4) elseif not fishing and BS_CD[4] then --they removed a profession BS_CD[4] = nil end --cooking if cooking and (GetProfessionInfo(cooking) == tradename) and C_TradeSkillUI.GetTradeSkillListLink() then local skill = select(3, GetProfessionInfo(cooking)) BS_CD[5] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif not cooking and BS_CD[5] then --they removed a profession BS_CD[5] = nil end --firstAid if firstAid and (GetProfessionInfo(firstAid) == tradename) and C_TradeSkillUI.GetTradeSkillListLink() then local skill = select(3, GetProfessionInfo(firstAid)) BS_CD[6] = { tradename, C_TradeSkillUI.GetTradeSkillListLink(), skill } elseif not firstAid and BS_CD[6] then --they removed a profession BS_CD[6] = nil end end end