You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
26 KiB

4 years ago
-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_Mailing --
-- http://www.curse.com/addons/wow/tradeskillmaster_mailing --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
local TSM = select(2, ...)
local Inbox = TSM:NewModule("Inbox", "AceEvent-3.0", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Mailing") -- loads the localization table
local private = { recheckTime = 1, allowTimerStart = true, lootIndex = 1, freeSlots = true }
function Inbox:OnEnable()
Inbox:RegisterEvent("MAIL_SHOW")
TSMAPI:CreateEventBucket("MAIL_INBOX_UPDATE", private.InboxUpdate, 0.3)
Inbox:RegisterEvent("MAIL_CLOSED")
end
function Inbox:CreateTab(parent)
local frame = CreateFrame("Frame", nil, parent)
frame:Hide()
frame:SetAllPoints()
frame:SetScript("OnHide", function() private:StopAutoLooting() end)
frame:SetScript("OnShow", private.InboxUpdate)
local label = TSMAPI.GUI:CreateLabel(frame, "small")
label:SetPoint("TOPLEFT", 5, -5)
label:SetPoint("TOPRIGHT", -5, -5)
label:SetHeight(15)
label:SetJustifyH("CENTER")
label:SetJustifyV("CENTER")
frame.topLabel = label
TSMAPI.GUI:CreateHorizontalLine(frame, -25)
local stContainer = CreateFrame("Frame", nil, frame)
stContainer:SetPoint("TOPLEFT", 5, -35)
stContainer:SetPoint("BOTTOMRIGHT", -5, 55)
TSMAPI.Design:SetFrameColor(stContainer)
local handlers = {
OnClick = function(_, data)
if IsShiftKeyDown() and select(6, GetInboxHeaderInfo(data.index)) <= 0 then
if private:CanLootMailIndex(data.index) then
private:LootMailItem(data.index)
else
TSM:Print(L["Could not loot item from mail because your bags are full."])
end
end
if InboxFrame.openMailID ~= data.index then
InboxFrame.openMailID = data.index
OpenMailFrame.updateButtonPositions = true
OpenMail_Update()
ShowUIPanel(OpenMailFrame)
OpenMailFrame:SetPoint("TOPLEFT", InboxFrame, "TOPRIGHT", 32, 0)
PlaySound("igSpellBookOpen")
else
InboxFrame.openMailID = 0
HideUIPanel(OpenMailFrame)
end
InboxFrame_Update()
end,
OnEnter = function(_, data, self)
end,
OnLeave = function()
end,
}
local st = TSMAPI:CreateScrollingTable(stContainer, nil, handlers)
st:SetData({})
frame.st = st
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", 5, 30)
btn:SetPoint("BOTTOMRIGHT", -5, 30)
btn:SetHeight(20)
btn:SetText(L["Open All Mail"])
btn:SetScript("OnClick", function() private:StartAutoLooting("all") end)
frame.allBtn = btn
local label = TSMAPI.GUI:CreateLabel(frame, "normal")
label:SetPoint("BOTTOMLEFT", 5, 5)
label:SetHeight(20)
label:SetJustifyH("LEFT")
label:SetJustifyV("CENTER")
label:SetText(L["AH Mail:"])
local btnWidth = (frame:GetWidth() - label:GetWidth() - 25) / 5
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", label, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth)
btn:SetHeight(20)
btn:SetText(L["Sales"])
btn:SetScript("OnClick", function() private:StartAutoLooting("sales") end)
frame.salesBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", frame.salesBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth)
btn:SetHeight(20)
btn:SetText(L["Buys"])
btn:SetScript("OnClick", function() private:StartAutoLooting("buys") end)
frame.buysBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", frame.buysBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth)
btn:SetHeight(20)
btn:SetText(L["Cancels"])
btn:SetScript("OnClick", function() private:StartAutoLooting("cancels") end)
frame.cancelsBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", frame.cancelsBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth)
btn:SetHeight(20)
btn:SetText(L["Expires"])
btn:SetScript("OnClick", function() private:StartAutoLooting("expires") end)
frame.expiresBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18)
btn:SetPoint("BOTTOMLEFT", frame.expiresBtn, "BOTTOMRIGHT", 5, 0)
btn:SetPoint("BOTTOMRIGHT", -5, 5)
btn:SetHeight(20)
btn:SetText("Pending")
btn:SetScript("OnClick", function() private:StartAutoLooting("pendings") end)
frame.expiresBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 16)
btn:SetFrameStrata("HIGH")
btn:SetPoint("CENTER")
btn:SetHeight(30)
btn:SetWidth(150)
btn:SetText(L["Reload UI"])
btn:SetScript("OnClick", ReloadUI)
btn:Hide()
frame.reloadBtn = btn
frame.EnableButtons = function(self)
self.allBtn:Enable()
self.salesBtn:Enable()
self.buysBtn:Enable()
self.cancelsBtn:Enable()
self.expiresBtn:Enable()
self.buttonsEnabled = true
end
frame.DisableButtons = function(self)
self.allBtn:Disable()
self.salesBtn:Disable()
self.buysBtn:Disable()
self.cancelsBtn:Disable()
self.expiresBtn:Disable()
self.buttonsEnabled = nil
end
frame.buttonsEnabled = true
private.frame = frame
return frame
end
local function CacheFrameOnUpdate(self, elapsed)
if not private.waitingForData then
local seconds = self.endTime - GetTime()
if seconds <= 0 then
-- Look for new mail
-- Sometimes it fails and isn't available at exactly 60-61 seconds, and more like 62-64, will keep rechecking every 1 second
-- until data becomes available
if TSM.db.global.autoCheck then
private.waitingForData = true
self.timeLeft = private.recheckTime
private.lootIndex = 1
private.resetIndex = nil
CheckInbox()
private.frame.reloadBtn:Hide()
else
self:Hide()
end
return
end
private:UpdateTopLabel()
else
self.timeLeft = self.timeLeft - elapsed
if self.timeLeft <= 0 then
self.timeLeft = private.recheckTime
private.lootIndex = 1
private.resetIndex = nil
CheckInbox()
private.frame.reloadBtn:Hide()
end
end
end
function Inbox:MAIL_SHOW()
if not private.cacheFrame then
-- Timer for mailbox cache updates
private.cacheFrame = CreateFrame("Frame", nil, MailFrame)
private.cacheFrame:Hide()
private.cacheFrame:SetScript("OnUpdate", CacheFrameOnUpdate)
end
end
local function FormatDaysLeft(daysLeft, index)
-- code taken from Blizzard MailFrame.lua code
if daysLeft >= 1 then
if InboxItemCanDelete(index) then
daysLeft = YELLOW_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE;
else
daysLeft = GREEN_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE;
end
else
daysLeft = RED_FONT_COLOR_CODE .. SecondsToTime(floor(daysLeft * 24 * 60 * 60)) .. FONT_COLOR_CODE_CLOSE;
end
return daysLeft
end
function private:UpdateTopLabel()
local parts = {}
local numMail, totalMail = GetInboxNumItems()
if totalMail == numMail then
tinsert(parts, format(L["Showing all %d mail."], numMail))
else
tinsert(parts, format(L["Showing %d of %d mail."], numMail, totalMail))
end
local collectGold = private.collectGold or 0
if collectGold > 0 then
tinsert(parts, format(L["%s to collect."], TSMAPI:FormatTextMoney(collectGold)))
end
local nextRefresh = private.cacheFrame:IsVisible() and private.cacheFrame.endTime
if nextRefresh then
if numMail == 0 and TSM.db.global.showReloadBtn then
private.frame.reloadBtn:Show()
end
tinsert(parts, format(L["Next inbox update in %d seconds."], max(ceil(nextRefresh - GetTime()), 0)))
end
private.frame.topLabel:SetText(table.concat(parts, " "))
end
function private:InboxUpdate()
if not private.frame or not private.frame:IsVisible() then return end
TSMAPI:CancelFrame("inboxLootTextDelay")
local numMail, totalMail = GetInboxNumItems()
local greenColor, redColor, yellowColor = "|cff00ff00", "|cffff0000", "|cffeeff00"
local mailInfo = {}
local collectGold = 0
for i = 1, numMail do
mailInfo[i] = ""
local isInvoice = select(4, GetInboxText(i))
--local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index)
local _, _, sender, subject, money, cod, daysLeft, hasItem, _, _, _, _, _, itemQuantity = GetInboxHeaderInfo(i)
if isInvoice then
local invoiceType, itemName, playerName, bid, buyout, deposit, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(i)
sender = sender or "?"
if sender == "Blackwater Auction House" then sender = "AH" end
if not quantity then
quantity = select(3, GetInboxItem(i))
end
4 years ago
-- fix MoP difference
if invoiceType == "buyer" then
local itemLink = GetInboxItemLink(i, 1) or itemName
mailInfo[i] = format(L["Buy: %s (%d) | %s | %s"], itemLink, quantity or 1, TSMAPI:FormatTextMoney(bid, redColor), FormatDaysLeft(daysLeft, i))
4 years ago
elseif invoiceType == "seller" then
collectGold = collectGold + bid - ahcut
mailInfo[i] = format(L["Sale: %s (%d) | %s | %s"], itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i))
-- mailInfo[i] = format("Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i))
4 years ago
elseif invoiceType == "seller_temp_invoice" then
mailInfo[i] = format("Pending Sale: %s (%d) | %s | %s", itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor), FormatDaysLeft(daysLeft, i))
-- mailInfo[i] = format("Pending Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor), FormatDaysLeft(daysLeft, i))
4 years ago
end
elseif hasItem then
local itemLink
local quantity = 0
for j = 1, hasItem do
local link = GetInboxItemLink(i, j)
itemLink = itemLink or link
quantity = quantity + select(3, GetInboxItem(i, j))
if TSMAPI:GetItemString(itemLink) ~= TSMAPI:GetItemString(link) then
itemLink = L["Multiple Items"]
quantity = -1
break
end
end
local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and L["Multiple Items"]) or "---"
if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then
mailInfo[i] = format(L["Expired: %s | %s"], itemDesc, FormatDaysLeft(daysLeft, i))
elseif cod > 0 then
mailInfo[i] = format(L["COD: %s | %s | %s | %s"], itemDesc, TSMAPI:FormatTextMoney(cod, redColor), sender or "---", FormatDaysLeft(daysLeft, i))
elseif money > 0 then
collectGold = collectGold + money
mailInfo[i] = format("%s + %s | %s | %s", itemDesc, TSMAPI:FormatTextMoney(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i))
else
mailInfo[i] = format("%s | %s | %s", itemDesc, sender or "---", FormatDaysLeft(daysLeft, i))
end
elseif money > 0 then
mailInfo[i] = format("%s | %s | %s | %s", subject, TSMAPI:FormatTextMoney(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i))
else
mailInfo[i] = format("%s | %s | %s", subject, sender or "---", FormatDaysLeft(daysLeft, i))
end
end
private.collectGold = collectGold
local stData = {}
for i, info in ipairs(mailInfo) do
tinsert(stData, { cols = { { value = info } }, index = i })
end
private.frame.st:SetData(stData)
private:UpdateTopLabel()
-- -- Yay nothing else to loot, so nothing else to update the cache for!
-- if private.cacheFrame.endTime and numMail == totalMail and private.lastTotal ~= totalMail then
-- private.cacheFrame.endTime = nil
-- private.cacheFrame:Hide()
-- -- Start a timer since we're over the limit of 50 items before waiting for it to recache
-- elseif (private.cacheFrame.endTime and numMail >= 50 and private.lastTotal ~= totalMail) or (numMail >= 50 and private.allowTimerStart) then
-- private.resetIndex = nil
-- private.allowTimerStart = nil
-- private.waitingForData = nil
-- private.lastTotal = totalMail
-- private.cacheFrame.endTime = GetTime() + 60
-- private.cacheFrame:Show()
-- end
4 years ago
-- The last item we setup to auto loot is finished, time for the next one
if not private.frame.buttonsEnabled then
-- if private.autoLootTotal ~= numMail then
-- private.autoLootTotal = GetInboxNumItems()
4 years ago
-- If we're auto checking mail when new data is available, will wait and continue auto looting, otherwise we just stop now
if totalMail == 0 then
4 years ago
private:StopAutoLooting()
else
private:AutoLoot()
end
else
TSMAPI:CreateTimeDelay("mailSkipDelay", 1, function()
local money, _, _, hasItem, _, _, _, canReply = select(5, GetInboxHeaderInfo(private.lootIndex))
if not hasItem and money == 0 then
private.lootIndex = private.lootIndex + 1
return private:AutoLoot()
end
end)
-- end
4 years ago
end
end
function private:ShouldOpenMail(index)
local shouldOpen
if private.mode == "all" then
return true
elseif private.mode == "sales" then
local money = select(5, GetInboxHeaderInfo(index))
if money > 0 and GetInboxInvoiceInfo(index) == "seller" then
return true
end
elseif private.mode == "buys" then
local hasItem = select(8, GetInboxHeaderInfo(index))
if hasItem and GetInboxInvoiceInfo(index) == "buyer" then
return true
end
elseif private.mode == "cancels" then
local isInvoice = select(4, GetInboxText(index))
local subject, _, _, _, hasItem = select(4, GetInboxHeaderInfo(index))
if not isInvoice and hasItem == 1 then
local itemLink = GetInboxItemLink(index, 1)
if itemLink then
local itemName = TSMAPI:GetSafeItemInfo(itemLink)
local quantity = select(3, GetInboxItem(index, 1))
if quantity and quantity > 0 and (subject == format(AUCTION_REMOVED_MAIL_SUBJECT.." (%d)", itemName, quantity) or subject == format(AUCTION_REMOVED_MAIL_SUBJECT, itemName)) then
return true
end
end
end
elseif private.mode == "pendings" then
local isInvoice = select(4, GetInboxText(index))
if isInvoice then
invoiceType = GetInboxInvoiceInfo(index)
if invoiceType == "seller_temp_invoice" then
return true
end
end
elseif private.mode == "expires" then
local isInvoice = select(4, GetInboxText(index))
local subject, _, _, _, hasItem = select(4, GetInboxHeaderInfo(index))
if not isInvoice and hasItem == 1 then
local itemLink = GetInboxItemLink(index, 1)
if itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then
return true
end
end
end
end
-- Deals with auto looting of mail!
function private:StartAutoLooting(mode)
private.mode = mode
local canCollectMail
if private.mode == "all" then
local total
private.autoLootTotal, total = GetInboxNumItems()
canCollectMail = not (private.autoLootTotal == 0 and total == 0)
else
for i = 1, GetInboxNumItems() do
if private:ShouldOpenMail(i) then
canCollectMail = true
break
end
end
end
if not canCollectMail then
private.mode = nil
return
end
Inbox:RegisterEvent("UI_ERROR_MESSAGE")
private.frame:DisableButtons()
private.moneyCollected = 0
private.mode = mode
private.lootIndex = 1
private:AutoLoot()
end
function private:AutoLoot()
TSMAPI:CancelFrame("mailSkipDelay")
-- Already looted everything after the invalid indexes we had, so fail it
if private.lootIndex > 1 and private.lootIndex > GetInboxNumItems() then
if private.resetIndex then
private:StopAutoLooting()
else
private.resetIndex = true
private.lootIndex = 1
private:AutoLoot()
end
return
end
local _, _, sender, subject, money, cod, _, items, _, _, _, _, isGM = GetInboxHeaderInfo(private.lootIndex)
if (sender == "The Postmaster" or sender == "Blackwater Auction House" or sender == "Customer Support") or not isGM and (not cod or cod <= 0) and ((money and money > 0) or (items and items > 0)) or GetInboxInvoiceInfo(private.lootIndex) == "seller_temp_invoice" then
4 years ago
TSMAPI:CancelFrame("mailWaitDelay")
if private.mode == "all" then
if money > 0 then
if TSM.db.global.openAllLeaveGold then
private.lootIndex = private.lootIndex + 1
return private:AutoLoot()
end
end
if private:CanLootMailIndex(private.lootIndex) then
if money > 0 then
private.moneyCollected = private.moneyCollected + money
end
private:LootMailItem(private.lootIndex)
else
private.lootIndex = private.lootIndex + 1
return private:AutoLoot()
end
else
if private:CanLootMailIndex(private.lootIndex) and private:ShouldOpenMail(private.lootIndex) then
if money > 0 then
private.moneyCollected = private.moneyCollected + money
end
private:LootMailItem(private.lootIndex)
else
private.lootIndex = private.lootIndex + 1
return private:AutoLoot()
end
end
-- Can't grab the first mail, so increase it and try again
elseif GetInboxNumItems() >= private.lootIndex then
private.lootIndex = private.lootIndex + 1
private:AutoLoot()
end
end
function private:LootMailItem(index)
if TSM.db.global.inboxMessages then
--local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index)
local _, _, sender, subject, money, cod, daysLeft, hasItem, _, _, _, _, _, itemQuantity = GetInboxHeaderInfo(index)
4 years ago
sender = sender or "?"
isTakeable = select(4, GetInboxText(index))
if isTakeable then
4 years ago
-- it's an invoice
local invoiceType, itemName, playerName, bid, _, _, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(index)
-- fix MoP difference
if not quantity then
quantity = select(3, GetInboxItem(index))
end
4 years ago
local redColor = "|cffFF0000"
local greenColor = "|cff00FF00"
local yellowColor = "|cffFFFF00"
if invoiceType == "buyer" then
local itemLink = GetInboxItemLink(index, 1) or itemName
TSM:Printf(L["Collected purchase of %s (%d) for %s."], itemLink, quantity or 1, TSMAPI:FormatTextMoney(bid, redColor))
4 years ago
elseif invoiceType == "seller" then
TSM:Printf(L["Collected sale of %s (%d) for %s."], itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, greenColor))
-- TSM:Printf("Collected sale of %s for %s.", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor))
4 years ago
elseif invoiceType == "seller_temp_invoice" then
-- TSM:Printf("Removing pending sale: %s (%s)", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor))
TSM:Printf("Removing pending sale of %s (%d) for %s.", itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor))
4 years ago
DeleteInboxItem(index)
return
end
elseif hasItem then
local itemLink
local quantity = 0
for i = 1, hasItem do
local link = GetInboxItemLink(index, i)
itemLink = itemLink or link
quantity = quantity + select(3, GetInboxItem(index, i))
if TSMAPI:GetItemString(itemLink) ~= TSMAPI:GetItemString(link) then
itemLink = L["Multiple Items"]
quantity = -1
break
end
end
local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and "Multiple Items") or "?"
if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then
TSM:Printf(L["Collected expired auction of %s"], itemDesc)
elseif cod > 0 then
TSM:Printf(L["Collected COD of %s from %s for %s."], itemDesc, sender, TSMAPI:FormatTextMoney(cod, redColor))
elseif money > 0 then
TSM:Printf(L["Collected %s and %s from %s."], itemDesc, TSMAPI:FormatTextMoney(money, greenColor), sender)
else
TSM:Printf(L["Collected %s from %s."], itemDesc, sender)
end
elseif money > 0 then
TSM:Printf(L["Collected %s from %s."], TSMAPI:FormatTextMoney(money, greenColor), sender)
elseif (sender == "The Postmaster" or sender == "Blackwater Auction House" or sender == "Customer Support" and subject == "Your Ascension Order" and daysLeft < 270) and money == 0 and hasItem == nil then
TSM:Printf("Removing empty mail from %s.", sender)
DeleteInboxItem(index)
4 years ago
else
TSM:Printf(L["Collected mail from %s with a subject of '%s'."], sender, subject)
end
end
AutoLootMailItem(index)
end
function private:CanLootMailIndex(index)
local hasItem = select(8, GetInboxHeaderInfo(index))
if not hasItem or hasItem == 0 then return true end
if not TSM.db.global.keepMailSpace or TSM.db.global.keepMailSpace == 0 then
for j = 1, ATTACHMENTS_MAX_RECEIVE do
local itemString = TSMAPI:GetItemString(GetInboxItemLink(index, j))
local quantity = select(3, GetInboxItem(index, j))
local space = 0
if itemString then
for bag = 0, NUM_BAG_SLOTS do
if TSMAPI:ItemWillGoInBag(itemString, bag) then
for slot = 1, GetContainerNumSlots(bag) do
local iString = TSMAPI:GetItemString(GetContainerItemLink(bag, slot))
if iString == itemString then
local stackSize = select(2, GetContainerItemInfo(bag, slot))
local maxStackSize = select(8, TSMAPI:GetSafeItemInfo(itemString))
if (maxStackSize - stackSize) >= quantity then
return true
end
elseif not iString then
return true
end
end
end
end
end
end
else
-- get number of free slots per generic / special bags and partial slots by bag
local genericSpace, uniqueSpace, partSlots = private:GetBagSlots()
local usedSlots = {}
for j = 1, ATTACHMENTS_MAX_RECEIVE do
local itemString = TSMAPI:GetItemString(GetInboxItemLink(index, j))
local quantity = select(3, GetInboxItem(index, j))
local isDone = false
if itemString then
for bag = 0, NUM_BAG_SLOTS do
if TSMAPI:ItemWillGoInBag(itemString, bag) then
for slot = 1, GetContainerNumSlots(bag) do
local iString = TSMAPI:GetItemString(GetContainerItemLink(bag, slot))
if iString == itemString and (partSlots[bag] and partSlots[bag][slot]) then
local stackSize = select(2, GetContainerItemInfo(bag, slot))
local maxStackSize = select(8, TSMAPI:GetSafeItemInfo(itemString))
if (maxStackSize - stackSize - (usedSlots[bag] and usedSlots[bag][slot] or 0)) >= quantity then
if stackSize + quantity == maxStackSize then
if partSlots[bag] and partSlots[bag][slot] then
partSlots[bag][slot] = nil -- this partial slot would be filled so remove it from available part slots
end
else
if not usedSlots[bag] then
usedSlots[bag] = {}
end
usedSlots[bag][slot] = (usedSlots[bag][slot] or 0) + stackSize -- store the stacksize for this slot after adding this item
end
isDone = true
break
end
else
local itemFamily = GetItemFamily(itemString)
local bagFamily = GetItemFamily(GetBagName(bag)) or 0
if itemFamily and bagFamily and bagFamily > 0 and bit.band(itemFamily, bagFamily) > 0 and (uniqueSpace[bag] and uniqueSpace[bag] > 0) then
uniqueSpace[bag] = uniqueSpace[bag] - 1 -- remove one empty slot from the bag
isDone = true
break
else
if genericSpace[bag] and genericSpace[bag] > 0 then
genericSpace[bag] = genericSpace[bag] - 1 -- remove one empty slot from the bag
if genericSpace[bag] <= 0 then
genericSpace[bag] = nil
end
isDone = true
break
end
end
end
end
if isDone then break end
end
end
end
end
--calculate the total remaining empty slots in generic bags after looting this mail
local remainingSpace = 0
for bag, space in pairs(genericSpace) do
remainingSpace = remainingSpace + space
end
if remainingSpace >= TSM.db.global.keepMailSpace then
return true -- either not using keepMailSpace option or we can loot all of this mail
else
private.keepFreeSlots = true -- can't loot the whole of this mail and leave enough free slots so set the flag that displays the chat message
end
end
end
function private:StopAutoLooting(failed)
if failed and (not private.frame or not private.frame:IsVisible()) then
TSM:Print(L["Cannot finish auto looting, inventory is full or too many unique items."])
end
if private.keepFreeSlots then
TSM:Printf(L["Cannot finish auto looting, keeping %s slots free."], TSM.db.global.keepMailSpace)
private.keepFreeSlots = false
end
private.mode = nil
private.resetIndex = nil
private.autoLootTotal = nil
if not private.frame then return end
private.frame:EnableButtons()
--Tell user how much money has been collected if they don't have it turned off in TradeSkillMaster_Mailing options
if private.moneyCollected and private.moneyCollected > 0 and TSM.db.global.displayMoneyCollected then
TSM:Printf(L["%s total gold collected!"], TSMAPI:FormatTextMoney(private.moneyCollected))
private.moneyCollected = 0
end
end
function private:GetBagSlots()
local genericSpace, uniqueSpace, partSlots = {}, {}, {}
for bag = 0, NUM_BAG_SLOTS do
if (GetItemFamily(GetBagName(bag)) or 0) > 0 then
uniqueSpace[bag] = GetContainerNumFreeSlots(bag) or 0
else
genericSpace[bag] = GetContainerNumFreeSlots(bag) or 0
end
for slot = 1, GetContainerNumSlots(bag) do
local iLink = GetContainerItemLink(bag, slot)
if iLink then
if not partSlots[bag] then
partSlots[bag] = {}
end
table.insert(partSlots[bag], slot)
end
end
end
return genericSpace, uniqueSpace, partSlots
end
function Inbox:UI_ERROR_MESSAGE(event, msg)
if msg == ERR_MAIL_DATABASE_ERROR then
-- recover from internal mail error
TSMAPI:CreateTimeDelay("mailWaitDelay", 1, private.AutoLoot)
elseif msg == ERR_INV_FULL or msg == ERR_ITEM_MAX_COUNT then
-- Try the next index in case we can still loot more such as in the case of glyphs
private.lootIndex = private.lootIndex + 1
-- If we've exhausted all slots, but we still have <50 and more mail pending, wait until new data comes and keep looting it
local current, total = GetInboxNumItems()
if private.lootIndex > current then
if private.lootIndex > total and total <= 50 then
private:StopAutoLooting(true)
end
return
end
TSMAPI:CreateTimeDelay("mailWaitDelay", math.max(5/GetFramerate(), 0.3), private.AutoLoot)
4 years ago
end
end
function Inbox:MAIL_CLOSED()
private.resetIndex = nil
private.allowTimerStart = true
private.waitingForData = nil
private:StopAutoLooting()
TSMAPI:CancelFrame("inboxLootTextDelay")
TSMAPI:CancelFrame("mailSkipDelay")
Inbox:UnregisterEvent("UI_ERROR_MESSAGE") --sometimes shows error messages even when closed, so unregister that event.
end