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
-- ------------------------------------------------------------------------------ -- |
|
-- 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 |