You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
7.4 KiB
234 lines
7.4 KiB
|
4 years ago
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
-- TradeSkillMaster_Mailing --
|
||
|
|
-- http://www.curse.com/addons/wow/tradeskillmaster_mailing --
|
||
|
|
-- --
|
||
|
|
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||
|
|
-- All Rights Reserved* - Detailed license information included with addon. --
|
||
|
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
|
||
|
|
local TSM = select(2, ...)
|
||
|
|
local AutoMail = TSM:NewModule("AutoMail", "AceEvent-3.0")
|
||
|
|
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Mailing") -- loads the localization table
|
||
|
|
|
||
|
|
local private = {}
|
||
|
|
|
||
|
|
|
||
|
|
function AutoMail:OnEnable()
|
||
|
|
AutoMail:RegisterEvent("MAIL_CLOSED", private.StopSending)
|
||
|
|
end
|
||
|
|
|
||
|
|
function AutoMail:SendItems(items, target, callback, codPerItem)
|
||
|
|
if private.isSending or TSMAPI:IsPlayer(target) or not MailFrame:IsVisible() then return end
|
||
|
|
private.isSending = true
|
||
|
|
private.items = items
|
||
|
|
private.target = target
|
||
|
|
private.callback = callback
|
||
|
|
private.codPerItem = codPerItem
|
||
|
|
private.waitingLocations = {}
|
||
|
|
TSMAPI:CreateTimeDelay("mailingSendDelay", 0, private.SendNextMail, TSM.db.global.sendDelay)
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
-- returns the number of items currently attached to the mail
|
||
|
|
function private:GetNumPendingAttachments()
|
||
|
|
local totalAttached = 0
|
||
|
|
for i=1, ATTACHMENTS_MAX_SEND do
|
||
|
|
if GetSendMailItem(i) then
|
||
|
|
totalAttached = totalAttached + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return totalAttached
|
||
|
|
end
|
||
|
|
|
||
|
|
function private:SendNextMail()
|
||
|
|
for _, info in ipairs(private.waitingLocations) do
|
||
|
|
if not GetContainerItemInfo(info.bag, info.slot) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- send off any pending items
|
||
|
|
private:SendOffMail()
|
||
|
|
|
||
|
|
-- fill the mail with the next batch of items
|
||
|
|
local bagsFull = private:FillMail()
|
||
|
|
if #private.waitingLocations > 0 then return end
|
||
|
|
|
||
|
|
-- check if anything was actually put in the mail to be sent
|
||
|
|
if private:GetNumPendingAttachments() == 0 then
|
||
|
|
-- we're done
|
||
|
|
if bagsFull then
|
||
|
|
TSM:Printf(L["Could not send mail due to not having free bag space available to split a stack of items."])
|
||
|
|
end
|
||
|
|
private:StopSending()
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
-- send off this mail
|
||
|
|
private:SendOffMail()
|
||
|
|
end
|
||
|
|
|
||
|
|
function private:SendOffMail()
|
||
|
|
local attachments = private:GetNumPendingAttachments()
|
||
|
|
if attachments == 0 or not private.target then return end
|
||
|
|
SendMailNameEditBox:SetText(private.target)
|
||
|
|
SetSendMailMoney(0)
|
||
|
|
if private.codPerItem then
|
||
|
|
local numItems = 0
|
||
|
|
for i=1, ATTACHMENTS_MAX_SEND do
|
||
|
|
local count = select(3, GetSendMailItem(i))
|
||
|
|
numItems = numItems + count
|
||
|
|
end
|
||
|
|
SetSendMailCOD(private.codPerItem*numItems)
|
||
|
|
else
|
||
|
|
SetSendMailCOD(0)
|
||
|
|
end
|
||
|
|
SendMail(private.target, SendMailSubjectEditBox:GetText() or "TSM_Mailing", "")
|
||
|
|
if TSM.db.global.sendMessages then
|
||
|
|
local items = {}
|
||
|
|
for i=1, attachments do
|
||
|
|
local num = select(3, GetSendMailItem(i))
|
||
|
|
local link = GetSendMailItemLink(i)
|
||
|
|
local itemString = TSMAPI:GetItemString(link)
|
||
|
|
if itemString then
|
||
|
|
items[itemString] = items[itemString] or {num=0, link=link}
|
||
|
|
items[itemString].num = items[itemString].num + num
|
||
|
|
end
|
||
|
|
end
|
||
|
|
local temp = {}
|
||
|
|
for itemString, info in pairs(items) do
|
||
|
|
tinsert(temp, format("%sx%d", info.link, info.num))
|
||
|
|
end
|
||
|
|
local msg = ""
|
||
|
|
local cod = GetSendMailCOD()
|
||
|
|
if cod and cod > 0 then
|
||
|
|
msg = format(L["Sent %s to %s with a COD of %s."], table.concat(temp, ", "), private.target, TSMAPI:FormatTextMoney(cod))
|
||
|
|
else
|
||
|
|
msg = format(L["Sent %s to %s."], table.concat(temp, ", "), private.target)
|
||
|
|
end
|
||
|
|
local function DoPrint()
|
||
|
|
if private:GetNumPendingAttachments() > 0 then return end
|
||
|
|
TSMAPI:CancelFrame("sendMailPrintDelay")
|
||
|
|
TSM:Printf(msg)
|
||
|
|
end
|
||
|
|
TSMAPI:CreateTimeDelay("sendMailPrintDelay", 0, DoPrint, 0.1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- fills the current mail with items to be sent to the target
|
||
|
|
function private:FillMail()
|
||
|
|
if private:GetNumPendingAttachments() ~= 0 then return end
|
||
|
|
|
||
|
|
local locationInfo = {}
|
||
|
|
for bag, slot, itemString, quantity, locked in TSMAPI:GetBagIterator(true) do
|
||
|
|
if not locked then
|
||
|
|
locationInfo[itemString] = locationInfo[itemString] or {}
|
||
|
|
tinsert(locationInfo[itemString], {bag=bag, slot=slot, quantity=quantity})
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local emptySlots = {}
|
||
|
|
for bag=0, NUM_BAG_SLOTS do
|
||
|
|
for slot=1, GetContainerNumSlots(bag) do
|
||
|
|
if not GetContainerItemInfo(bag, slot) then
|
||
|
|
local family = bag == 0 and 0 or GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(bag)))
|
||
|
|
tinsert(emptySlots, {bag=bag, slot=slot, family=family})
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
private.waitingLocations = {}
|
||
|
|
|
||
|
|
for itemString, quantity in pairs(private.items) do
|
||
|
|
if locationInfo[itemString] and quantity > 0 then
|
||
|
|
-- use stack sizes which match exactly first, followed by the smallest stacks
|
||
|
|
local sameSize = {}
|
||
|
|
for i=#locationInfo[itemString], 1, -1 do
|
||
|
|
if locationInfo[itemString][i].quantity == quantity then
|
||
|
|
tinsert(sameSize, locationInfo[itemString][i])
|
||
|
|
tremove(locationInfo[itemString], i)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
sort(locationInfo[itemString], function(a,b) return a.quantity < b.quantity end)
|
||
|
|
for _, info in ipairs(sameSize) do
|
||
|
|
tinsert(locationInfo[itemString], 1, info)
|
||
|
|
end
|
||
|
|
for _, info in ipairs(locationInfo[itemString]) do
|
||
|
|
if quantity == 0 then break end
|
||
|
|
if quantity >= info.quantity then
|
||
|
|
PickupContainerItem(info.bag, info.slot)
|
||
|
|
quantity = quantity - info.quantity
|
||
|
|
private.items[itemString] = quantity
|
||
|
|
|
||
|
|
ClickSendMailItemButton()
|
||
|
|
if private:GetNumPendingAttachments() == ATTACHMENTS_MAX_SEND then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
else
|
||
|
|
-- sort the empty slots such that we'll use special bags first if possible
|
||
|
|
local family = GetItemFamily(itemString)
|
||
|
|
local splitTarget
|
||
|
|
if family > 0 then
|
||
|
|
local specialBags = {}
|
||
|
|
for bag=1, NUM_BAG_SLOTS do
|
||
|
|
local bagFamily = GetItemFamily(GetInventoryItemLink("player", ContainerIDToInventoryID(bag)))
|
||
|
|
if bagFamily and bagFamily > 0 and bit.band(family, bagFamily) > 0 then
|
||
|
|
specialBags[bag] = true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
sort(emptySlots, function(a, b)
|
||
|
|
if specialBags[a.bag] and specialBags[b.bag] then
|
||
|
|
if a.bag == b.bag then
|
||
|
|
return a.slot < b.slot
|
||
|
|
end
|
||
|
|
return a.bag < b.bag
|
||
|
|
end
|
||
|
|
if a.bag == b.bag then
|
||
|
|
return a.slot < b.slot
|
||
|
|
end
|
||
|
|
if specialBags[a.bag] then return true end
|
||
|
|
if specialBags[b.bag] then return false end
|
||
|
|
return a.bag < b.bag
|
||
|
|
end)
|
||
|
|
else
|
||
|
|
sort(emptySlots, function(a, b)
|
||
|
|
if a.bag == b.bag then
|
||
|
|
return a.slot < b.slot
|
||
|
|
end
|
||
|
|
return a.bag < b.bag
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
for i=1, #emptySlots do
|
||
|
|
if emptySlots[i].family == 0 or bit.band(family, emptySlots[i].family) > 0 then
|
||
|
|
splitTarget = emptySlots[i]
|
||
|
|
tremove(emptySlots, i)
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not splitTarget then return true end
|
||
|
|
SplitContainerItem(info.bag, info.slot, quantity)
|
||
|
|
PickupContainerItem(splitTarget.bag, splitTarget.slot)
|
||
|
|
tinsert(private.waitingLocations, splitTarget)
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- check if we want to send only one type of item per mail
|
||
|
|
if TSM.db.global.sendItemsIndividually then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- stops sending mail and calls the callback
|
||
|
|
function private:StopSending()
|
||
|
|
if not private.isSending then return end
|
||
|
|
TSMAPI:CancelFrame("mailingSendDelay")
|
||
|
|
private.isSending = nil
|
||
|
|
private.items = nil
|
||
|
|
private.target = nil
|
||
|
|
private.waitingLocations = {}
|
||
|
|
private.callback()
|
||
|
|
end
|