diff --git a/TradeSkillMaster_Mailing/Modules/Inbox.lua b/TradeSkillMaster_Mailing/Modules/Inbox.lua index aae2775..dbe9f56 100644 --- a/TradeSkillMaster_Mailing/Modules/Inbox.lua +++ b/TradeSkillMaster_Mailing/Modules/Inbox.lua @@ -6,718 +6,87 @@ -- All Rights Reserved* - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- +-- register this file with Ace Libraries local TSM = select(2, ...) -local Inbox = TSM:NewModule("Inbox", "AceEvent-3.0", "AceHook-3.0") +TSM = LibStub("AceAddon-3.0"):NewAddon(TSM, "TSM_Mailing", "AceEvent-3.0", "AceConsole-3.0") +local AceGUI = LibStub("AceGUI-3.0") -- load the AceGUI libraries 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, +TSM.SPELLING_WARNING = "|cffff0000"..L["BE SURE TO SPELL THE NAME CORRECTLY!"].."|r" +local private = {lootIndex=1, recheckTime=1, allowTimerStart=true} + +local savedDBDefaults = { + global = { + defaultMailTab = true, + autoCheck = true, + displayMoneyCollected = true, + sendItemsIndividually = false, + resendDelay = 1, + sendDelay = 0.5, + optionsTreeStatus = {}, + openAllLeaveGold = false, + inboxMessages = true, + sendMessages = true, + defaultPage = 1, + showReloadBtn = true, + keepMailSpace = 0, + }, + realm = { + deMailTarget = "", + mailTargets = {}, + mailItems = {}, + }, + char = { + goldMailTarget = "", + goldKeepAmount = 1000000, + }, +} + +function TSM:OnEnable() + -- load the savedDB into TSM.db + TSM.db = LibStub:GetLibrary("AceDB-3.0"):New("AscensionTSM_MailingDB", savedDBDefaults, true) + + for moduleName, module in pairs(TSM.modules) do + TSM[moduleName] = module + end + + -- register this module with TSM + TSM:RegisterModule() + + -- temporary check + TSMAPI:Verify(TSMAPI.IsPlayer, "You need to update your TradeSkillMaster addon. Otherwise, you may see lua errors!") +end + +-- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule(). +function TSM:RegisterModule() + TSM.operations = {maxOperations=12, callbackOptions="Options:Load", callbackInfo="GetOperationInfo"} + TSM.moduleAPIs = { + {key="mailItems", callback="AutoMail:SendItems"}, } - - 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, _, _, _, _, _ = GetInboxHeaderInfo(i) - if isInvoice then - local invoiceType, itemName, playerName, bid, buyout, deposit, ahcut = GetInboxInvoiceInfo(i) - - sender = sender or "?" - if hasItem then - quantity = select(3, GetInboxItem(index)) - end - -- fix MoP difference - if (quantity == nil) then quantity = 0 end - - if invoiceType == "buyer" then - local itemLink = GetInboxItemLink(i, 1) or itemName - mailInfo[i] = format(L["Buy: %s (%d) | %s | %s"], itemLink, quantity or 0, TSMAPI:FormatTextMoney(bid, redColor), FormatDaysLeft(daysLeft, i)) - elseif invoiceType == "seller" then - collectGold = collectGold + bid - ahcut - --mailInfo[i] = format(L["Sale: %s (%d) | %s | %s"], itemName, quantity, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i)) - mailInfo[i] = format("Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i)) - elseif invoiceType == "seller_temp_invoice" then - mailInfo[i] = format("Pending Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor), FormatDaysLeft(daysLeft, i)) - end - elseif hasItem and hasItem > 1 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 - - -- 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() - - -- 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 - 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 - 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 money, cod, _, items, _, _, _, _, isGM = select(5, GetInboxHeaderInfo(private.lootIndex)) - if 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 - 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, _, hasItem, _, _, _, _, _ = GetInboxHeaderInfo(index) - sender = sender or "?" - isTakeable = select(4, GetInboxText(index)) - if hasItem then - quantity = select(3, GetInboxItem(index)) - end - if isTakeable then - -- it's an invoice - local invoiceType, itemName, playerName, bid, _, _, ahcut = GetInboxInvoiceInfo(index) - - -- fix MoP difference - if (quantity == nil) then quantity = 0 end --itemQuantity end - - 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 0, TSMAPI:FormatTextMoney(bid, redColor)) - elseif invoiceType == "seller" then - --TSM:Printf(L["Collected sale of %s (%d) for %s."], itemName, quantity, TSMAPI:FormatTextMoney(bid - ahcut, greenColor)) - TSM:Printf("Collected sale of %s for %s.", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor)) - elseif invoiceType == "seller_temp_invoice" then - TSM:Printf("Removing pending sale: %s (%s)", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor)) - DeleteInboxItem(index) - return - end - elseif hasItem and hasItem > 1 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) - 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 + + TSMAPI:NewModule(TSM) +end + +TSM.operationDefaults = { + maxQtyEnabled = nil, + maxQty = 10, + target = "", + restock = nil, -- take into account how many the target already has + restockGBank = nil, + keepQty = 0, + ignorePlayer = {}, + ignorerealm = {}, + relationships = {}, +} + +function TSM:GetOperationInfo(operationName) + local operation = TSM.operations[operationName] + if not operation then return end + if operation.target == "" then return end + + if operation.maxQtyEnabled then + return format(L["Mailing up to %d to %s."], operation.maxQty, operation.target) 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 + return format(L["Mailing all to %s."], operation.target) 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", 0.3, private.AutoLoot) - 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