Advertisement
SilverFox4226

Inbox.lua

Dec 16th, 2018
1,329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.27 KB | None | 0 0
  1. -- ------------------------------------------------------------------------------ --
  2. -- TradeSkillMaster_Mailing --
  3. -- http://www.curse.com/addons/wow/tradeskillmaster_mailing --
  4. -- --
  5. -- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
  6. -- All Rights Reserved* - Detailed license information included with addon. --
  7. -- ------------------------------------------------------------------------------ --
  8.  
  9. local TSM = select(2, ...)
  10. local Inbox = TSM:NewModule("Inbox", "AceEvent-3.0", "AceHook-3.0")
  11. local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Mailing") -- loads the localization table
  12. local private = {recheckTime=1, allowTimerStart=true, moneyCollected=0, threadId=nil, frame=nil, mode=nil, modeModified=nil}
  13.  
  14.  
  15. function Inbox:OnEnable()
  16. Inbox:RegisterEvent("MAIL_SHOW")
  17. Inbox:RegisterEvent("MAIL_INBOX_UPDATE", function() TSMAPI.Delay:AfterTime("mailingInboxUpdate", 0.2, private.InboxUpdate) end)
  18. Inbox:RegisterEvent("MAIL_CLOSED")
  19. end
  20.  
  21. function Inbox:CreateTab()
  22. local BFC = TSMAPI.GUI:GetBuildFrameConstants()
  23. local frameInfo = {
  24. type = "Frame",
  25. key = "inboxTab",
  26. hidden = true,
  27. points = "ALL",
  28. scripts = {"OnShow", "OnHide"},
  29. children = {
  30. {
  31. type = "Text",
  32. key = "topLabel",
  33. text = "",
  34. textFont = {TSMAPI.Design:GetContentFont("small")},
  35. justify = {"CENTER", "MIDDLE"},
  36. size = {0, 15},
  37. points = {{"TOPLEFT", 5, -5}, {"TOPRIGHT", -5, -5}},
  38. },
  39. {
  40. type = "HLine",
  41. offset = -25,
  42. },
  43. {
  44. type = "ScrollingTableFrame",
  45. key = "st",
  46. points = {{"TOPLEFT", 5, -30}, {"BOTTOMRIGHT", -5, 55}},
  47. scripts = {"OnClick"},
  48. },
  49. {
  50. type = "Button",
  51. key = "allBtn",
  52. text = L["Open All Mail"],
  53. textHeight = 18,
  54. tooltip = L["Opens all mail in your inbox. If you have more than 50 items in your inbox, the opening will automatically continue when the inbox refreshes."].."\n\n"..TSMAPI.Design:GetInlineColor("link")..L["Shift-Click|r to leave mail with gold."],
  55. size = {0, 20},
  56. points = {{"BOTTOMLEFT", 5, 30}, {"BOTTOMRIGHT", -5, 30}},
  57. scripts = {"OnClick"},
  58. },
  59. {
  60. type = "Text",
  61. key = "ahMailLabel",
  62. text = L["AH Mail:"],
  63. textFont = {TSMAPI.Design:GetContentFont("normal")},
  64. justify = {"RIGHT", "CENTER"},
  65. size = {70, 20},
  66. points = {{"BOTTOMLEFT", 5, 5}},
  67. },
  68. {
  69. type = "Button",
  70. key = "salesBtn",
  71. text = L["Sales"],
  72. textHeight = 15,
  73. tooltip = L["Opens all mail containing gold from sales."].."\n\n"..format(L["%sShift-Click|r to continue opening after an inbox refresh if you have more than 50 items in your inbox."], TSMAPI.Design:GetInlineColor("link")),
  74. size = {55, 20},
  75. points = {{"BOTTOMLEFT", BFC.PREV, "BOTTOMRIGHT", 5, 0}},
  76. scripts = {"OnClick"},
  77. },
  78. {
  79. type = "Button",
  80. key = "buysBtn",
  81. text = L["Buys"],
  82. tooltip = L["Opens all mail containing items you have bought."].."\n\n"..format(L["%sShift-Click|r to continue opening after an inbox refresh if you have more than 50 items in your inbox."], TSMAPI.Design:GetInlineColor("link")),
  83. textHeight = 15,
  84. size = {55, 20},
  85. points = {{"BOTTOMLEFT", BFC.PREV, "BOTTOMRIGHT", 5, 0}},
  86. scripts = {"OnClick"},
  87. },
  88. {
  89. type = "Button",
  90. key = "cancelsBtn",
  91. text = L["Cancels"],
  92. textHeight = 15,
  93. tooltip = L["Opens all mail containing canceled auctions."].."\n\n"..format(L["%sShift-Click|r to continue opening after an inbox refresh if you have more than 50 items in your inbox."], TSMAPI.Design:GetInlineColor("link")),
  94. size = {55, 20},
  95. points = {{"BOTTOMLEFT", BFC.PREV, "BOTTOMRIGHT", 5, 0}},
  96. scripts = {"OnClick"},
  97. },
  98. {
  99. type = "Button",
  100. key = "expiresBtn",
  101. text = L["Expires"],
  102. textHeight = 15,
  103. tooltip = L["Opens all mail containing expired auctions."].."\n\n"..format(L["%sShift-Click|r to continue opening after an inbox refresh if you have more than 50 items in your inbox."], TSMAPI.Design:GetInlineColor("link")),
  104. size = {0, 20},
  105. points = {{"BOTTOMLEFT", BFC.PREV, "BOTTOMRIGHT", 5, 0}, {"BOTTOMRIGHT", -5, 5}},
  106. scripts = {"OnClick"},
  107. },
  108. {
  109. type = "Button",
  110. key = "reloadBtn",
  111. text = RELOADUI,
  112. textHeight = 16,
  113. size = {150, 20},
  114. points = {{"CENTER"}},
  115. scripts = {"OnClick"},
  116. },
  117. },
  118. handlers = {
  119. OnShow = function(self)
  120. private.frame = self
  121. self.reloadBtn:SetFrameStrata("HIGH")
  122. self.reloadBtn:Hide()
  123.  
  124. if not self.helpBtn then
  125. local TOTAL_WIDTH = private.frame:GetParent():GetWidth()
  126. local helpPlateInfo = {
  127. FramePos = {x = 0, y = 70},
  128. FrameSize = {width = TOTAL_WIDTH, height = private.frame:GetHeight()},
  129. {
  130. ButtonPos = {x = 100, y = -20},
  131. HighLightBox = {x = 70, y = -35, width = TOTAL_WIDTH-70, height = 30},
  132. ToolTipDir = "DOWN",
  133. ToolTipText = L["These buttons change what is shown in the mailbox frame. You can view your inbox, automatically mail items in groups, quickly send items to other characters, and more in the various tabs."],
  134. },
  135. {
  136. ButtonPos = {x = 200, y = -200},
  137. HighLightBox = {x = 0, y = -65, width = TOTAL_WIDTH, height = 305},
  138. ToolTipDir = "RIGHT",
  139. ToolTipText = L["This is where the items in your inbox are listed in an information and easy to read format."],
  140. },
  141. {
  142. ButtonPos = {x = 300, y = -360},
  143. HighLightBox = {x = 0, y = -370, width = TOTAL_WIDTH, height = 55},
  144. ToolTipDir = "RIGHT",
  145. ToolTipText = L["The 'Open All Mail' button will open all mail in your inbox (including beyond the 50-mail limit). The AH mail buttons below that will open specific types of mail from your inbox."],
  146. },
  147. }
  148.  
  149. self.helpBtn = CreateFrame("Button", nil, private.frame, "MainHelpPlateButton")
  150. self.helpBtn:SetPoint("TOPLEFT", 50, 100)
  151. self.helpBtn:SetScript("OnClick", function() TSM.MailTab:ToggleHelpPlate(private.frame, helpPlateInfo, self.helpBtn, true) end)
  152. self.helpBtn:SetScript("OnHide", function() if HelpPlate_IsShowing(helpPlateInfo) then TSM.MailTab:ToggleHelpPlate(private.frame, helpPlateInfo, self.helpBtn, false) end end)
  153. if not TSM.db.global.helpPlatesShown.inbox then
  154. TSM.db.global.helpPlatesShown.inbox = true
  155. TSM.MailTab:ToggleHelpPlate(private.frame, helpPlateInfo, self.helpBtn, false)
  156. end
  157. end
  158.  
  159. private:InboxUpdate()
  160. end,
  161. OnHide = private.MailThreadDone,
  162. st = {
  163. OnClick = function(_, data)
  164. if IsShiftKeyDown() and select(6, GetInboxHeaderInfo(data.index)) <= 0 then
  165. if private:CanLootMailIndex(data.index, true) then
  166. private:PrintOpenMailMessage(data.index)
  167. AutoLootMailItem(data.index)
  168. else
  169. TSM:Print(L["Could not loot item from mail because your bags are full."])
  170. end
  171. end
  172.  
  173. if InboxFrame.openMailID ~= data.index then
  174. InboxFrame.openMailID = data.index
  175. OpenMailFrame.updateButtonPositions = true
  176. OpenMail_Update()
  177. ShowUIPanel(OpenMailFrame)
  178. OpenMailFrameInset:SetPoint("TOPLEFT", 4, -80)
  179. PlaySound(SOUNDKIT["IG_SPELLBOOK_OPEN"])
  180. else
  181. InboxFrame.openMailID = 0
  182. HideUIPanel(OpenMailFrame)
  183. end
  184. InboxFrame_Update()
  185. end,
  186. },
  187. allBtn = {
  188. OnClick = function() private:StartOpenMail("all") end,
  189. },
  190. buysBtn = {
  191. OnClick = function() private:StartOpenMail("buys") end,
  192. },
  193. salesBtn = {
  194. OnClick = function() private:StartOpenMail("sales") end,
  195. },
  196. cancelsBtn = {
  197. OnClick = function() private:StartOpenMail("cancels") end,
  198. },
  199. expiresBtn = {
  200. OnClick = function() private:StartOpenMail("expires") end,
  201. },
  202. reloadBtn = {
  203. OnClick = ReloadUI,
  204. },
  205. },
  206. }
  207. return frameInfo
  208. end
  209.  
  210. local function CacheFrameOnUpdate(self, elapsed)
  211. if not private.waitingForData then
  212. local seconds = self.endTime - GetTime()
  213. if seconds <= 0 then
  214. -- Look for new mail
  215. -- Sometimes it fails and isn't available at exactly 60-61 seconds, and more like 62-64, will keep rechecking every 1 second
  216. -- until data becomes available
  217. if TSM.db.global.autoCheck then
  218. private.waitingForData = true
  219. self.timeLeft = private.recheckTime
  220. CheckInbox()
  221. private.frame.reloadBtn:Hide()
  222. else
  223. self:Hide()
  224. end
  225. return
  226. end
  227.  
  228. private:UpdateTopLabel()
  229. else
  230. self.timeLeft = self.timeLeft - elapsed
  231. if self.timeLeft <= 0 then
  232. self.timeLeft = private.recheckTime
  233. CheckInbox()
  234. private.frame.reloadBtn:Hide()
  235. end
  236. end
  237. end
  238.  
  239. function Inbox:MAIL_SHOW()
  240. TSMAPI.Delay:AfterTime("mailingGetSellers", 0.1, private.RequestSellerInfo, 0.1)
  241. if not private.cacheFrame then
  242. -- Timer for mailbox cache updates
  243. private.cacheFrame = CreateFrame("Frame", nil, MailFrame)
  244. private.cacheFrame:Hide()
  245. private.cacheFrame:SetScript("OnUpdate", CacheFrameOnUpdate)
  246. end
  247. end
  248.  
  249. function private:RequestSellerInfo()
  250. local isDone = true
  251. for i=1, GetInboxNumItems() do
  252. local invoiceType, _, seller = GetInboxInvoiceInfo(i)
  253. if invoiceType and seller == "" then
  254. isDone = false
  255. end
  256. end
  257. if isDone and GetInboxNumItems() > 0 then
  258. TSMAPI.Delay:Cancel("mailingGetSellers")
  259. end
  260. end
  261.  
  262. local function FormatDaysLeft(daysLeft, index)
  263. -- code taken from Blizzard MailFrame.lua code
  264. if daysLeft >= 1 then
  265. if InboxItemCanDelete(index) then
  266. daysLeft = YELLOW_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE;
  267. else
  268. daysLeft = GREEN_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE;
  269. end
  270. else
  271. daysLeft = RED_FONT_COLOR_CODE .. SecondsToTime(floor(daysLeft * 24 * 60 * 60)) .. FONT_COLOR_CODE_CLOSE;
  272. end
  273. return daysLeft
  274. end
  275.  
  276. function private:UpdateTopLabel()
  277. local parts = {}
  278.  
  279. local numMail, totalMail = GetInboxNumItems()
  280. if totalMail == numMail then
  281. tinsert(parts, format(L["Showing all %d mail."], numMail))
  282. else
  283. tinsert(parts, format(L["Showing %d of %d mail."], numMail, totalMail))
  284. end
  285.  
  286. local collectGold = private.collectGold or 0
  287. if collectGold > 0 then
  288. tinsert(parts, format(L["%s to collect."], TSMAPI:MoneyToString(collectGold)))
  289. end
  290.  
  291. local nextRefresh = private.cacheFrame:IsVisible() and private.cacheFrame.endTime
  292. if nextRefresh then
  293. if numMail == 0 and TSM.db.global.showReloadBtn then
  294. private.frame.reloadBtn:Show()
  295. end
  296. tinsert(parts, format(L["Inbox update in %d seconds."], max(ceil(nextRefresh - GetTime()), 0)))
  297. end
  298.  
  299. private.frame.topLabel:SetText(table.concat(parts, " "))
  300. end
  301.  
  302. function private:InboxUpdate()
  303. if not private.frame or not private.frame:IsVisible() then return end
  304.  
  305. local numMail, totalMail = GetInboxNumItems()
  306.  
  307. local greenColor, redColor = "|cff00ff00", "|cffff0000"
  308. local mailInfo = {}
  309. local collectGold = 0
  310. for i = 1, numMail do
  311. mailInfo[i] = ""
  312. local isInvoice = select(5, GetInboxText(i))
  313. local _, _, sender, subject, money, cod, daysLeft, hasItem = GetInboxHeaderInfo(i)
  314. if isInvoice then
  315. local invoiceType, itemName, playerName, bid, _, _, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(i)
  316. if invoiceType == "buyer" then
  317. local itemLink = private:GetFirstInboxItemLink(i) or itemName
  318. mailInfo[i] = format(L["Buy: %s (%d) | %s | %s"], itemLink, quantity, TSMAPI:MoneyToString(bid, redColor), FormatDaysLeft(daysLeft, i))
  319. elseif invoiceType == "seller" then
  320. collectGold = collectGold + bid - ahcut
  321. mailInfo[i] = format(L["Sale: %s (%d) | %s | %s"], itemName, quantity, TSMAPI:MoneyToString(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i))
  322. end
  323. elseif hasItem then
  324. local itemLink
  325. local quantity = 0
  326. for j = 1, hasItem do
  327. local link = GetInboxItemLink(i, j)
  328. itemLink = itemLink or link
  329. quantity = quantity + (select(4, GetInboxItem(i, j)) or 0)
  330. if TSMAPI.Item:ToItemString(itemLink) ~= TSMAPI.Item:ToItemString(link) then
  331. itemLink = L["Multiple Items"]
  332. quantity = -1
  333. break
  334. end
  335. end
  336. if hasItem == 1 then
  337. itemLink = private:GetFirstInboxItemLink(i) or itemLink
  338. end
  339. local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and L["Multiple Items"]) or "---"
  340.  
  341. local name = TSMAPI.Item:GetName(itemLink) or "?"
  342. if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI.Util:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, name))) then
  343. mailInfo[i] = format(L["Expired: %s | %s"], itemDesc, FormatDaysLeft(daysLeft, i))
  344. elseif cod > 0 then
  345. mailInfo[i] = format(L["COD: %s | %s | (%s) | %s | %s"], itemDesc, TSMAPI:MoneyToString(cod, redColor), quantity > 0 and TSMAPI:MoneyToString(floor(cod / quantity + 0.5), redColor) or "---", sender or "---", FormatDaysLeft(daysLeft, i))
  346. elseif money > 0 then
  347. collectGold = collectGold + money
  348. mailInfo[i] = format("%s + %s | %s | %s", itemDesc, TSMAPI:MoneyToString(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i))
  349. else
  350. mailInfo[i] = format("%s | %s | %s", itemDesc, sender or "---", FormatDaysLeft(daysLeft, i))
  351. end
  352. elseif money > 0 then
  353. mailInfo[i] = format("%s | %s | %s | %s", subject, TSMAPI:MoneyToString(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i))
  354. else
  355. mailInfo[i] = format("%s | %s | %s", subject, sender or "---", FormatDaysLeft(daysLeft, i))
  356. end
  357. end
  358. private.collectGold = collectGold
  359.  
  360. local stData = {}
  361. for i, info in ipairs(mailInfo) do
  362. tinsert(stData, { cols = { { value = info } }, index = i })
  363. end
  364. private.frame.st:SetData(stData)
  365.  
  366. if numMail > 0 then
  367. private.frame.reloadBtn:Hide()
  368. end
  369. private:UpdateTopLabel()
  370.  
  371. if private.cacheFrame.endTime and numMail == totalMail and private.lastTotal ~= totalMail then
  372. -- Yay nothing else to loot, so nothing else to update the cache for!
  373. private.cacheFrame.endTime = nil
  374. private.cacheFrame:Hide()
  375. elseif (private.cacheFrame.endTime and numMail >= 50 and private.lastTotal ~= totalMail) or (numMail >= 50 and private.allowTimerStart) then
  376. -- Start a timer since we're over the limit of 50 items before waiting for it to recache
  377. private.allowTimerStart = nil
  378. private.waitingForData = nil
  379. private.lastTotal = totalMail
  380. private.cacheFrame.endTime = GetTime() + 60
  381. private.cacheFrame:Show()
  382. end
  383. end
  384.  
  385.  
  386. function private:CanLootMailIndex(index, force)
  387. local money, cod, _, hasItem = select(5, GetInboxHeaderInfo(index))
  388. -- check if this would put them over the gold cap
  389. money = (money or 0) + (cod or 0)
  390. local MAX_COPPER = 99999999999
  391. local currentMoney = GetMoney()
  392. TSMAPI:Assert(currentMoney <= MAX_COPPER)
  393. if currentMoney + money > MAX_COPPER then return end
  394. if not hasItem or hasItem == 0 then return true end
  395.  
  396. if force or not TSM.db.global.keepMailSpace or TSM.db.global.keepMailSpace == 0 then
  397. for j = 1, ATTACHMENTS_MAX_RECEIVE do
  398. local link = GetInboxItemLink(index, j)
  399. local itemString = TSMAPI.Item:ToItemString(link)
  400. local quantity = select(4, GetInboxItem(index, j)) or 0
  401. local space = 0
  402. if itemString then
  403. for bag = 0, NUM_BAG_SLOTS do
  404. if TSMAPI.Inventory:ItemWillGoInBag(link, bag) then
  405. for slot = 1, GetContainerNumSlots(bag) do
  406. local iString = TSMAPI.Item:ToItemString(GetContainerItemLink(bag, slot))
  407. if iString == itemString then
  408. local stackSize = select(2, GetContainerItemInfo(bag, slot))
  409. local maxStackSize = TSMAPI.Item:GetMaxStack(itemString) or 1
  410. if (maxStackSize - stackSize) >= quantity then
  411. return true
  412. end
  413. elseif not iString then
  414. return true
  415. end
  416. end
  417. end
  418. end
  419.  
  420. -- Cannot loot the first item, so return.
  421. private.inventoryFull = true
  422. return
  423. end
  424. end
  425. else
  426. -- get number of free slots per generic / special bags and partial slots by bag
  427. local genericSpace, uniqueSpace, partSlots = private:GetBagSlots()
  428. local usedSlots = {}
  429. for j = 1, ATTACHMENTS_MAX_RECEIVE do
  430. local link = GetInboxItemLink(index, j)
  431. local itemString = TSMAPI.Item:ToItemString(link)
  432. local quantity = select(4, GetInboxItem(index, j)) or 0
  433. local isDone = false
  434. if itemString then
  435. for bag = 0, NUM_BAG_SLOTS do
  436. if TSMAPI.Inventory:ItemWillGoInBag(link, bag) then
  437. for slot = 1, GetContainerNumSlots(bag) do
  438. local iString = TSMAPI.Item:ToItemString(GetContainerItemLink(bag, slot))
  439. if iString == itemString and (partSlots[bag] and partSlots[bag][slot]) then
  440. local stackSize = select(2, GetContainerItemInfo(bag, slot))
  441. local maxStackSize = TSMAPI.Item:GetMaxStack(itemString)
  442. if (maxStackSize - stackSize - (usedSlots[bag] and usedSlots[bag][slot] or 0)) >= quantity then
  443. if stackSize + quantity == maxStackSize then
  444. if partSlots[bag] and partSlots[bag][slot] then
  445. partSlots[bag][slot] = nil -- this partial slot would be filled so remove it from available part slots
  446. end
  447. else
  448. if not usedSlots[bag] then
  449. usedSlots[bag] = {}
  450. end
  451. usedSlots[bag][slot] = (usedSlots[bag][slot] or 0) + stackSize -- store the stacksize for this slot after adding this item
  452. end
  453. isDone = true
  454. break
  455. end
  456. else
  457. local itemFamily = GetItemFamily(TSMAPI.Item:ToItemID(itemString)) or 0
  458. local bagFamily = GetItemFamily(GetBagName(bag)) or 0
  459. if itemFamily and bagFamily and bagFamily > 0 and bit.band(itemFamily, bagFamily) > 0 and (uniqueSpace[bag] and uniqueSpace[bag] > 0) then
  460. uniqueSpace[bag] = uniqueSpace[bag] - 1 -- remove one empty slot from the bag
  461. isDone = true
  462. break
  463. else
  464. if genericSpace[bag] and genericSpace[bag] > 0 then
  465. genericSpace[bag] = genericSpace[bag] - 1 -- remove one empty slot from the bag
  466. if genericSpace[bag] <= 0 then
  467. genericSpace[bag] = nil
  468. end
  469. isDone = true
  470. break
  471. end
  472. end
  473. end
  474. end
  475. if isDone then break end
  476. end
  477. end
  478. end
  479. end
  480.  
  481. --calculate the total remaining empty slots in generic bags after looting this mail
  482. local remainingSpace = 0
  483. for bag, space in pairs(genericSpace) do
  484. remainingSpace = remainingSpace + space
  485. end
  486. if remainingSpace >= TSM.db.global.keepMailSpace then
  487. return true -- either not using keepMailSpace option or we can loot all of this mail
  488. else
  489. 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
  490. end
  491. end
  492. end
  493.  
  494. function private:GetBagSlots()
  495. local genericSpace, uniqueSpace, partSlots = {}, {}, {}
  496. for bag = 0, NUM_BAG_SLOTS do
  497. if (GetItemFamily(GetBagName(bag)) or 0) > 0 then
  498. uniqueSpace[bag] = GetContainerNumFreeSlots(bag) or 0
  499. else
  500. genericSpace[bag] = GetContainerNumFreeSlots(bag) or 0
  501. end
  502. for slot = 1, GetContainerNumSlots(bag) do
  503. local iLink = GetContainerItemLink(bag, slot)
  504. if iLink then
  505. if not partSlots[bag] then
  506. partSlots[bag] = {}
  507. end
  508. table.insert(partSlots[bag], slot)
  509. end
  510. end
  511. end
  512. return genericSpace, uniqueSpace, partSlots
  513. end
  514.  
  515. function Inbox:MAIL_CLOSED()
  516. private.allowTimerStart = true
  517. private.waitingForData = nil
  518. TSMAPI.Delay:Cancel("mailingGetSellers")
  519. private:MailThreadDone()
  520. end
  521.  
  522. function private:ShouldDeleteMail(index)
  523. local subject, money, cod, numItems, wasReturned, canReply, isGM = TSMAPI.Util:Select({4, 5, 6, 8, 10, 12, 13}, GetInboxHeaderInfo(index))
  524. if not TSM.db.global.deleteEmptyNPCMail then return false end
  525. if isGM then return false end
  526. if canReply then return false end
  527. if numItems then return false end
  528. if cod > 0 then return false end
  529. if money > 0 then return false end
  530. if wasReturned then return false end
  531. return true
  532. end
  533.  
  534. function private:ShouldOpenMail(index)
  535. local _, _, _, subject, money, cod, _, numItems, _, _, _, _, isGM = GetInboxHeaderInfo(index)
  536. cod = cod or 0
  537. money = money or 0
  538. numItems = numItems or 0
  539.  
  540. if isGM or cod > 0 or (money == 0 and numItems == 0) then return end
  541. if not private:CanLootMailIndex(index) then return end
  542.  
  543. if private.mode == "all" then
  544. if private.modeModified then
  545. return money == 0
  546. else
  547. return true
  548. end
  549. elseif private.mode == "sales" then
  550. return money > 0 and GetInboxInvoiceInfo(index) == "seller"
  551. elseif private.mode == "buys" then
  552. return numItems > 0 and GetInboxInvoiceInfo(index) == "buyer"
  553. elseif private.mode == "cancels" then
  554. local isInvoice = select(5, GetInboxText(index))
  555. if not isInvoice and numItems == 1 then
  556. local itemName = TSMAPI.Item:GetName(private:GetFirstInboxItemLink(index))
  557. if itemName then
  558. local quantity = select(4, GetInboxItem(index, 1))
  559. if quantity and quantity > 0 and (subject == format(AUCTION_REMOVED_MAIL_SUBJECT.." (%d)", itemName, quantity) or subject == format(AUCTION_REMOVED_MAIL_SUBJECT, itemName)) then
  560. return true
  561. end
  562. end
  563. end
  564. elseif private.mode == "expires" then
  565. local isInvoice = select(5, GetInboxText(index))
  566. if not isInvoice and numItems == 1 then
  567. local itemName = TSMAPI.Item:GetName(private:GetFirstInboxItemLink(index))
  568. if itemName and strfind(subject, "^" .. TSMAPI.Util:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, itemName))) then
  569. return true
  570. end
  571. end
  572. end
  573. end
  574.  
  575. function private:PrintOpenMailMessage(index)
  576. if not TSM.db.global.inboxMessages then return end
  577. local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index)
  578. local greenColor, redColor = "|cff00ff00", "|cffff0000"
  579. sender = sender or "?"
  580. if select(5, GetInboxText(index)) then
  581. -- it's an invoice
  582. local invoiceType, itemName, playerName, bid, _, _, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(index)
  583. playerName = playerName or "?"
  584. if invoiceType == "buyer" then
  585. local itemLink = private:GetFirstInboxItemLink(index) or itemName
  586. TSM:Printf(L["Bought %sx%d for %s from %s"], itemLink, quantity, TSMAPI:MoneyToString(bid, redColor), playerName)
  587. elseif invoiceType == "seller" then
  588. TSM:Printf(L["Sold [%s]x%d for %s to %s"], itemName, quantity, TSMAPI:MoneyToString(bid - ahcut, greenColor), playerName)
  589. end
  590. elseif hasItem then
  591. local itemLink
  592. local quantity = 0
  593. for i = 1, hasItem do
  594. local link = GetInboxItemLink(index, i)
  595. itemLink = itemLink or link
  596. quantity = quantity + (select(4, GetInboxItem(index, i)) or 0)
  597. if TSMAPI.Item:ToItemString(itemLink) ~= TSMAPI.Item:ToItemString(link) then
  598. itemLink = L["Multiple Items"]
  599. quantity = -1
  600. break
  601. end
  602. end
  603. if hasItem == 1 then
  604. itemLink = private:GetFirstInboxItemLink(index) or itemLink
  605. end
  606. local itemName = TSMAPI.Item:GetName(itemLink) or "?"
  607. local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and "Multiple Items") or "?"
  608. if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI.Util:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, itemName))) then
  609. TSM:Printf(L["Your auction of %s expired"], itemDesc)
  610. elseif hasItem == 1 and quantity > 0 and (subject == format(AUCTION_REMOVED_MAIL_SUBJECT.." (%d)", itemName, quantity) or subject == format(AUCTION_REMOVED_MAIL_SUBJECT, itemName)) then
  611. TSM:Printf(L["Cancelled auction of %sx%d"], itemLink, quantity)
  612. elseif cod > 0 then
  613. TSM:Printf(L["%s sent you a COD of %s for %s"], sender, TSMAPI:MoneyToString(cod, redColor), itemDesc)
  614. elseif money > 0 then
  615. TSM:Printf(L["%s sent you %s and %s"], sender, itemDesc, TSMAPI:MoneyToString(money, greenColor))
  616. else
  617. TSM:Printf(L["%s sent you %s"], sender, itemDesc)
  618. end
  619. elseif money > 0 then
  620. TSM:Printf(L["%s sent you %s"], sender, TSMAPI:MoneyToString(money, greenColor))
  621. else
  622. TSM:Printf(L["%s sent you a message: %s"], sender, subject)
  623. end
  624. end
  625.  
  626. function private.OpenMailThread(self)
  627. self:SetThreadName("MAILING_OPEN_MAIL")
  628.  
  629. local eventStatus = nil
  630. self:RegisterEvent("UI_ERROR_MESSAGE", function(_, msg)
  631. if msg == ERR_MAIL_DATABASE_ERROR or msg == ERR_INV_FULL or msg == ERR_ITEM_MAX_COUNT then
  632. -- internal mail error, inventory full, or too many unique items
  633. eventStatus = "ERROR"
  634. end
  635. end)
  636. self:RegisterEvent("MAIL_INBOX_UPDATE", function() eventStatus = "UPDATE" end)
  637. private.frame.allBtn:Disable()
  638. private.frame.salesBtn:Disable()
  639. private.frame.buysBtn:Disable()
  640. private.frame.cancelsBtn:Disable()
  641. private.frame.expiresBtn:Disable()
  642.  
  643. -- wait for any pending mail to arrive
  644. while select(2, GetInboxNumItems()) == 0 and HasNewMail() do self:Yield(true) end
  645.  
  646. private.moneyCollected = 0
  647. local attemptedToOpenMail = true
  648. local shouldWait = false
  649. while attemptedToOpenMail do
  650. attemptedToOpenMail = nil
  651. local encounteredError = nil
  652. local numMail, totalMail = GetInboxNumItems()
  653. for index=numMail, 1, -1 do
  654. if private:ShouldOpenMail(index) then
  655. if shouldWait then
  656. -- this isn't the first time through the loop, so give the pending opens some times to clear out
  657. self:Sleep(2)
  658. shouldWait = nil
  659. attemptedToOpenMail = true
  660. break
  661. end
  662. local money = select(5, GetInboxHeaderInfo(index)) or 0
  663. local numItems = select(8, GetInboxHeaderInfo(index)) or 0
  664. local numInboxItems = GetInboxNumItems()
  665.  
  666. -- auto-loot the mail
  667. private:PrintOpenMailMessage(index)
  668. AutoLootMailItem(index)
  669.  
  670. -- wait for an inbox event
  671. eventStatus = nil
  672. local triedDeleting = nil
  673. while not eventStatus do self:Yield(true) end
  674. if eventStatus == "UPDATE" then
  675. -- wait for the number of mails to go down by 1 (for at most 1 second per item)
  676. local waitEndTime = debugprofilestop() + (max(numItems, 1) * 1000)
  677. while debugprofilestop() < waitEndTime do
  678. if GetInboxNumItems() == numInboxItems - 1 then break end
  679. if not triedDeleting and private:ShouldDeleteMail(index) then
  680. DeleteInboxItem(index)
  681. triedDeleting = true
  682. end
  683. if eventStatus == "ERROR" then
  684. TSM:LOG_ERR("Encountered error at index %d (triedDeleting=%s)", index, tostring(triedDeleting))
  685. encounteredError = true
  686. break
  687. end
  688. self:Yield(true)
  689. end
  690.  
  691. if not encounteredError then
  692. attemptedToOpenMail = true
  693. end
  694. elseif eventStatus == "ERROR" then
  695. -- there was an error trying to open this mail, so skip it silently and try again
  696. encounteredError = true
  697. end
  698.  
  699. -- track money collected
  700. private.moneyCollected = private.moneyCollected + money
  701. elseif private:ShouldDeleteMail(index) then
  702. -- wait for an inbox event
  703. DeleteInboxItem(index)
  704. eventStatus = nil
  705. while not eventStatus do self:Yield(true) end
  706.  
  707. if eventStatus == "UPDATE" then
  708. attemptedToOpenMail = true
  709. elseif eventStatus == "ERROR" then
  710. encounteredError = true
  711. end
  712. end
  713. end
  714. local numMail, totalMail = GetInboxNumItems()
  715. if attemptedToOpenMail and totalMail > numMail and numMail < 50 and (private.mode == "all" or private.modeModified) then
  716. -- wait for the inbox to update and then continue
  717. while true do
  718. local numMail, totalMail = GetInboxNumItems()
  719. if numMail == 50 or numMail == totalMail then break end
  720. self:Sleep(0.5)
  721. end
  722. self:Sleep(1)
  723. elseif not attemptedToOpenMail and encounteredError then
  724. TSM:Print(L["Cannot finish auto looting, inventory is full or too many unique items."])
  725. else
  726. shouldWait = true
  727. end
  728. end
  729.  
  730. -- check if we ran out of
  731. if private.keepFreeSlots then
  732. TSM:Printf(L["Stopped opening mail to keep %d slots free."], TSM.db.global.keepMailSpace)
  733. private.keepFreeSlots = nil
  734. end
  735.  
  736. if private.inventoryFull then
  737. TSM:Print(L["Cannot finish auto looting, inventory is full or too many unique items."])
  738. private.inventoryFull = nil
  739. end
  740.  
  741. -- play sound
  742. TSMAPI:DoPlaySound(TSM.db.global.openMailSound)
  743. end
  744.  
  745. function private:MailThreadDone()
  746. if not private.threadId then return end
  747. -- Tell user how much money has been collected if enabled
  748. if private.moneyCollected > 0 and TSM.db.global.displayMoneyCollected then
  749. TSM:Printf(L["Total Gold Collected: %s"], TSMAPI:MoneyToString(private.moneyCollected))
  750. private.moneyCollected = 0
  751. end
  752.  
  753. TSMAPI.Threading:Kill(private.threadId)
  754. private.threadId = nil
  755. private.mode = nil
  756. private.modeModified = nil
  757. private.frame.allBtn:Enable()
  758. private.frame.salesBtn:Enable()
  759. private.frame.buysBtn:Enable()
  760. private.frame.cancelsBtn:Enable()
  761. private.frame.expiresBtn:Enable()
  762. end
  763.  
  764. function private:StartOpenMail(mode)
  765. private:MailThreadDone()
  766. private.mode = mode
  767. private.modeModified = IsShiftKeyDown()
  768. private.threadId = TSMAPI.Threading:Start(private.OpenMailThread, 0.7, private.MailThreadDone)
  769. end
  770.  
  771. function private:GetFirstInboxItemLink(index)
  772. if not TSMMailingInboxTooltip then
  773. CreateFrame("GameTooltip", "TSMMailingInboxTooltip", UIParent, "GameTooltipTemplate")
  774. end
  775. TSMMailingInboxTooltip:SetOwner(UIParent, "ANCHOR_NONE")
  776. TSMMailingInboxTooltip:ClearLines()
  777. local _, speciesId, level, breedQuality, maxHealth, power, speed, name = TSMMailingInboxTooltip:SetInboxItem(index)
  778. local link = nil
  779. if (speciesId or 0) > 0 then
  780. link = TSMAPI.Item:GetLink(strjoin(":", "p", speciesId, level, breedQuality, maxHealth, power, speed))
  781. else
  782. link = GetInboxItemLink(index, 1)
  783. end
  784. TSMMailingInboxTooltip:Hide()
  785. return link
  786. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement