--[[ Copyright (c) 2010, ckaotik All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of ckaotik nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ]]-- _, BrokerGarbage = ... -- Libraries & setting up the LDB -- --------------------------------------------------------- BrokerGarbage.PT = LibStub("LibPeriodicTable-3.1", true) -- don't scream if LPT isn't present -- notation mix-up for Broker2FuBar to work local LDB = LibStub("LibDataBroker-1.1"):NewDataObject("Broker_Garbage", { type = "data source", icon = "Interface\\Icons\\achievement_bg_returnxflags_def_wsg", label = "Garbage", text = "", OnClick = function(...) BrokerGarbage:OnClick(...) end, OnEnter = function(...) BrokerGarbage:Tooltip(...) end, OnLeave = function() end, -- needed for e.g. NinjaPanel }) local function UpdateLDB() BrokerGarbage.totalBagSpace, BrokerGarbage.totalFreeSlots, BrokerGarbage.specialSlots, BrokerGarbage.freeSpecialSlots = BrokerGarbage:GetBagSlots() if BrokerGarbage.cheapestItems[1] then LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBformat) else BrokerGarbage.cheapestItems[1] = nil LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBNoJunk) end end -- internal variables BrokerGarbage.optionsModules = {} -- used for ordering/showing entries in the options panel local locked = false -- set to true while selling stuff local sellValue = 0 -- represents the actual value that we sold stuff for local cost = 0 -- the amount of money that we repaired for local initialized = false -- Event Handler -- --------------------------------------------------------- local frame = CreateFrame("frame") local function eventHandler(self, event, arg1, ...) BrokerGarbage:Debug("EVENT", event, arg1, ...) if event == "ADDON_LOADED" and arg1 == "Broker_Garbage" then BrokerGarbage:CheckSettings() -- some default values initialization BrokerGarbage.isAtVendor = false BrokerGarbage.totalBagSpace = 0 BrokerGarbage.totalFreeSlots = 0 -- inventory database BrokerGarbage.itemsCache = {} BrokerGarbage.clamInInventory = false BrokerGarbage.containerInInventory = false -- full inventory scan to start with BrokerGarbage:ScanInventory() initialized = true frame:UnregisterEvent("ADDON_LOADED") elseif event == "BAG_UPDATE" and initialized then if not arg1 or arg1 < 0 or arg1 > 4 then return end BrokerGarbage:ScanInventoryContainer(arg1) -- partial inventory scan on the relevant container elseif event == "MERCHANT_SHOW" then BrokerGarbage.isAtVendor = true BrokerGarbage:UpdateRepairButton() local disable = BrokerGarbage.disableKey[BG_GlobalDB.disableKey] if not (disable and disable()) then BrokerGarbage:AutoRepair() BrokerGarbage:AutoSell() end elseif event == "MERCHANT_CLOSED" then BrokerGarbage.isAtVendor = false -- fallback unlock if locked then BrokerGarbage.isAtVendor = false locked = false BrokerGarbage:Debug("Fallback Unlock: Merchant window closed, scan lock released.") end elseif event == "AUCTION_HOUSE_CLOSED" then -- Update cached auction values if needed BrokerGarbage.itemsCache = {} elseif (locked or cost ~=0) and event == "PLAYER_MONEY" then -- regular unlock -- wrong player_money event (resulting from repair, not sell) if sellValue ~= 0 and cost ~= 0 and ((-1)*sellValue <= cost+2 and (-1)*sellValue >= cost-2) then BrokerGarbage:Debug("Not yet ... Waiting for actual money change.") return end if sellValue ~= 0 and cost ~= 0 and BG_GlobalDB.autoRepairAtVendor and BG_GlobalDB.autoSellToVendor then -- repair & auto-sell BrokerGarbage:Print(format(BrokerGarbage.locale.sellAndRepair, BrokerGarbage:FormatMoney(sellValue), BrokerGarbage:FormatMoney(cost), BrokerGarbage:FormatMoney(sellValue - cost) )) sellValue = 0 cost = 0 elseif cost ~= 0 and BG_GlobalDB.autoRepairAtVendor then -- repair only BrokerGarbage:Print(format(BrokerGarbage.locale.repair, BrokerGarbage:FormatMoney(cost))) cost = 0 elseif sellValue ~= 0 and BG_GlobalDB.autoSellToVendor then -- autosell only BrokerGarbage:Print(format(BrokerGarbage.locale.sell, BrokerGarbage:FormatMoney(sellValue))) sellValue = 0 end locked = false BrokerGarbage:Debug("Regular Unlock: Money received, scan lock released.") end end -- register events frame:RegisterEvent("ADDON_LOADED") frame:RegisterEvent("BAG_UPDATE") frame:RegisterEvent("MERCHANT_SHOW") frame:RegisterEvent("MERCHANT_CLOSED") frame:RegisterEvent("AUCTION_HOUSE_CLOSED") frame:RegisterEvent("PLAYER_MONEY") frame:SetScript("OnEvent", eventHandler) -- Sell Icon -- --------------------------------------------------------- function BrokerGarbage:UpdateRepairButton(...) if not BG_GlobalDB.showAutoSellIcon then if _G["BrokerGarbage_SellIcon"] then BrokerGarbage_SellIcon:Hide() end -- re-position all the buttons MerchantRepairAllButton:ClearAllPoints() MerchantGuildBankRepairButton:ClearAllPoints() MerchantGuildBankRepairButton:SetPoint("LEFT", MerchantRepairAllButton, "RIGHT", 4, 0) MerchantFrame_UpdateRepairButtons() return end local sellIcon -- show auto-sell icon on vendor frame if not _G["BrokerGarbage_SellIcon"] then sellIcon = CreateFrame("Button", "BrokerGarbage_SellIcon", MerchantFrame, "ItemButtonTemplate") SetItemButtonTexture(sellIcon, "Interface\\Icons\\achievement_bg_returnxflags_def_wsg") sellIcon:SetFrameStrata("HIGH") sellIcon:SetScript("OnClick", BrokerGarbage.AutoSell) sellIcon:SetScript("OnEnter", function(self) GameTooltip:SetOwner(self, "ANCHOR_RIGHT") local tiptext local junkValue = 0 for i = 0, 4 do junkValue = junkValue + (BrokerGarbage.toSellValue[i] or 0) end if junkValue ~= 0 then tiptext = format(BrokerGarbage.locale.autoSellTooltip, BrokerGarbage:FormatMoney(junkValue)) else tiptext = BrokerGarbage.locale.reportNothingToSell end GameTooltip:SetText(tiptext, nil, nil, nil, nil, true) end) sellIcon:SetScript("OnLeave", function() GameTooltip:Hide() end) else sellIcon = _G["BrokerGarbage_SellIcon"] end if MerchantBuyBackItemItemButton:IsVisible() then if CanMerchantRepair() then if CanGuildBankRepair() then -- move all the default icons further to the right. blizz anchors are weird -.- MerchantGuildBankRepairButton:ClearAllPoints() MerchantGuildBankRepairButton:SetPoint("RIGHT", MerchantBuyBackItemItemButton, "LEFT", -22, 0) MerchantRepairAllButton:ClearAllPoints() MerchantRepairAllButton:SetPoint("RIGHT", MerchantGuildBankRepairButton, "LEFT", -4, 0) end sellIcon:SetWidth(MerchantRepairAllButton:GetWidth()) sellIcon:SetHeight(MerchantRepairAllButton:GetHeight()) sellIcon:SetPoint("RIGHT", MerchantRepairItemButton, "LEFT", -4, 0) else sellIcon:SetWidth(MerchantBuyBackItemItemButton:GetWidth()) sellIcon:SetHeight(MerchantBuyBackItemItemButton:GetHeight()) sellIcon:SetPoint("RIGHT", MerchantBuyBackItemItemButton, "LEFT", -18, 0) end MerchantRepairText:Hide() sellIcon:Show() else sellIcon:Hide() end local junkValue = 0 for i = 0, 4 do junkValue = junkValue + (BrokerGarbage.toSellValue[i] or 0) end SetItemButtonDesaturated(_G["BrokerGarbage_SellIcon"], junkValue == 0) end hooksecurefunc("MerchantFrame_Update", BrokerGarbage.UpdateRepairButton) -- Tooltip -- --------------------------------------------------------- function BrokerGarbage:Tooltip(self) local colNum = BG_GlobalDB.showSource and 4 or 3 BrokerGarbage.tt = LibStub("LibQTip-1.0"):Acquire("BrokerGarbage_TT", colNum, "LEFT", "RIGHT", "RIGHT", colNum == 4 and "CENTER" or nil) BrokerGarbage.tt:Clear() -- font settings local tooltipHFont = CreateFont("TooltipHeaderFont") tooltipHFont:SetFont(GameTooltipText:GetFont(), 14) tooltipHFont:SetTextColor(1,1,1) local tooltipFont = CreateFont("TooltipFont") tooltipFont:SetFont(GameTooltipText:GetFont(), 11) tooltipFont:SetTextColor(255/255,176/255,25/255) -- add header lines BrokerGarbage.tt:SetHeaderFont(tooltipHFont) BrokerGarbage.tt:AddHeader('Broker_Garbage', '', BrokerGarbage.locale.headerRightClick) -- add info lines BrokerGarbage.tt:SetFont(tooltipFont) BrokerGarbage.tt:AddLine(BrokerGarbage.locale.headerShiftClick, '', BrokerGarbage.locale.headerCtrlClick) BrokerGarbage.tt:AddSeparator(2) -- add clam information if IsAddOnLoaded("Broker_Garbage-LootManager") and ( (BGLM_GlobalDB.openContainers and BrokerGarbage.containerInInventory) or (BGLM_GlobalDB.openClams and BrokerGarbage.clamInInventory)) then if BGLM_GlobalDB.openContainers and BrokerGarbage.containerInInventory then lineNum = BrokerGarbage.tt:AddLine() BrokerGarbage.tt:SetCell(lineNum, 1, BrokerGarbage_LootManager.locale.openPlease, tooltipFont, "CENTER", colNum) end if BGLM_GlobalDB.openClams and BrokerGarbage.clamInInventory then lineNum = BrokerGarbage.tt:AddLine() BrokerGarbage.tt:SetCell(lineNum, 1, BrokerGarbage_LootManager.locale.openClams, tooltipFont, "CENTER", colNum) end BrokerGarbage.tt:AddSeparator(2) end -- shows up to n lines of deletable items local lineNum local cheapList = BrokerGarbage.cheapestItems or {} for i = 1, #cheapList do -- adds lines: itemLink, count, itemPrice, source lineNum = BrokerGarbage.tt:AddLine( select(2,GetItemInfo(cheapList[i].itemID)), cheapList[i].count, BrokerGarbage:FormatMoney(cheapList[i].value), (BG_GlobalDB.showSource and BrokerGarbage.tag[cheapList[i].source] or nil)) BrokerGarbage.tt:SetLineScript(lineNum, "OnMouseDown", BrokerGarbage.OnClick, cheapList[i]) end if lineNum == nil then BrokerGarbage.tt:AddLine(BrokerGarbage.locale.noItems, '', BrokerGarbage.locale.increaseTreshold) end -- add statistics information if (BG_GlobalDB.showLost and BG_LocalDB.moneyLostByDeleting ~= 0) or (BG_GlobalDB.showEarned and BG_LocalDB.moneyEarned ~= 0) then BrokerGarbage.tt:AddSeparator(2) if BG_LocalDB.moneyLostByDeleting ~= 0 then BrokerGarbage.tt:AddLine(BrokerGarbage.locale.moneyLost, '', BrokerGarbage:FormatMoney(BG_LocalDB.moneyLostByDeleting)) end if BG_LocalDB.moneyEarned ~= 0 then BrokerGarbage.tt:AddLine(BrokerGarbage.locale.moneyEarned, '', BrokerGarbage:FormatMoney(BG_LocalDB.moneyEarned)) end end -- Use smart anchoring code to anchor the tooltip to our frame BrokerGarbage.tt:SmartAnchorTo(self) BrokerGarbage.tt:SetAutoHideDelay(0.25, self) -- Show it, et voilà ! BrokerGarbage.tt:Show() BrokerGarbage.tt:UpdateScrolling(BG_GlobalDB.tooltipMaxHeight) end -- onClick function - works for both, the LDB plugin -and- tooltip lines function BrokerGarbage:OnClick(itemTable, button) BrokerGarbage.debug1 = itemTable BrokerGarbage.debug2 = button -- handle LDB clicks seperately local LDBclick = false if not itemTable or not itemTable.itemID or type(itemTable.itemID) ~= "number" then BrokerGarbage:Debug("Click on LDB") itemTable = BrokerGarbage.cheapestItems and BrokerGarbage.cheapestItems[1] LDBclick = true end -- handle different clicks if itemTable and IsShiftKeyDown() then -- delete or sell item, depending on if we're at a vendor or not if BrokerGarbage.isAtVendor and itemTable.value > 0 then BrokerGarbage:Debug("At vendor, selling "..itemTable.itemID) BG_GlobalDB.moneyEarned = BG_GlobalDB.moneyEarned + itemTable.value BG_LocalDB.moneyEarned = BG_LocalDB.moneyEarned + itemTable.value BG_GlobalDB.itemsSold = BG_GlobalDB.itemsSold + itemTable.count ClearCursor() UseContainerItem(itemTable.bag, itemTable.slot) else BrokerGarbage:Debug("Not at vendor", "Deleting") BrokerGarbage:Delete(itemTable) end --[[elseif itemTable and IsAltKeyDown() and IsControlKeyDown() then -- disenchant local itemLink = select(2, GetItemInfo(itemTable.itemID)) if BrokerGarbage:CanDisenchant(itemLink, true) then -- Disenchant: 13262 end]]-- elseif itemTable and IsControlKeyDown() then -- add to exclude list if not BG_LocalDB.exclude[itemTable.itemID] then BG_LocalDB.exclude[itemTable.itemID] = true end BrokerGarbage:Print(format(BrokerGarbage.locale.addedTo_exclude, select(2,GetItemInfo(itemTable.itemID)))) BrokerGarbage.itemsCache = {} if BrokerGarbage.optionsLoaded then BrokerGarbage:ListOptionsUpdate("exclude") end BrokerGarbage:ScanInventory() elseif itemTable and IsAltKeyDown() then -- add to force vendor price list BG_GlobalDB.forceVendorPrice[itemTable.itemID] = true BrokerGarbage:Print(format(BrokerGarbage.locale.addedTo_forceVendorPrice, select(2,GetItemInfo(itemTable.itemID)))) BrokerGarbage.itemsCache = {} if BrokerGarbage.optionsLoaded then BrokerGarbage:ListOptionsUpdate("forceprice") end BrokerGarbage:ScanInventory() elseif button == "RightButton" then -- open config InterfaceOptionsFrame_OpenToCategory(BrokerGarbage.options.name) elseif LDBclick then -- click on the LDB to rescan BrokerGarbage:ScanInventory() end UpdateLDB() end -- Item Value Calculation -- --------------------------------------------------------- -- calculates the value of a stack/partial stack of an item function BrokerGarbage:GetItemValue(item, count) local itemID if item and type(item) == "number" then itemID = item elseif item and type(item) == "string" then itemID = BrokerGarbage:GetItemID(item) else -- invalid argument BrokerGarbage:Debug("GetItemValue: Invalid argument "..(item or "<none>").."supplied.") return nil end if BrokerGarbage:GetCached(itemID) then return BrokerGarbage:GetCached(itemID).value * (count or 1) else local value = BrokerGarbage:GetSingleItemValue(item) return value and value * (count or 1) or nil end end -- returns which of the items values is the highest (value, type) function BrokerGarbage:GetSingleItemValue(item) if not item then return nil end local hasData, itemLink, itemQuality, itemLevel, _, _, _, _, itemType, _, vendorPrice = GetItemInfo(item) BrokerGarbage:Debug("GetSingleItemValue("..(item or "?").."), "..(hasData or "no data")) hasData, itemLink, itemQuality, itemLevel, _, _, _, _, itemType, _, vendorPrice = GetItemInfo(item) if not hasData then -- invalid argument BrokerGarbage:Debug("Error! GetSingleItemValue: Failed on "..(itemLink or item or "<unknown>").."."..(hasData or "no data")) return nil end -- ignore AH prices for gray items if not itemQuality or itemQuality == 0 then return vendorPrice, vendorPrice and BrokerGarbage.VENDOR end BrokerGarbage.auctionAddon = nil -- reset this! local disenchantPrice, auctionPrice, source = 0, 0, nil local canDE = BrokerGarbage:CanDisenchant(itemLink) -- calculate auction value: choose the highest auction/disenchant value if IsAddOnLoaded("Auctionator") then BrokerGarbage.auctionAddon = "Auctionator" auctionPrice = Atr_GetAuctionBuyout(itemLink) or 0 disenchantPrice = canDE and Atr_GetDisenchantValue(itemLink) end if IsAddOnLoaded("Auc-Advanced") then -- uses Market Value in any case BrokerGarbage.auctionAddon = (BrokerGarbage.auctionAddon and BrokerGarbage.auctionAddon..", " or "") .. "Auc-Advanced" auctionPrice = math.max(auctionPrice, AucAdvanced.API.GetMarketValue(itemLink)) if IsAddOnLoaded("Enchantrix") then disenchantPrice = canDE and math.max(disenchantPrice, select(3, Enchantrix.Storage.GetItemDisenchantTotals(itemLink))) end end if IsAddOnLoaded("AuctionLite") then BrokerGarbage.auctionAddon = (BrokerGarbage.auctionAddon and BrokerGarbage.auctionAddon..", " or "") .. "AuctionLite" auctionPrice = math.max(auctionPrice, AuctionLite:GetAuctionValue(itemLink) or 0) disenchantPrice = canDE and math.max(disenchantPrice, AuctionLite:GetDisenchantValue(itemLink) or 0) end if IsAddOnLoaded("WOWEcon_PriceMod") then BrokerGarbage.auctionAddon = (BrokerGarbage.auctionAddon and BrokerGarbage.auctionAddon..", " or "") .. "WoWecon" auctionPrice = math.max(auctionPrice, Wowecon.API.GetAuctionPrice_ByLink(itemLink) or 0) if canDE and not disenchantPrice then local tmpPrice = 0 local DEData = Wowecon.API.GetDisenchant_ByLink(itemLink) for i, data in pairs(DEData) do -- [1] = item link, [2] = quantity, [3] = chance tmpPrice = tmpPrice + (Wowecon.API.GetAuctionPrice_ByLink(data[1]) * data[2] * data[3]) end disenchantPrice = math.max(disenchantPrice, math.floor(tmpPrice)) end end -- last chance to get auction values if GetAuctionBuyout then BrokerGarbage.auctionAddon = BrokerGarbage.auctionAddon or BrokerGarbage.locale.unknown auctionPrice = math.max(auctionPrice, GetAuctionBuyout(itemLink) or 0) else BrokerGarbage.auctionAddon = BrokerGarbage.auctionAddon or BrokerGarbage.locale.na end if GetDisenchantValue then disenchantPrice = canDE and math.max(disenchantPrice, GetDisenchantValue(itemLink) or 0) end -- simply return the highest value price local maximum = math.max((disenchantPrice or 0), (auctionPrice or 0), (vendorPrice or 0)) if vendorPrice and maximum == vendorPrice then return vendorPrice, BrokerGarbage.VENDOR elseif auctionPrice and maximum == auctionPrice then return auctionPrice, BrokerGarbage.AUCTION elseif disenchantPrice and maximum == disenchantPrice then return disenchantPrice, BrokerGarbage.DISENCHANT else return nil, nil end end -- finds all occurences of the given item and returns the least important location function BrokerGarbage:FindSlotToDelete(itemID, ignoreFullStack) local locations = {} local _, _, _, _, _, _, _, maxStack = GetItemInfo(itemID) local numSlots, freeSlots, ratio, bagType for container = 0,4 do numSlots = GetContainerNumSlots(container) freeSlots, bagType = GetContainerFreeSlots(container) freeSlots = freeSlots and #freeSlots or 0 if numSlots then ratio = freeSlots/numSlots for slot = 1, numSlots do local _,count,_,_,_,_,link = GetContainerItemInfo(container, slot) if link and BrokerGarbage:GetItemID(link) == itemID then if not ignoreFullStack or (ignoreFullStack and count < maxStack) then -- found one table.insert(locations, { slot = slot, bag = container, count = count, ratio = ratio, bagType = (bagType or 0) }) end end end end end -- recommend the location with the largest count or ratio that is NOT a specialty bag table.sort(locations, function(a,b) if a.bagType ~= b.bagType then return a.bagType == 0 else if a.count == b.count then return a.ratio > b.ratio else return a.count < b.count end end end) return locations end -- deletes the item in a given location of your bags function BrokerGarbage:Delete(item, position) local itemID, itemCount, cursorType if type(item) == "string" and item == "cursor" then -- item on the cursor cursorType, itemID = GetCursorInfo() if cursorType ~= "item" then BrokerGarbage:Print("Error! Trying to delete an item from the cursor, but there is none.") return end itemCount = position -- second argument is the item count elseif type(item) == "table" then -- item given as an itemTable itemID = item.itemID position = {item.bag, item.slot} elseif type(item) == "number" then -- item given via its itemID itemID = item elseif item then -- item given via its itemLink itemID = BrokerGarbage:GetItemID(item) else BrokerGarbage:Print("Error! BrokerGarbage:Delete() no argument supplied.") return end -- security check if not cursorType and GetContainerItemID(position[1] or item.bag, position[2] or item.slot) ~= itemID then BrokerGarbage:Print("Error! Item to be deleted is not the expected item.") return end -- make sure there is nothing unwanted on the cursor if not cursorType then ClearCursor() end if not cursorType and (not position or type(position) ~= "table") then BrokerGarbage:Print("Error! No position given to delete from.") return else _, itemCount = GetContainerItemInfo(position[1], position[2]) end -- actual deleting happening after this securecall(PickupContainerItem, position[1], position[2]) securecall(DeleteCursorItem) -- comment this line to prevent item deletion local itemValue = (BrokerGarbage:GetCached(itemID).value or 0) * itemCount -- if an item is unknown to the cache, statistics will not change -- statistics BG_GlobalDB.itemsDropped = BG_GlobalDB.itemsDropped + itemCount BG_GlobalDB.moneyLostByDeleting = BG_GlobalDB.moneyLostByDeleting + itemValue BG_LocalDB.moneyLostByDeleting = BG_LocalDB.moneyLostByDeleting + itemValue local _, itemLink = GetItemInfo(itemID) BrokerGarbage:Print(format(BrokerGarbage.locale.itemDeleted, itemLink, itemCount)) end -- Inventory Scanning -- --------------------------------------------------------- -- only used as a shortcut to cache any unknown item in the whole inventory function BrokerGarbage:ScanInventory() for container = 0,4 do BrokerGarbage:ScanInventoryContainer(container) end if BrokerGarbage.isAtVendor then BrokerGarbage:UpdateRepairButton() end end -- scans your inventory bags for possible junk items and updates LDB display function BrokerGarbage:ScanInventoryContainer(container) -- container doesn't exist or cannot be scanned if not GetContainerNumSlots(container) then return end local numSlots = GetContainerNumSlots(container) BrokerGarbage.toSellValue[container] = 0 for slot = 1, numSlots do local itemID = GetContainerItemID(container,slot) local item = BrokerGarbage:GetCached(itemID) if itemID and item then -- update toSellValue if item.classification == BrokerGarbage.VENDORLIST or (item.classification == BrokerGarbage.UNUSABLE and BG_GlobalDB.sellNotWearable and item.quality <= BG_GlobalDB.sellNWQualityTreshold) or (BG_GlobalDB.autoSellIncludeItems and item.classification == BrokerGarbage.INCLUDE) or (item.classification ~= BrokerGarbage.EXCLUDE and item.quality == 0) then local itemCount = select(2, GetContainerItemInfo(container, slot)) BrokerGarbage.toSellValue[container] = BrokerGarbage.toSellValue[container] + item.value * itemCount end end end BrokerGarbage:GetCheapest() UpdateLDB() end -- Find Cheap Items -- --------------------------------------------------------- local function TableSort(a, b) -- put included items even prior to forced vendor price items if (a.source == b.source) or (a.source ~= BrokerGarbage.INCLUDE and b.source ~= BrokerGarbage.INCLUDE) or BG_GlobalDB.useRealValues then if a.value == b.value then if a.itemID == b.itemID then return a.count < b.count else return a.itemID < b.itemID end else return a.value < b.value end else return a.source == BrokerGarbage.INCLUDE end end -- returns the n cheapest items in your bags in a table function BrokerGarbage:GetCheapest(number) if not number then number = BG_GlobalDB.tooltipNumItems end local cheapestItems = {} local numSlots, count, quality, canOpen, itemLink, itemID, stackSize local item, maxValue, insert BrokerGarbage.clamInInventory = false BrokerGarbage.containerInInventory = false for container = 0, 4 do numSlots = GetContainerNumSlots(container) if numSlots then for slot = 1, numSlots do -- "Gather Information" _, count, _, _, _, canOpen, itemLink = GetContainerItemInfo(container, slot) itemID = itemLink and BrokerGarbage:GetItemID(itemLink) item = itemID and BrokerGarbage:GetCached(itemID) if item then insert = true local value = count * item.value local vendorValue = select(11, GetItemInfo(itemID)) * count local classification = item.classification -- remember lootable items if canOpen or (item and item.isClam) then if item.isClam then BrokerGarbage.clamInInventory = true else BrokerGarbage.containerInInventory = true end end -- handle different types of items if not item or item.classification == BrokerGarbage.EXCLUDE then insert = false elseif item.classification == BrokerGarbage.LIMITED then local saveStacks = ceil(item.limit/(item.stackSize or 1)) local locations = BrokerGarbage:FindSlotToDelete(itemID) if #locations > saveStacks then local itemCount = 0 for i = #locations, 1, -1 do if itemCount < item.limit then -- keep this amount itemCount = itemCount + locations[i].count if locations[i].bag == container and locations[i].slot == slot then insert = false end else break; end end else insert = false end if insert then -- treat like a regular include item value = BG_GlobalDB.useRealValues and value or 0 end elseif item.classification == BrokerGarbage.DISENCHANT or item.classification == BrokerGarbage.AUCTION then -- check if item is really soulbound if BrokerGarbage:IsItemSoulbound(itemID, container, slot) then -- use vendor price instead value = vendorValue classification = BrokerGarbage.VENDOR end elseif item.classification == BrokerGarbage.UNUSABLE then if not BG_GlobalDB.sellNotWearable or item.quality > BG_GlobalDB.sellNWQualityTreshold then insert = false end elseif item.classification == BrokerGarbage.INCLUDE then value = BG_GlobalDB.useRealValues and value or 0 elseif item.classification == BrokerGarbage.VENDORLIST or item.classification == BrokerGarbage.VENDOR then value = vendorValue end if item.quality > BG_GlobalDB.dropQuality and not (classification == BrokerGarbage.INCLUDE or classification == BrokerGarbage.VENDORLIST) then -- include and vendor list items should always be displayed insert = false elseif value == 0 and BG_GlobalDB.hideZeroValue and classification == BrokerGarbage.VENDOR then insert = false end -- insert data if insert then maxValue = cheapestItems[number] and cheapestItems[number].value or nil if not maxValue then tinsert(cheapestItems, { itemID = itemID, bag = container, slot = slot, count = count, value = value, source = classification, }) elseif value < maxValue then -- update last item cheapestItems[number].itemID = itemID cheapestItems[number].bag = container cheapestItems[number].slot = slot cheapestItems[number].count = count cheapestItems[number].value = value cheapestItems[number].source = classification end table.sort(cheapestItems, TableSort) end end end end end BrokerGarbage.cheapestItems = cheapestItems return cheapestItems end -- special functionality -- --------------------------------------------------------- -- when at a merchant this will clear your bags of junk (gray quality) and items on your autoSellList function BrokerGarbage:AutoSell() if not BrokerGarbage.isAtVendor then return end if self == _G["BrokerGarbage_SellIcon"] then BrokerGarbage:Debug("AutoSell was triggered by a click on Sell Icon.") elseif not BG_GlobalDB.autoSellToVendor then -- we're not supposed to sell. jump out return end local sell, classification local item, itemID, value, count, numSlots sellValue = 0 for container = 0, 4 do numSlots = GetContainerNumSlots(container) if numSlots then for slot = 1, numSlots do _, count, _, _, _, _, itemLink = GetContainerItemInfo(container, slot) itemID = BrokerGarbage:GetItemID(itemLink) if itemLink and BrokerGarbage:GetCached(itemID) then item = BrokerGarbage:GetCached(itemID) value = item.value sell = false -- various cases that have us sell this item if item.classification == BrokerGarbage.UNUSABLE then if BG_GlobalDB.sellNotWearable and item.quality <= BG_GlobalDB.sellNWQualityTreshold then sell = true end elseif item.classification == BrokerGarbage.INCLUDE and BG_GlobalDB.autoSellIncludeItems then sell = true elseif item.classification == BrokerGarbage.VENDORLIST then sell = true elseif item.classification ~= BrokerGarbage.EXCLUDE and item.quality == 0 then sell = true end -- Actual Selling if value ~= 0 and sell then if not locked then BrokerGarbage:Debug("Inventory scans locked") locked = true end BrokerGarbage:Debug("Selling", itemID) ClearCursor() UseContainerItem(container, slot) sellValue = sellValue + (count * value) -- update statistics BG_GlobalDB.moneyEarned = BG_GlobalDB.moneyEarned + (count * value) BG_LocalDB.moneyEarned = BG_LocalDB.moneyEarned + (count * value) BG_GlobalDB.itemsSold = BG_GlobalDB.itemsSold + count end end end end end -- create output if needed if self == _G["BrokerGarbage_SellIcon"] then if sellValue == 0 and BG_GlobalDB.reportNothingToSell then BrokerGarbage:Print(BrokerGarbage.locale.reportNothingToSell) elseif sellValue ~= 0 and not BG_GlobalDB.autoSellToVendor then BrokerGarbage:Print(format(BrokerGarbage.locale.sell, BrokerGarbage:FormatMoney(sellValue))) end _G["BrokerGarbage_SellIcon"]:GetNormalTexture():SetDesaturated(true) end BrokerGarbage:UpdateRepairButton() end -- automatically repair at a vendor function BrokerGarbage:AutoRepair() if BG_GlobalDB.autoRepairAtVendor and CanMerchantRepair() then cost = GetRepairAllCost() local money = GetMoney() if cost > 0 and CanGuildBankRepair() and GetGuildBankWithdrawMoney() >= cost and not BG_LocalDB.neverRepairGuildBank then -- guild repair if we're allowed to and the user wants it RepairAllItems(1) elseif cost > 0 and money >= cost then -- not enough allowance to guild bank repair, pay ourselves RepairAllItems(0) elseif cost > 0 then -- oops. give us your moneys! BrokerGarbage:Print(format(BrokerGarbage.locale.couldNotRepair, BrokerGarbage:FormatMoney(cost))) end else cost = 0 end end