Zerotorescue@0: local MailOpener = LibStub("AceAddon-3.0"):GetAddon("MailOpener"); Zerotorescue@0: local OpenAll = MailOpener:NewModule("OpenAll", "AceEvent-3.0", "AceTimer-3.0"); Zerotorescue@0: Zerotorescue@3: --[[ Zerotorescue@3: Module name: OpenAll Zerotorescue@3: Description: The actual mail opening initiated by the core. Zerotorescue@3: Required: Yes. Zerotorescue@3: Zerotorescue@3: Dev notes: Zerotorescue@3: When shift clicking the Open All button it should override all filters. Zerotorescue@3: ]] Zerotorescue@3: Zerotorescue@0: local MAIL_ITEM_INDEX, mailTimer, inventoryFull, inventoryFullSoundPlayed, opening, lastSync, numCurrentMail, numHiddenMail, continue; Zerotorescue@0: Zerotorescue@0: function OpenAll:OnInitialize() Zerotorescue@0: local defaults = { Zerotorescue@0: profile = { Zerotorescue@0: speed = 0.05, Zerotorescue@0: keepFreeSpace = 0, Zerotorescue@0: filter = { Zerotorescue@0: AH = { Zerotorescue@0: canceled = true, Zerotorescue@0: expired = true, Zerotorescue@0: outbid = true, Zerotorescue@0: success = true, Zerotorescue@0: won = true, Zerotorescue@0: }, Zerotorescue@0: normalAttachments = false, Zerotorescue@0: normalMoney = true, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: -- Register our saved variables NameSpace Zerotorescue@0: self.db = MailOpener.db:RegisterNamespace("OpenAll", defaults); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:OnEnable() Zerotorescue@0: self:RegisterEvent("MAIL_SHOW"); Zerotorescue@0: Zerotorescue@0: if not self.btnOpenAll then Zerotorescue@0: -- Open all button Zerotorescue@0: local button = CreateFrame("Button", "btnMailOpenerOpenAll", InboxFrame, "UIPanelButtonTemplate") Zerotorescue@0: button:SetText("Open all") Zerotorescue@0: button:SetHeight(26) Zerotorescue@0: button:SetWidth(120) Zerotorescue@0: button:SetPoint("BOTTOM", InboxFrame, "CENTER", -10, -165) Zerotorescue@0: button:SetScript("OnClick", function() OpenAll:Open(true) end) Zerotorescue@0: Zerotorescue@0: self.btnOpenAll = button; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self.btnOpenAll:Show(); Zerotorescue@0: Zerotorescue@0: if not self.timeLeftFrame then Zerotorescue@0: -- If the timeLeftFrame doesn't exist we will have to build it Zerotorescue@0: Zerotorescue@0: self:Debug("Building text frame"); Zerotorescue@0: Zerotorescue@0: local frame = CreateFrame("Button", "MailOpenerTimeLeftButton", InboxFrame); Zerotorescue@0: Zerotorescue@0: -- Mail counter Zerotorescue@0: frame.text = frame:CreateFontString("MailOpenerTimeLeftFrameMailCount", "OVERLAY", "GameFontHighlight"); Zerotorescue@0: frame.text:SetPoint("CENTER", MailFrame, "TOPLEFT", 40, -35); Zerotorescue@0: Zerotorescue@0: -- Long time left indicator Zerotorescue@0: frame.smallText = frame:CreateFontString("MailOpenerTimeLeftFrameTimeRemaining", "OVERLAY", "GameFontNormal"); Zerotorescue@0: frame.smallText:SetFont(GameFontHighlight:GetFont(), 11, "OUTLINE"); Zerotorescue@0: frame.smallText:SetPoint("TOPLEFT", MailFrame, "TOPLEFT", 75, -38); Zerotorescue@0: frame.smallText:SetWidth(270); Zerotorescue@0: frame.smallText:SetJustifyH("LEFT"); Zerotorescue@0: frame.smallText:SetJustifyV("MIDDLE"); Zerotorescue@0: Zerotorescue@0: frame:SetPoint("TOPLEFT", MailFrame, "TOPLEFT", 75, -38); Zerotorescue@0: frame:SetWidth(270); Zerotorescue@0: frame:SetHeight(35); Zerotorescue@0: frame:SetScript("OnClick", function(self) Zerotorescue@0: local timeRemainingUntillOpened = frame.smallText:GetText(); Zerotorescue@0: if timeRemainingUntillOpened then Zerotorescue@0: MailOpener.currentPopupContents = "|cffffd700" .. timeRemainingUntillOpened .. "|r"; Zerotorescue@0: Zerotorescue@0: StaticPopup_Show("MailOpenerCopyWindow"); Zerotorescue@0: end Zerotorescue@0: end); Zerotorescue@0: Zerotorescue@0: self.timeLeftFrame = frame; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self.timeLeftFrame:Show(); Zerotorescue@0: Zerotorescue@3: -- Go through all children of the mail frame to find QA's element and hide it Zerotorescue@0: local kids = { MailFrame:GetChildren() }; Zerotorescue@0: Zerotorescue@0: for _, child in ipairs(kids) do Zerotorescue@0: if child and child.text then Zerotorescue@0: child.text:Hide(); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- If we were toggling this module on while the mailbox is opened we must register all events again Zerotorescue@0: if MailFrame:IsVisible() then Zerotorescue@0: self:MAIL_SHOW(); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:OnDisable() Zerotorescue@0: self:UnregisterEvent("MAIL_SHOW"); Zerotorescue@0: Zerotorescue@0: if self.btnOpenAll then Zerotorescue@0: self.btnOpenAll:Hide(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if self.timeLeftFrame then Zerotorescue@0: self.timeLeftFrame:Hide(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if MailOpener.PostalEnabled then Zerotorescue@0: -- Enable Postal's openers again Zerotorescue@0: Zerotorescue@0: MailOpener:TogglePostalModule("OpenAll", true); Zerotorescue@0: MailOpener:TogglePostalModule("Select", true); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Go through all children of the mail frame to find QA's elements and SHOW these Zerotorescue@0: local kids = { MailFrame:GetChildren() }; Zerotorescue@0: Zerotorescue@0: for _, child in ipairs(kids) do Zerotorescue@0: if child and child.text then Zerotorescue@0: child.text:Show(); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:Stop(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:MAIL_SHOW() Zerotorescue@0: self:Debug("MAIL_SHOW"); Zerotorescue@0: Zerotorescue@0: self:StopOpening(false); Zerotorescue@0: Zerotorescue@0: if MailOpener.PostalEnabled then Zerotorescue@0: -- Disable Postal's openers so we can do it ourselves Zerotorescue@0: Zerotorescue@0: MailOpener:TogglePostalModule("OpenAll", false); Zerotorescue@0: MailOpener:TogglePostalModule("Select", false); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Keep an eye for closing of the mailbox Zerotorescue@0: self:RegisterEvent("MAIL_CLOSED", "Stop"); Zerotorescue@0: self:RegisterEvent("PLAYER_LEAVING_WORLD", "Stop"); Zerotorescue@0: Zerotorescue@0: -- Look if the mailbox is full Zerotorescue@0: self:RegisterEvent("UI_ERROR_MESSAGE"); Zerotorescue@0: -- Only look again after bags updated Zerotorescue@0: self:RegisterEvent("BAG_UPDATE"); Zerotorescue@0: Zerotorescue@0: -- We need to know when to start opening Zerotorescue@0: self:RegisterMessage("MO_OPEN_MAIL", "Open"); Zerotorescue@0: self:RegisterMessage("MO_SERVER_SYNCED"); Zerotorescue@3: self:RegisterMessage("MO_MAIL_EMPTIED"); Zerotorescue@0: Zerotorescue@0: self:CancelTimer(self.tmrTimeRemaining, true); Zerotorescue@0: self.tmrTimeRemaining = self:ScheduleRepeatingTimer("UpdateTimer", 1); Zerotorescue@0: self:UpdateTimer(); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:Stop() Zerotorescue@0: self:Debug("Stop"); Zerotorescue@0: Zerotorescue@0: -- We shutdown, so nothing to do when the mailbox is closed anymore Zerotorescue@0: self:UnregisterEvent("MAIL_CLOSED"); Zerotorescue@0: self:UnregisterEvent("PLAYER_LEAVING_WORLD"); Zerotorescue@0: Zerotorescue@0: -- We care about a full inventory just a little Zerotorescue@0: self:UnregisterEvent("UI_ERROR_MESSAGE"); Zerotorescue@0: self:UnregisterEvent("BAG_UPDATE"); Zerotorescue@0: Zerotorescue@0: -- We no longer care Zerotorescue@0: self:UnregisterMessage("MO_OPEN_MAIL"); Zerotorescue@0: self:UnregisterMessage("MO_SERVER_SYNCED"); Zerotorescue@3: self:UnregisterMessage("MO_MAIL_EMPTIED"); Zerotorescue@0: Zerotorescue@0: self:CancelTimer(self.tmrMailOpener, true); Zerotorescue@0: self:CancelTimer(self.tmrTimeRemaining, true); Zerotorescue@0: Zerotorescue@0: self:SetOpeningStatus(false); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:MO_SERVER_SYNCED() Zerotorescue@0: self:Debug("MO_SERVER_SYNCED"); Zerotorescue@0: Zerotorescue@2: -- Stop opening now to prevent the opener from continue while Beancounter is counting Zerotorescue@2: self:StopOpening(false); Zerotorescue@2: Zerotorescue@0: lastSync = GetTime(); Zerotorescue@0: Zerotorescue@2: self:UpdateMailCount(); Zerotorescue@2: end Zerotorescue@2: Zerotorescue@3: function OpenAll:MO_MAIL_EMPTIED() Zerotorescue@3: -- A mail has been processed so we can process the next Zerotorescue@2: continue = true; Zerotorescue@2: Zerotorescue@3: self:UpdateTimer(); Zerotorescue@2: end Zerotorescue@2: Zerotorescue@2: function OpenAll:UpdateMailCount() Zerotorescue@0: local numItems, totalItems = GetInboxNumItems(); Zerotorescue@0: Zerotorescue@0: numCurrentMail = numItems; Zerotorescue@0: numHiddenMail = ( totalItems - numItems ); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:BAG_UPDATE() Zerotorescue@0: -- If the bags are updated we should check if the inventory is full again Zerotorescue@0: inventoryFull = false; Zerotorescue@1: -- Replay sound Zerotorescue@1: inventoryFullSoundPlayed = nil; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- We registered this event to look for the inventory full error message because this is faster than counting the amount of items in the inventory all the time Zerotorescue@0: function OpenAll:UI_ERROR_MESSAGE(e, errorMessage) Zerotorescue@0: if errorMessage == ERR_INV_FULL then Zerotorescue@0: -- Inventory is full. Zerotorescue@0: Zerotorescue@0: if not inventoryFull then Zerotorescue@0: inventoryFull = true; Zerotorescue@0: Zerotorescue@0: -- Play the sound Zerotorescue@0: if MailOpener.db.profile.notifications.bagsFullSound and (not MailOpener.db.profile.notifications.bagsFullSoundOnlyOnce or not inventoryFullSoundPlayed) then Zerotorescue@0: PlaySoundFile(MailOpener.db.profile.notifications.bagsFullSoundFile); Zerotorescue@0: inventoryFullSoundPlayed = true; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Continue opening mail (we still want to open gold mail) Zerotorescue@0: continue = true; Zerotorescue@0: elseif errorMessage == ERR_ITEM_MAX_COUNT or errorMessage == ERR_MAIL_DATABASE_ERROR then Zerotorescue@0: -- Can't carry more of this item OR mail database error Zerotorescue@0: Zerotorescue@0: -- Continue opening mail (we still want to retrieve other items or gold) Zerotorescue@0: continue = true; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:Open(forced) Zerotorescue@0: self:Debug("Open"); Zerotorescue@0: Zerotorescue@0: if not opening or forced == true then Zerotorescue@0: local numItems, totalItems = GetInboxNumItems(); Zerotorescue@0: -- Start at the end, add one because OpenNext will take it away again Zerotorescue@0: local newMailItemIndex = ( ( numItems or 0 ) + 1 ); Zerotorescue@0: Zerotorescue@0: if newMailItemIndex > 1 then Zerotorescue@0: self:Debug("Open succes"); Zerotorescue@0: Zerotorescue@0: -- Stop the previous opening and restart Zerotorescue@0: if forced == true then Zerotorescue@0: self:StopOpening(false); -- this is not a "simple" stop, so also reset inventory full warning Zerotorescue@0: else Zerotorescue@0: self:StopOpening(true); -- forced is false - automated action - simple reset, skip inventory full reset to avoid sound spam Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Update the caret Zerotorescue@0: MAIL_ITEM_INDEX = newMailItemIndex; Zerotorescue@0: Zerotorescue@0: -- We're now going to be busy again Zerotorescue@0: self:SetOpeningStatus(true); Zerotorescue@0: Zerotorescue@0: -- Open the next mail in line Zerotorescue@0: self:OpenNext(); Zerotorescue@0: else Zerotorescue@0: if MailOpener.db.profile.notifications.mailboxIsEmpty then Zerotorescue@0: print("|cffff0000There is currently no mail available.|r"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:Debug("MO_OPEN_COMPLETE"); Zerotorescue@0: Zerotorescue@0: -- Report that we're all done Zerotorescue@0: self:SendMessage("MO_OPEN_COMPLETE"); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Return the type of mail a message subject is Zerotorescue@0: local knownAHSubjectPatterns = { Zerotorescue@0: canceled = AUCTION_REMOVED_MAIL_SUBJECT:replace("%s", ""), Zerotorescue@0: expired = AUCTION_EXPIRED_MAIL_SUBJECT:replace("%s", ""), Zerotorescue@0: outbid = AUCTION_OUTBID_MAIL_SUBJECT:replace("%s", ""), Zerotorescue@0: success = AUCTION_SOLD_MAIL_SUBJECT:replace("%s", ""), Zerotorescue@0: won = AUCTION_WON_MAIL_SUBJECT:replace("%s", ""), Zerotorescue@0: }; Zerotorescue@0: function OpenAll:GetAuctionMailType(subject) Zerotorescue@0: if subject then Zerotorescue@0: -- Check if any of our patterns match, sorted by most likely matches first (if one is true the rest shouldn't be evaluated) Zerotorescue@0: if subject:find(knownAHSubjectPatterns.expired) then Zerotorescue@0: return "expired"; Zerotorescue@0: elseif subject:find(knownAHSubjectPatterns.success) then Zerotorescue@0: return "success"; Zerotorescue@0: elseif subject:find(knownAHSubjectPatterns.won) then Zerotorescue@0: return "won"; Zerotorescue@0: elseif subject:find(knownAHSubjectPatterns.canceled) then Zerotorescue@0: return "canceled"; Zerotorescue@0: elseif subject:find(knownAHSubjectPatterns.outbid) then Zerotorescue@0: return "outbid"; Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return; -- not auction mail Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:OpenMail(index) Zerotorescue@0: if index > 0 then Zerotorescue@0: -- LUA arrays start at 1, so mail with index 0 doesn't exist, so we're finished Zerotorescue@0: Zerotorescue@0: local sender, subject, gold, cod, _, items, _, _, _, _, isGM = select(3, GetInboxHeaderInfo(index)); Zerotorescue@0: local auctionMailType = self:GetAuctionMailType(subject); Zerotorescue@0: Zerotorescue@0: if isGM then Zerotorescue@0: -- GM Mail Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped.GMMail then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (GM mail)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif cod and cod > 0 then Zerotorescue@0: -- Cost on delivery Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped.COD then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (C.O.D.)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif ((gold and gold > 0) or (items and items > 0)) then Zerotorescue@0: -- Mail with some sort of attachments Zerotorescue@0: Zerotorescue@0: local slotsAvailable = 0; Zerotorescue@0: if self.db.profile.keepFreeSpace > 0 then Zerotorescue@0: for bag = 0, 4 do Zerotorescue@0: local numberOfFreeSlots = GetContainerNumFreeSlots(bag); Zerotorescue@0: slotsAvailable = ( slotsAvailable + numberOfFreeSlots ); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if inventoryFull and not MailOpener.db.profile.general.continueOpeningStackableItems and items and items > 0 then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped.inventoryFull then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (inventory is full)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif self.db.profile.keepFreeSpace > 0 and items and ( slotsAvailable - items ) < self.db.profile.keepFreeSpace then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped.keepFreeSpaceLimit then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (keep free space limit)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: else Zerotorescue@0: -- This string will hold the mailtype, MailOpener.db.profile.notifications.skipped/processed[mailType] will be checked if this should be announced Zerotorescue@0: local mailType = "other"; Zerotorescue@0: Zerotorescue@0: if not auctionMailType then Zerotorescue@0: -- This is a normal mail Zerotorescue@0: Zerotorescue@0: if gold and gold > 0 then Zerotorescue@0: mailType = "normalGoldMail"; Zerotorescue@0: elseif items and items > 0 then Zerotorescue@0: mailType = "normalItemsMail"; Zerotorescue@0: end Zerotorescue@0: else Zerotorescue@0: -- This is an auction house mail Zerotorescue@0: Zerotorescue@0: mailType = "AH" .. auctionMailType; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: if not self.db.profile.filter.normalMoney and mailType == "normalGoldMail" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (normal mail with gold)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.normalAttachments and mailType == "normalItemsMail" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (normal mail with attachments)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.AH.expired and mailType == "AHexpired" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (expired auction)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.AH.success and mailType == "AHsuccess" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (successful auction)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.AH.won and mailType == "AHwon" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (auction won)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.AH.canceled and mailType == "AHcanceled" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (canceled auction)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: elseif not self.db.profile.filter.AH.outbid and mailType == "AHoutbid" then Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped[mailType] then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject .. " (outbid on auction)"); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: Zerotorescue@0: return; Zerotorescue@0: else Zerotorescue@0: continue = false; Zerotorescue@3: Zerotorescue@3: self:Debug("MO_OPENING_MAIL"); Zerotorescue@0: Zerotorescue@2: -- Notifiy other modules of opening Zerotorescue@2: self:SendMessage("MO_OPENING_MAIL"); Zerotorescue@2: Zerotorescue@0: -- Open current mail Zerotorescue@0: AutoLootMailItem(index); Zerotorescue@0: Zerotorescue@0: if MailOpener.db.profile.notifications.processed.all and MailOpener.db.profile.notifications.processed[mailType] then Zerotorescue@0: if gold and gold > 0 then Zerotorescue@0: print("Processing " .. index .. ": " .. subject .. " (" .. MailOpener:FormatMoney(gold) .. ")"); Zerotorescue@0: else Zerotorescue@0: print("Processing " .. index .. ": " .. subject); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- And prepare for the next Zerotorescue@0: self.tmrMailOpener = self:ScheduleTimer("OpenNext", self.db.profile.speed); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: else Zerotorescue@0: -- Unknown, probably just text Zerotorescue@0: if MailOpener.db.profile.notifications.skipped.all and MailOpener.db.profile.notifications.skipped.other then Zerotorescue@0: if subject then Zerotorescue@0: print("Skipping " .. index .. ": " .. subject); Zerotorescue@0: else Zerotorescue@0: print("Skipping " .. index); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:OpenNext(); Zerotorescue@0: end Zerotorescue@0: else Zerotorescue@0: -- Finished! Zerotorescue@0: if MailOpener.db.profile.notifications.finishedCurrentBatch then Zerotorescue@0: print("Finished opening the current batch."); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self:SetOpeningStatus(false); Zerotorescue@3: Zerotorescue@0: self:Debug("MO_OPEN_COMPLETE"); Zerotorescue@0: Zerotorescue@0: -- Report that we're all done Zerotorescue@0: self:SendMessage("MO_OPEN_COMPLETE"); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:OpenNext() Zerotorescue@0: if continue then Zerotorescue@0: -- If the previous mail was opened successful, open the next Zerotorescue@0: Zerotorescue@0: -- Next mail in line Zerotorescue@0: MAIL_ITEM_INDEX = ( MAIL_ITEM_INDEX - 1 ); Zerotorescue@0: Zerotorescue@0: -- Open it Zerotorescue@0: self:OpenMail(MAIL_ITEM_INDEX); Zerotorescue@0: else Zerotorescue@0: -- Try again at the next interval Zerotorescue@0: Zerotorescue@0: self.tmrMailOpener = self:ScheduleTimer("OpenNext", self.db.profile.speed); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@2: function OpenAll:Continue() Zerotorescue@2: continue = true; Zerotorescue@2: self:OpenNext(); Zerotorescue@2: end Zerotorescue@2: Zerotorescue@0: local mailRemainingPatterns = { Zerotorescue@3: minutesSeconds = "|cffffffff%d|r/|cffffffff%d|r mail remaining, opening everything will take about |cffffffff%d|r minutes and |cffffffff%d|r seconds (next refresh in |cffffffff%d|r seconds)."; Zerotorescue@3: minutes = "|cffffffff%d|r/|cffffffff%d|r mail remaining, opening everything will take about |cffffffff%d|r minutes (next refresh in |cffffffff%d|r seconds)."; Zerotorescue@3: seconds = "|cffffffff%d|r/|cffffffff%d|r mail remaining, opening everything will take about |cffffffff%d|r seconds (next refresh in |cffffffff%d|r seconds)."; Zerotorescue@3: nextRefresh = "|cffffffff%d|r/|cffffffff%d|r mail remaining, next refresh in |cffffffff%d|r seconds."; Zerotorescue@0: waitingBatch = "|cffffffff%d|r/|cffffffff%d|r mail remaining - waiting for something from the current batch to be opened..."; Zerotorescue@0: waitingSync = "|cffffffff%d|r/|cffffffff%d|r mail remaining - waiting for the next mailbox refresh..."; Zerotorescue@0: soon = "|cffffffff%d|r/|cffffffff%d|r mail remaining - everything will be opened soon..."; Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: function OpenAll:UpdateTimer() Zerotorescue@0: if lastSync then Zerotorescue@3: self:UpdateMailCount(); Zerotorescue@3: Zerotorescue@0: -- Calculate the total amount of mail waiting Zerotorescue@0: local numTotalMail = ( numHiddenMail + numCurrentMail ); Zerotorescue@0: Zerotorescue@0: -- Resize the font based on mail left so the counter always fits perfectly Zerotorescue@0: if numTotalMail < 100 then Zerotorescue@0: self.timeLeftFrame.text:SetFont(GameFontHighlight:GetFont(), 30, "THICKOUTLINE"); Zerotorescue@0: elseif numTotalMail < 1000 then Zerotorescue@0: self.timeLeftFrame.text:SetFont(GameFontHighlight:GetFont(), 24, "THICKOUTLINE"); Zerotorescue@0: else Zerotorescue@0: self.timeLeftFrame.text:SetFont(GameFontHighlight:GetFont(), 18, "THICKOUTLINE"); Zerotorescue@0: end Zerotorescue@0: self.timeLeftFrame.text:SetText(numTotalMail); Zerotorescue@3: Zerotorescue@3: -- Calculate the next server sync based on the last server sync plus sync interval Zerotorescue@3: local nextSync = ( lastSync + 61 ); Zerotorescue@0: Zerotorescue@3: -- Calculate the timer remaining untill the next sync Zerotorescue@3: local timeRemaining = floor( nextSync - GetTime() ); Zerotorescue@3: Zerotorescue@3: if numHiddenMail > 0 or timeRemaining > 0 then Zerotorescue@3: -- If there is still mail being hidden or the timer is still know, display stuff Zerotorescue@0: Zerotorescue@0: -- If the next sync was already due, our nextSync calculation was wrong and we must wait a little longer (lag?) Zerotorescue@0: local syncTimeOut = false; Zerotorescue@0: -- If time remaining is below 0, next sync should be soon Zerotorescue@0: if timeRemaining < 0 then Zerotorescue@0: timeRemaining = 0; Zerotorescue@0: syncTimeOut = true; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Calculate the amount of server syncs required to open all mail Zerotorescue@0: local syncsRequired = ceil( numHiddenMail / 50 ); Zerotorescue@0: -- Calculate the time required to execute all these syncs Zerotorescue@0: local timeRequired = ( ( syncsRequired - 1 ) * 61 ) + timeRemaining; Zerotorescue@0: Zerotorescue@0: local minutes = floor( timeRequired / 60 ); Zerotorescue@0: local seconds = floor( timeRequired % 60 ); Zerotorescue@0: Zerotorescue@0: local remainingText; Zerotorescue@0: if syncTimeOut then Zerotorescue@3: -- Previous server sync was expected earlier, notify user Zerotorescue@3: Zerotorescue@0: if numCurrentMail == 50 then Zerotorescue@3: -- Sync couldn't occur because we were still waiting for the current batch to be opened Zerotorescue@0: remainingText = format(mailRemainingPatterns.waitingBatch, numCurrentMail, numTotalMail); Zerotorescue@0: else Zerotorescue@0: remainingText = format(mailRemainingPatterns.waitingSync, numCurrentMail, numTotalMail); Zerotorescue@0: end Zerotorescue@3: elseif numHiddenMail == 0 then Zerotorescue@3: -- If no hidden mail is remaining, only show the timer for as long as we can be sure Zerotorescue@3: Zerotorescue@3: remainingText = format(mailRemainingPatterns.nextRefresh, numCurrentMail, numTotalMail, timeRemaining); Zerotorescue@0: elseif minutes ~= 0 then Zerotorescue@0: if seconds ~= 0 then Zerotorescue@0: remainingText = format(mailRemainingPatterns.minutesSeconds, numCurrentMail, numTotalMail, minutes, seconds, timeRemaining); Zerotorescue@0: else Zerotorescue@0: remainingText = format(mailRemainingPatterns.minutes, numCurrentMail, numTotalMail, minutes, timeRemaining); Zerotorescue@0: end Zerotorescue@0: elseif seconds ~= 0 then Zerotorescue@0: remainingText = format(mailRemainingPatterns.seconds, numCurrentMail, numTotalMail, seconds, timeRemaining); Zerotorescue@0: else Zerotorescue@0: remainingText = format(mailRemainingPatterns.soon, numCurrentMail, numTotalMail); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: self.timeLeftFrame.smallText:SetText(remainingText); Zerotorescue@3: else Zerotorescue@0: self.timeLeftFrame.smallText:SetText(""); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:StopOpening(simple) Zerotorescue@2: -- Stop opener timer Zerotorescue@2: self:CancelTimer(self.tmrMailOpener, true); Zerotorescue@2: Zerotorescue@0: if not simple then Zerotorescue@2: -- A simple stop is an automated stop, an advance stop is one manually or after a sever sync Zerotorescue@2: Zerotorescue@0: -- Recheck inventory full Zerotorescue@0: inventoryFull = false; Zerotorescue@0: -- Replay sound Zerotorescue@0: inventoryFullSoundPlayed = nil; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- Reset opener position Zerotorescue@0: MAIL_ITEM_INDEX = 0; Zerotorescue@0: -- Stopped opening, so allow to continue Zerotorescue@0: continue = true; Zerotorescue@0: self:SetOpeningStatus(false); Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:SetOpeningStatus(openingStatus) Zerotorescue@0: opening = openingStatus; Zerotorescue@0: Zerotorescue@0: if openingStatus then Zerotorescue@0: self.btnOpenAll:SetText("Opening..."); Zerotorescue@0: else Zerotorescue@0: self.btnOpenAll:SetText("Open all"); Zerotorescue@0: end Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:GetOptionsGroup() Zerotorescue@0: local configGroup = { Zerotorescue@0: order = 300, Zerotorescue@0: type = "group", Zerotorescue@0: name = "Open All", Zerotorescue@0: desc = "Change open all settings.", Zerotorescue@0: args = { Zerotorescue@0: filters = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Filters", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Toggle which mail the opener should autoloot.", Zerotorescue@0: }, Zerotorescue@0: AHHeader = { Zerotorescue@0: order = 15, Zerotorescue@0: type = "header", Zerotorescue@0: name = "Auction House Mail", Zerotorescue@0: }, Zerotorescue@0: canceled = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Open all |cfffed000auction canceled|r mail", Zerotorescue@0: desc = "Automatically loot all auction canceled mails from the auction house.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.AH.canceled = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.AH.canceled; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: expired = { Zerotorescue@0: order = 21, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Open all |cfffed000auction expired|r mail", Zerotorescue@0: desc = "Automatically loot all auction canceled mails from the auction house.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.AH.expired = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.AH.expired; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: outbid = { Zerotorescue@0: order = 22, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Open all |cfffed000outbid on|r mail", Zerotorescue@0: desc = "Automatically loot all auction outbid mails from the auction house.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.AH.outbid = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.AH.outbid; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: success = { Zerotorescue@0: order = 23, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Open all |cfffed000auction successful|r mail", Zerotorescue@0: desc = "Automatically loot all auction successful mails from the auction house.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.AH.success = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.AH.success; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: won = { Zerotorescue@0: order = 24, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Open all |cfffed000auction won|r mail", Zerotorescue@0: desc = "Automatically loot all auction won mails from the auction house.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.AH.won = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.AH.won; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: normalHeader = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "header", Zerotorescue@0: name = "Remaining Mail", Zerotorescue@0: }, Zerotorescue@0: normalAttachments = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Other mail with |cfffed000attachments|r", Zerotorescue@0: desc = "Automatically loot all mails with attachments not sent by any of the above sources.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.normalAttachments = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.normalAttachments; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: normalMoney = { Zerotorescue@0: order = 50, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Other mail with |cfffed000gold|r", Zerotorescue@0: desc = "Automatically loot all mails with gold not sent by any of the above sources.", Zerotorescue@0: set = function(i, v) self.db.profile.filter.normalMoney = v; end, Zerotorescue@0: get = function() return self.db.profile.filter.normalMoney; end, Zerotorescue@0: width = "double", Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: -- Continuous opening config inline group Zerotorescue@0: continuousOpening = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Opening Interval", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = function() Zerotorescue@0: local defaultString = "The default behaviour for opening mail is to only do so right after new mail was received from the server. If you close the mailbox or your inventory is full before everything is opened you will have to click the open all button manually or wait for a next mailbox refresh.\n\n"; Zerotorescue@0: Zerotorescue@0: local currentSettings = ""; Zerotorescue@0: if MailOpener.db.profile.general.continueOpening then Zerotorescue@0: currentSettings = currentSettings .. "Mail Opener will |cff00ff00continue|r to attempt to open the remaining mail every |cfffed000" .. MailOpener.db.profile.general.waitTime .. " seconds|r. "; Zerotorescue@0: else Zerotorescue@0: currentSettings = currentSettings .. "Mail Opener will |cffff0000not|r continue to attempt to open the remaining mail and will only start opening when new mail has just been received from the server. "; Zerotorescue@0: end Zerotorescue@0: currentSettings = currentSettings .. "The first batch after each server refresh will be opened after waiting |cfffed000" .. MailOpener.db.profile.general.initialDelay .. " seconds|r."; Zerotorescue@0: return defaultString .. currentSettings; Zerotorescue@0: end, Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 15, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: continueOpening = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "toggle", Zerotorescue@0: name = "Continue opening mail", Zerotorescue@0: desc = "Continue opening mail at the interval set below, even if the mailbox wasn't refreshed recently.", Zerotorescue@0: width = "full", Zerotorescue@0: get = function() return MailOpener.db.profile.general.continueOpening; end, Zerotorescue@0: set = function(i, v) MailOpener.db.profile.general.continueOpening = v; end, Zerotorescue@0: }, Zerotorescue@0: waitTime = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "range", Zerotorescue@0: width = "double", Zerotorescue@0: min = 0.5, Zerotorescue@0: max = 60, Zerotorescue@0: step = 0.5, Zerotorescue@0: name = "Continued Mail Opening Interval", Zerotorescue@5: desc = "Change the interval at which Mail Opener tries to continue opening mail after opening the mailbox. Please note that this setting does not reduce the game's normal 60 seconds wait time for mail.\n\nThe default value is 5 seconds.", Zerotorescue@0: get = function() return MailOpener.db.profile.general.waitTime; end, Zerotorescue@0: set = function(i, v) MailOpener.db.profile.general.waitTime = v; end, Zerotorescue@0: disabled = function() return (not MailOpener.db.profile.general.continueOpening); end, Zerotorescue@0: }, Zerotorescue@0: initialDelay = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "range", Zerotorescue@0: width = "double", Zerotorescue@0: min = 0.5, Zerotorescue@0: max = 60, Zerotorescue@0: step = 0.5, Zerotorescue@0: name = "Initial Mail Opening Delay", Zerotorescue@0: desc = "Change the delay before Mail Opener tries opening mail after opening the mailbox or new mail has been received from the server.\n\nThe default value is 0.5 seconds.", Zerotorescue@0: get = function() return MailOpener.db.profile.general.initialDelay; end, Zerotorescue@0: set = function(i, v) MailOpener.db.profile.general.initialDelay = v; end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, -- end Continuous opening config inline group Zerotorescue@0: keepFree = { Zerotorescue@0: order = 30, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Keep Free Space", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "You can set an amount of bag space you wish to reserve when opening mail. Mail with a higher amount of attachments than available space will be skipped completely with this option set above 0.", Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 15, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: keepFreeSpace = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 0, Zerotorescue@0: max = 100, Zerotorescue@0: step = 1, Zerotorescue@0: width = "double", Zerotorescue@0: name = "Keep free space", Zerotorescue@0: desc = "Change the amount of space to reserve for other things when opening mail. If this option is set higher than 0, mail with a higher amount of attachments than available space will be skipped completely.\n\nE.g. If this is set to 1 and you have a total of 12 slots left then any mail with 12 attachments will be skipped while one with 11 attachments would be opened.", Zerotorescue@0: set = function(i, v) self.db.profile.keepFreeSpace = v; end, Zerotorescue@0: get = function() return self.db.profile.keepFreeSpace; end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: speed = { Zerotorescue@0: order = 40, Zerotorescue@0: type = "group", Zerotorescue@0: inline = true, Zerotorescue@0: name = "Opening Speed", Zerotorescue@0: args = { Zerotorescue@0: description = { Zerotorescue@0: order = 10, Zerotorescue@0: type = "description", Zerotorescue@0: name = "Change the speed at which mail is opened. You should set the opening speed to the lowest latency you have in a city or experiment with setting it to the minimum.", Zerotorescue@0: }, Zerotorescue@0: header = { Zerotorescue@0: order = 15, Zerotorescue@0: type = "header", Zerotorescue@0: name = "", Zerotorescue@0: }, Zerotorescue@0: openMailInterval = { Zerotorescue@0: order = 20, Zerotorescue@0: type = "range", Zerotorescue@0: min = 5, Zerotorescue@0: max = 2500, Zerotorescue@0: step = 5, Zerotorescue@0: width = "double", Zerotorescue@0: name = "Open single mail interval", Zerotorescue@0: desc = "Change the mail opening speed (in microseconds) for each mail. Lower may not always be faster.", Zerotorescue@0: get = function() return ( self.db.profile.speed * 1000 ); end, Zerotorescue@0: set = function(i, v) self.db.profile.speed = ( v / 1000 ); end, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }, Zerotorescue@0: }; Zerotorescue@0: Zerotorescue@0: return configGroup; Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: function OpenAll:Debug(t) Zerotorescue@0: return MailOpener:Debug("|cff00ff00OpenAll|r:" .. t); Zerotorescue@0: end