Compare commits

...

8 Commits

  1. 2
      README.md
  2. 79
      TradeSkillMaster/Auction/AuctionControl.lua
  3. 3
      TradeSkillMaster/Auction/AuctionFrame.lua
  4. 6
      TradeSkillMaster/TradeSkillMaster.lua
  5. 2
      TradeSkillMaster/TradeSkillMaster.toc
  6. 4
      TradeSkillMaster_Accounting/Locale/enUS.lua
  7. 73
      TradeSkillMaster_Accounting/TradeSkillMaster_Accounting.lua
  8. 4
      TradeSkillMaster_AuctionDB/TradeSkillMaster_AuctionDB.toc
  9. 21
      TradeSkillMaster_Auctioning/modules/GUI.lua
  10. 29
      TradeSkillMaster_Crafting/Modules/CraftingGUI.lua
  11. 4
      TradeSkillMaster_Crafting/Modules/Gather.lua
  12. 26
      TradeSkillMaster_Crafting/Modules/Queue.lua
  13. 2
      TradeSkillMaster_Crafting/TradeSkillMaster_Crafting.lua
  14. 106
      TradeSkillMaster_Mailing/Modules/Inbox.lua
  15. 3
      TradeSkillMaster_Mailing/TradeSkillMaster_Mailing.lua
  16. 4
      TradeSkillMaster_Shopping/Locale/enUS.lua
  17. 54
      TradeSkillMaster_Shopping/TradeSkillMaster_Shopping.lua
  18. 15
      TradeSkillMaster_Shopping/modules/Options.lua
  19. 8
      TradeSkillMaster_Shopping/modules/Util.lua
  20. 122
      TradeSkillMaster_Shopping/sidebar/Groups.lua
  21. 18
      TradeSkillMaster_Shopping/sidebar/Other.lua

2
README.md

@ -43,6 +43,8 @@ TSM price strings can reference built-in data sources and combine them with math
### Accounting sources ### Accounting sources
- `avgSell`: Average sell price. - `avgSell`: Average sell price.
- `avgBuy`: Average buy price. - `avgBuy`: Average buy price.
- `smartAvgBuy`: Smart average buy price (uses current holdings to weight recent buys).
- `lastBuy`: Last buy price (most recent purchase; also shown under Last Purchased in Accounting tooltips).
- `maxSell`: Maximum sell price. - `maxSell`: Maximum sell price.
- `maxBuy`: Maximum buy price. - `maxBuy`: Maximum buy price.
- `minSell`: Minimum sell price. - `minSell`: Minimum sell price.

79
TradeSkillMaster/Auction/AuctionControl.lua

@ -15,6 +15,7 @@ TSMAPI:RegisterForTracing(private, "TradeSkillMaster.AuctionControl_private")
LibStub("AceEvent-3.0"):Embed(private) LibStub("AceEvent-3.0"):Embed(private)
private.matchList = {} private.matchList = {}
private.currentPage = {} private.currentPage = {}
private.shoppingPurchasedCounts = {}
local function GetNumInBags(baseItemString) local function GetNumInBags(baseItemString)
@ -43,6 +44,57 @@ local function ValidateAuction(index, list)
return count == private.currentAuction.count and buyout == private.currentAuction.buyout and itemString == private.currentAuction.itemString, data return count == private.currentAuction.count and buyout == private.currentAuction.buyout and itemString == private.currentAuction.itemString, data
end end
local function GetShoppingTotalQuantity(itemString)
itemString = TSMAPI:GetBaseItemString(itemString, true) or itemString
local player, alts = TSMAPI:ModuleAPI("ItemTracker", "playertotal", itemString)
if not player then
alts = nil
end
player = player or 0
alts = alts or 0
local guild = TSMAPI:ModuleAPI("ItemTracker", "guildtotal", itemString) or 0
local auctions = TSMAPI:ModuleAPI("ItemTracker", "auctionstotal", itemString) or 0
local bought = private.shoppingPurchasedCounts[itemString] or 0
return player + alts + guild + auctions + bought
end
local function GetOperationMaxPrice(opSettings, itemString)
if not opSettings or opSettings.maxPrice == nil then return end
if type(opSettings.maxPrice) == "number" then
return opSettings.maxPrice
elseif type(opSettings.maxPrice) == "string" then
local func = TSMAPI:ParseCustomPrice(opSettings.maxPrice)
return func and func(itemString) or nil
end
end
local function ShoppingBuyoutAllowed(itemString, count, perItemBuyout)
local operations = TSMAPI:GetItemOperation(itemString, "Shopping")
if not operations or #operations == 0 then return true end
itemString = TSMAPI:GetBaseItemString(itemString, true) or itemString
for _, opName in ipairs(operations) do
TSMAPI:UpdateOperation("Shopping", opName)
local opSettings = TSM.operations["Shopping"] and TSM.operations["Shopping"][opName]
if opSettings then
local maxRestock = tonumber(opSettings.maxRestock) or 0
local totalQty = GetShoppingTotalQuantity(itemString)
if maxRestock > 0 and (totalQty + count) > maxRestock then
-- over restock for this operation
elseif opSettings.evenStacks and count % 5 ~= 0 then
-- not an even stack for this operation
elseif opSettings.showAboveMaxPrice then
return true
else
local opMaxPrice = GetOperationMaxPrice(opSettings, itemString)
if opMaxPrice and perItemBuyout and perItemBuyout > 0 and perItemBuyout <= opMaxPrice then
return true
end
end
end
end
return false
end
local diffFrame = CreateFrame("Frame") local diffFrame = CreateFrame("Frame")
diffFrame:Hide() diffFrame:Hide()
diffFrame.num = 0 diffFrame.num = 0
@ -146,6 +198,15 @@ end
function private:DoBuyout() function private:DoBuyout()
if private.isSearching or not private.currentAuction or not private.confirmationFrame:IsVisible() then return end if private.isSearching or not private.currentAuction or not private.confirmationFrame:IsVisible() then return end
local perItemBuyout = private.currentAuction.buyout and private.currentAuction.count and (private.currentAuction.buyout / private.currentAuction.count)
if TSM.groupBuyoutCheck and (not perItemBuyout or not TSM.groupBuyoutCheck(private.currentAuction.itemString, private.currentAuction.count, perItemBuyout)) then
TSM:Print("Max restock quantity reached for this item.")
return
end
if private.module == "Shopping" and not ShoppingBuyoutAllowed(private.currentAuction.itemString, private.currentAuction.count, perItemBuyout) then
TSM:Print("Max restock quantity reached for this item.")
return
end
for i=#private.matchList, 1, -1 do for i=#private.matchList, 1, -1 do
local aucIndex = private.matchList[i] local aucIndex = private.matchList[i]
@ -275,6 +336,10 @@ function private:AUCTION_ITEM_LIST_UPDATE()
TSMAPI.AuctionScan:CacheRemove(prevAuction.itemString, private.currentCacheIndex) TSMAPI.AuctionScan:CacheRemove(prevAuction.itemString, private.currentCacheIndex)
private.currentCacheIndex = nil private.currentCacheIndex = nil
end end
if private.module == "Shopping" and prevAuction.itemString and prevAuction.count then
local baseItemString = TSMAPI:GetBaseItemString(prevAuction.itemString, true)
private.shoppingPurchasedCounts[baseItemString] = (private.shoppingPurchasedCounts[baseItemString] or 0) + prevAuction.count
end
TSM:AuctionControlCallback("OnBuyout", prevAuction) TSM:AuctionControlCallback("OnBuyout", prevAuction)
TSMAPI:FireEvent("TSM:AUCTIONCONTROL:ITEMBOUGHT", prevAuction) TSMAPI:FireEvent("TSM:AUCTIONCONTROL:ITEMBOUGHT", prevAuction)
@ -312,6 +377,9 @@ function TSMAPI.AuctionControl:ShowControlButtons(parent, rt, callback, module,
private.rt = rt private.rt = rt
private.callback = callback private.callback = callback
private.module = module private.module = module
if module == "Shopping" then
wipe(private.shoppingPurchasedCounts)
end
private.postBidPercent = postBidPercent private.postBidPercent = postBidPercent
private.postUndercut = postUndercut private.postUndercut = postUndercut
return private.controlButtons return private.controlButtons
@ -348,6 +416,17 @@ function private:ShowConfirmationWindow()
end end
private:SetCurrentAuction(private.rt:GetSelectedAuction()) private:SetCurrentAuction(private.rt:GetSelectedAuction())
if not private.currentAuction then return end if not private.currentAuction then return end
if private.confirmationMode == "Buyout" then
local perItemBuyout = private.currentAuction.buyout and private.currentAuction.count and (private.currentAuction.buyout / private.currentAuction.count)
if TSM.groupBuyoutCheck and (not perItemBuyout or not TSM.groupBuyoutCheck(private.currentAuction.itemString, private.currentAuction.count, perItemBuyout)) then
TSM:Print("Max restock quantity reached for this item.")
return
end
if private.module == "Shopping" and not ShoppingBuyoutAllowed(private.currentAuction.itemString, private.currentAuction.count, perItemBuyout) then
TSM:Print("Max restock quantity reached for this item.")
return
end
end
private:RegisterEvent("AUCTION_ITEM_LIST_UPDATE") private:RegisterEvent("AUCTION_ITEM_LIST_UPDATE")
diffFrame.num = 0 diffFrame.num = 0

3
TradeSkillMaster/Auction/AuctionFrame.lua

@ -43,6 +43,7 @@ function private:CreateTSMAHTab(moduleName, callbackShow, callbackHide)
tab:SetText(TSMAPI.Design:GetInlineColor("link2")..moduleName.."|r") tab:SetText(TSMAPI.Design:GetInlineColor("link2")..moduleName.."|r")
tab:SetNormalFontObject(GameFontHighlightSmall) tab:SetNormalFontObject(GameFontHighlightSmall)
tab.isTSMTab = moduleName tab.isTSMTab = moduleName
_G["TSM"..moduleName.."TabButton"] = tab
tab:SetPoint("LEFT", _G["AuctionFrameTab"..n-1], "RIGHT", -8, 0) tab:SetPoint("LEFT", _G["AuctionFrameTab"..n-1], "RIGHT", -8, 0)
tab:Show() tab:Show()
PanelTemplates_SetNumTabs(AuctionFrame, n) PanelTemplates_SetNumTabs(AuctionFrame, n)
@ -295,4 +296,4 @@ do
else else
private:RegisterEvent("ADDON_LOADED") private:RegisterEvent("ADDON_LOADED")
end end
end end

6
TradeSkillMaster/TradeSkillMaster.lua

@ -735,6 +735,12 @@ function TSMAPI:GetItemPrices(itemLink)
-- Use TSM:GetCustomPrice to get avgBuy price -- Use TSM:GetCustomPrice to get avgBuy price
prices.avgBuy = TSM:GetCustomPrice("avgBuy", itemString) or 0 prices.avgBuy = TSM:GetCustomPrice("avgBuy", itemString) or 0
-- Use TSM:GetCustomPrice to get smartAvgBuy price
prices.smartAvgBuy = TSM:GetCustomPrice("smartAvgBuy", itemString) or 0
-- Use TSM:GetCustomPrice to get lastBuy price
prices.lastBuy = TSM:GetCustomPrice("lastBuy", itemString) or 0
-- Use TSM:GetCustomPrice to get avgSell price -- Use TSM:GetCustomPrice to get avgSell price
prices.avgSell = TSM:GetCustomPrice("avgSell", itemString) or 0 prices.avgSell = TSM:GetCustomPrice("avgSell", itemString) or 0

2
TradeSkillMaster/TradeSkillMaster.toc

@ -2,7 +2,7 @@
## Title: |cff00fe00TradeSkillMaster: Revived|r ## Title: |cff00fe00TradeSkillMaster: Revived|r
## Notes: Core addon for the TradeSkillMaster suite, revived for Wrath of the Lich King. Does nothing without modules installed. ## Notes: Core addon for the TradeSkillMaster suite, revived for Wrath of the Lich King. Does nothing without modules installed.
## Author: Sapu94, Bart39, Gnomezilla [Warmane-Icecrown(A)], BlueAo [Warmane], andrew6180, Yoshiyuka, DimaSheiko, and other contributors... ## Author: Sapu94, Bart39, Gnomezilla [Warmane-Icecrown(A)], BlueAo [Warmane], andrew6180, Yoshiyuka, DimaSheiko, and other contributors...
## Version: 2.3.24 ## Version: 2.3.39
## SavedVariables: TradeSkillMasterAppDB, AscensionTSMDB ## SavedVariables: TradeSkillMasterAppDB, AscensionTSMDB
## OptionalDeps: AccurateTime, Ace3, LibDataBroker-1.1, LibDBIcon-1.0, LibExtraTip, TipHelper, LibParse, LibCompress, LibGraph-2.0, SharedMedia, TheUndermineJournal, TheUndermineJournalGE ## OptionalDeps: AccurateTime, Ace3, LibDataBroker-1.1, LibDBIcon-1.0, LibExtraTip, TipHelper, LibParse, LibCompress, LibGraph-2.0, SharedMedia, TheUndermineJournal, TheUndermineJournalGE
## X-Embeds: AccurateTime, Ace3, LibDataBroker-1.1, LibDBIcon-1.0, LibExtraTip, TipHelper, LibParse, LibCompress, LibGraph-2.0 ## X-Embeds: AccurateTime, Ace3, LibDataBroker-1.1, LibDBIcon-1.0, LibExtraTip, TipHelper, LibParse, LibCompress, LibGraph-2.0

4
TradeSkillMaster_Accounting/Locale/enUS.lua

@ -24,6 +24,10 @@ L["Average Prices:"] = true
L["Avg Buy Price"] = true L["Avg Buy Price"] = true
L["Avg Resale Profit"] = true L["Avg Resale Profit"] = true
L["Avg Sell Price"] = true L["Avg Sell Price"] = true
L["Last Buy Price"] = true
L["Last Buy Price:"] = true
L["Smart Avg Buy Price:"] = true
L["Smart Avg Buy Price"] = true
L["Back to Previous Page"] = true L["Back to Previous Page"] = true
L["Balance"] = true L["Balance"] = true
L["Below is a graph of the your character's gold on hand over time.\n\nThe x-axis is time and goes from %s to %s\nThe y-axis is gold."] = true L["Below is a graph of the your character's gold on hand over time.\n\nThe x-axis is time and goes from %s to %s\nThe y-axis is gold."] = true

73
TradeSkillMaster_Accounting/TradeSkillMaster_Accounting.lua

@ -125,6 +125,8 @@ function TSM:RegisterModule()
TSM.priceSources = { TSM.priceSources = {
{ key = "avgSell", label = L["Avg Sell Price"], callback = "GetAvgSellPrice" }, { key = "avgSell", label = L["Avg Sell Price"], callback = "GetAvgSellPrice" },
{ key = "avgBuy", label = L["Avg Buy Price"], callback = "GetAvgBuyPrice" }, { key = "avgBuy", label = L["Avg Buy Price"], callback = "GetAvgBuyPrice" },
{ key = "smartAvgBuy", label = L["Smart Avg Buy Price"], callback = "GetSmartAvgBuyPrice" },
{ key = "lastBuy", label = L["Last Buy Price"], callback = "GetLastBuyPrice" },
{ key = "maxSell", label = L["Max Sell Price"], callback = "GetMaxSellPrice" }, { key = "maxSell", label = L["Max Sell Price"], callback = "GetMaxSellPrice" },
{ key = "maxBuy", label = L["Max Buy Price"], callback = "GetMaxBuyPrice" }, { key = "maxBuy", label = L["Max Buy Price"], callback = "GetMaxBuyPrice" },
{ key = "minSell", label = L["Min Sell Price"], callback = "GetMinSellPrice" }, { key = "minSell", label = L["Min Sell Price"], callback = "GetMinSellPrice" },
@ -187,6 +189,7 @@ function TSM:GetTooltip(itemString)
if TSM.db.realm.tooltip.purchase and TSM.items[itemString] and #TSM.items[itemString].buys > 0 then if TSM.db.realm.tooltip.purchase and TSM.items[itemString] and #TSM.items[itemString].buys > 0 then
local lastPurchased = TSM.items[itemString].buys[#TSM.items[itemString].buys].time local lastPurchased = TSM.items[itemString].buys[#TSM.items[itemString].buys].time
local lastBuyPrice = TSM:GetLastBuyPrice(itemString)
local totalPrice, totalNum = 0, 0 local totalPrice, totalNum = 0, 0
for _, record in ipairs(TSM.items[itemString].buys) do for _, record in ipairs(TSM.items[itemString].buys) do
totalNum = totalNum + record.quantity totalNum = totalNum + record.quantity
@ -202,15 +205,30 @@ function TSM:GetTooltip(itemString)
else else
local avgPrice = TSM:GetAvgBuyPrice(itemString) local avgPrice = TSM:GetAvgBuyPrice(itemString)
local maxPrice = TSM:GetMaxBuyPrice(itemString) local maxPrice = TSM:GetMaxBuyPrice(itemString)
local smartAvgPrice = TSM:GetSmartAvgBuyPrice(itemString)
if moneyCoinsTooltip then if moneyCoinsTooltip then
tinsert(text, { left = " " .. L["Purchased (Avg/Max Price):"], right = format("%s (%s / %s)", "|cffffffff" .. totalNum .. "|r", (TSMAPI:FormatTextMoneyIcon(avgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")), (TSMAPI:FormatTextMoneyIcon(maxPrice, "|cffffffff", true) or ("|cffffffff" .. "?"))) }) tinsert(text, { left = " " .. L["Purchased (Avg/Max Price):"], right = format("%s (%s / %s)", "|cffffffff" .. totalNum .. "|r", (TSMAPI:FormatTextMoneyIcon(avgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")), (TSMAPI:FormatTextMoneyIcon(maxPrice, "|cffffffff", true) or ("|cffffffff" .. "?"))) })
else else
tinsert(text, { left = " " .. L["Purchased (Avg/Max Price):"], right = format("%s (%s / %s)", "|cffffffff" .. totalNum .. "|r", (TSMAPI:FormatTextMoney(avgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")), (TSMAPI:FormatTextMoney(maxPrice, "|cffffffff", true) or ("|cffffffff" .. "?"))) }) tinsert(text, { left = " " .. L["Purchased (Avg/Max Price):"], right = format("%s (%s / %s)", "|cffffffff" .. totalNum .. "|r", (TSMAPI:FormatTextMoney(avgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")), (TSMAPI:FormatTextMoney(maxPrice, "|cffffffff", true) or ("|cffffffff" .. "?"))) })
end end
if smartAvgPrice then
if moneyCoinsTooltip then
tinsert(text, { left = " " .. L["Smart Avg Buy Price:"], right = (TSMAPI:FormatTextMoneyIcon(smartAvgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")) })
else
tinsert(text, { left = " " .. L["Smart Avg Buy Price:"], right = (TSMAPI:FormatTextMoney(smartAvgPrice, "|cffffffff", true) or ("|cffffffff" .. "?")) })
end
end
end end
if lastPurchased then if lastPurchased then
local timeDiff = SecondsToTime(time() - lastPurchased) local timeDiff = SecondsToTime(time() - lastPurchased)
tinsert(text, { left = " " .. L["Last Purchased:"], right = "|cffffffff" .. format(L["%s ago"], timeDiff) }) tinsert(text, { left = " " .. L["Last Purchased:"], right = "|cffffffff" .. format(L["%s ago"], timeDiff) })
if lastBuyPrice then
if moneyCoinsTooltip then
tinsert(text, { left = " " .. L["Last Buy Price:"], right = (TSMAPI:FormatTextMoneyIcon(lastBuyPrice, "|cffffffff", true) or ("|cffffffff" .. "?")) })
else
tinsert(text, { left = " " .. L["Last Buy Price:"], right = (TSMAPI:FormatTextMoney(lastBuyPrice, "|cffffffff", true) or ("|cffffffff" .. "?")) })
end
end
end end
end end
@ -424,12 +442,24 @@ function TSM:GetAvgSellPrice(itemString)
return TSM.cache[itemString].avgSellPrice, TSM.cache[itemString].avgSellNum return TSM.cache[itemString].avgSellPrice, TSM.cache[itemString].avgSellNum
end end
local function GetAvgerageBuyPrice(itemString, noBaseItem) local function GetSmartBuyItemCount(itemString)
local player, alts = TSMAPI:ModuleAPI("ItemTracker", "playertotal", itemString)
if not player then
alts = nil
end
player = player or 0
alts = alts or 0
local guild = TSMAPI:ModuleAPI("ItemTracker", "guildtotal", itemString) or 0
local auctions = TSMAPI:ModuleAPI("ItemTracker", "auctionstotal", itemString) or 0
return player + alts + guild + auctions
end
local function GetAvgerageBuyPrice(itemString, noBaseItem, useSmart)
if not noBaseItem and itemString and baseItemLookup[itemString] then if not noBaseItem and itemString and baseItemLookup[itemString] then
local totalPrice, totalNum = 0, 0 local totalPrice, totalNum = 0, 0
for _, item in ipairs(baseItemLookup[itemString]) do for _, item in ipairs(baseItemLookup[itemString]) do
if not baseItemLookup[item] then if not baseItemLookup[item] then
local price, num = GetAvgerageBuyPrice(item, true) local price, num = GetAvgerageBuyPrice(item, true, useSmart)
if price and num and num > 0 then if price and num and num > 0 then
totalPrice = totalPrice + price totalPrice = totalPrice + price
totalNum = totalNum + num totalNum = totalNum + num
@ -443,16 +473,11 @@ local function GetAvgerageBuyPrice(itemString, noBaseItem)
if not (TSM.items[itemString] and #TSM.items[itemString].buys > 0) then return end if not (TSM.items[itemString] and #TSM.items[itemString].buys > 0) then return end
local itemCount = 0 local itemCount = 0
if TSM.db.realm.smartBuyPrice then if useSmart or TSM.db.realm.smartBuyPrice then
local player, alts = TSMAPI:ModuleAPI("ItemTracker", "playertotal", itemString) itemCount = GetSmartBuyItemCount(itemString)
if not player then if useSmart and itemCount <= 0 then
alts = nil return
end end
player = player or 0
alts = alts or 0
local guild = TSMAPI:ModuleAPI("ItemTracker", "guildtotal", itemString) or 0
local auctions = TSMAPI:ModuleAPI("ItemTracker", "auctionstotal", itemString) or 0
itemCount = player + alts + guild + auctions
end end
local num, totalPrice = 0, 0 local num, totalPrice = 0, 0
@ -482,6 +507,19 @@ function TSM:GetAvgBuyPrice(itemString)
return TSM.cache[itemString].avgBuyPrice, TSM.cache[itemString].avgBuyNum return TSM.cache[itemString].avgBuyPrice, TSM.cache[itemString].avgBuyNum
end end
function TSM:GetSmartAvgBuyPrice(itemString)
itemString = TSMAPI:GetItemString(select(2, TSMAPI:GetSafeItemInfo(itemString)))
if not itemString then return end
TSM.cache[itemString] = TSM.cache[itemString] or {}
TSM:UpdateBaseItemLookup()
if not TSM.cache[itemString].smartAvgBuyPrice then
local price, num = GetAvgerageBuyPrice(itemString, nil, true)
TSM.cache[itemString].smartAvgBuyPrice = price
TSM.cache[itemString].smartAvgBuyNum = num
end
return TSM.cache[itemString].smartAvgBuyPrice, TSM.cache[itemString].smartAvgBuyNum
end
function TSM:GetMaxSellPrice(itemString) function TSM:GetMaxSellPrice(itemString)
itemString = TSMAPI:GetItemString(select(2, TSMAPI:GetSafeItemInfo(itemString))) itemString = TSMAPI:GetItemString(select(2, TSMAPI:GetSafeItemInfo(itemString)))
if not (itemString and TSM.items[itemString] and #TSM.items[itemString].sales > 0) then return end if not (itemString and TSM.items[itemString] and #TSM.items[itemString].sales > 0) then return end
@ -546,6 +584,19 @@ function TSM:GetMinBuyPrice(itemString)
return TSM.cache[itemString].minBuyPrice return TSM.cache[itemString].minBuyPrice
end end
function TSM:GetLastBuyPrice(itemString)
itemString = TSMAPI:GetItemString(select(2, TSMAPI:GetSafeItemInfo(itemString)))
if not (itemString and TSM.items[itemString] and #TSM.items[itemString].buys > 0) then return end
TSM.cache[itemString] = TSM.cache[itemString] or {}
if not TSM.cache[itemString].lastBuyPrice then
local lastRecord = TSM.items[itemString].buys[#TSM.items[itemString].buys]
TSM.cache[itemString].lastBuyPrice = lastRecord and lastRecord.copper or nil
end
return TSM.cache[itemString].lastBuyPrice
end
function TSM:Round(value, sig) function TSM:Round(value, sig)
sig = sig or 1 sig = sig or 1
local gold = value / sig local gold = value / sig

4
TradeSkillMaster_AuctionDB/TradeSkillMaster_AuctionDB.toc

@ -2,10 +2,10 @@
## Title: |cff00ff00TradeSkillMaster_AuctionDB|r ## Title: |cff00ff00TradeSkillMaster_AuctionDB|r
## Notes: Stores auction house data and calculates market prices. ## Notes: Stores auction house data and calculates market prices.
## Author: Sapu94, Bart39 ## Author: Sapu94, Bart39
## Version: 2.3.24 ## Version: 2.3.39
## SavedVariables: AscensionTSM_AuctionDB ## SavedVariables: AscensionTSM_AuctionDB
## Dependency: TradeSkillMaster ## Dependency: TradeSkillMaster
## X-Curse-Packaged-Version: 2.3.24 ## X-Curse-Packaged-Version: 2.3.39
## X-Curse-Project-Name: TradeSkillMaster_AuctionDB ## X-Curse-Project-Name: TradeSkillMaster_AuctionDB
## X-Curse-Project-ID: tradeskillmaster_auctiondb ## X-Curse-Project-ID: tradeskillmaster_auctiondb
## X-Curse-Repository-ID: wow/tradeskillmaster_auctiondb/mainline ## X-Curse-Repository-ID: wow/tradeskillmaster_auctiondb/mainline

21
TradeSkillMaster_Auctioning/modules/GUI.lua

@ -12,6 +12,17 @@ local GUI = TSM:NewModule("GUI", "AceEvent-3.0", "AceHook-3.0")
local AceGUI = LibStub("AceGUI-3.0") local AceGUI = LibStub("AceGUI-3.0")
local private = {} local private = {}
function private:SetSelectionButtonsEnabled(enabled)
if not private.selectionFrame then return end
local action = enabled and "Enable" or "Disable"
if private.selectionFrame.postBtn then
private.selectionFrame.postBtn[action](private.selectionFrame.postBtn)
end
if private.selectionFrame.cancelBtn then
private.selectionFrame.cancelBtn[action](private.selectionFrame.cancelBtn)
end
end
function private:CreateButtons(parent) function private:CreateButtons(parent)
local height = 24 local height = 24
local frame = CreateFrame("Frame", nil, parent) local frame = CreateFrame("Frame", nil, parent)
@ -62,6 +73,7 @@ function private:CreateButtons(parent)
if self.which == "stop" and self.isDone then if self.which == "stop" and self.isDone then
GUI:HideSelectionFrame() GUI:HideSelectionFrame()
private.selectionFrame:Show() private.selectionFrame:Show()
private:SetSelectionButtonsEnabled(true)
elseif frame:IsVisible() and private.OnAction then elseif frame:IsVisible() and private.OnAction then
private:OnAction(self.which) private:OnAction(self.which)
end end
@ -86,13 +98,14 @@ function private:CreateButtons(parent)
button:SetScript("OnClick", OnClick) button:SetScript("OnClick", OnClick)
frame.cancel = button frame.cancel = button
local button = TSMAPI.GUI:CreateButton(frame, 18) local button = TSMAPI.GUI:CreateButton(frame, 18, "TSMAuctioningSkipButton")
button:SetPoint("TOPLEFT", frame.post, "TOPRIGHT", 5, 0) button:SetPoint("TOPLEFT", frame.post, "TOPRIGHT", 5, 0)
button:SetWidth(60) button:SetWidth(60)
button:SetHeight(height) button:SetHeight(height)
button:SetText(L["Skip"]) button:SetText(L["Skip"])
button.which = "skip" button.which = "skip"
button:SetScript("OnClick", OnClick) button:SetScript("OnClick", OnClick)
_G["TSMAuctioningCancelSkipButton"] = button
frame.skip = button frame.skip = button
local button = TSMAPI.GUI:CreateButton(frame, 18) local button = TSMAPI.GUI:CreateButton(frame, 18)
@ -752,7 +765,7 @@ function GUI:CreateSelectionFrame(parent)
frame.helpText = helpText frame.helpText = helpText
local btnWidth = floor((stContainer:GetWidth() - 10)/3) local btnWidth = floor((stContainer:GetWidth() - 10)/3)
local postBtn = TSMAPI.GUI:CreateButton(frame, 16) local postBtn = TSMAPI.GUI:CreateButton(frame, 16, "TSMAuctioningPostScanButton")
postBtn:SetPoint("BOTTOMLEFT", 5, 5) postBtn:SetPoint("BOTTOMLEFT", 5, 5)
postBtn:SetHeight(20) postBtn:SetHeight(20)
postBtn:SetWidth(btnWidth) postBtn:SetWidth(btnWidth)
@ -764,7 +777,7 @@ function GUI:CreateSelectionFrame(parent)
end) end)
frame.postBtn = postBtn frame.postBtn = postBtn
local cancelBtn = TSMAPI.GUI:CreateButton(frame, 16) local cancelBtn = TSMAPI.GUI:CreateButton(frame, 16, "TSMAuctioningCancelScanButton")
cancelBtn:SetPoint("BOTTOMLEFT", postBtn, "BOTTOMRIGHT", 5, 0) cancelBtn:SetPoint("BOTTOMLEFT", postBtn, "BOTTOMRIGHT", 5, 0)
cancelBtn:SetHeight(20) cancelBtn:SetHeight(20)
cancelBtn:SetWidth(btnWidth) cancelBtn:SetWidth(btnWidth)
@ -908,6 +921,7 @@ function GUI:CreateScanFrame(parent)
end end
function GUI:StartScan(frame) function GUI:StartScan(frame)
private:SetSelectionButtonsEnabled(false)
private.selectionFrame:Hide() private.selectionFrame:Hide()
private.scanFrame = private.scanFrame or GUI:CreateScanFrame(frame) private.scanFrame = private.scanFrame or GUI:CreateScanFrame(frame)
private.scanFrame:Show() private.scanFrame:Show()
@ -967,6 +981,7 @@ function GUI:ShowSelectionFrame(frame)
if private.scanFrame then private.scanFrame:Hide() end if private.scanFrame then private.scanFrame:Hide() end
private.selectionFrame = private.selectionFrame or GUI:CreateSelectionFrame(frame) private.selectionFrame = private.selectionFrame or GUI:CreateSelectionFrame(frame)
private.selectionFrame:Show() private.selectionFrame:Show()
private:SetSelectionButtonsEnabled(true)
TSMAPI.AuctionScan:StopScan(false) TSMAPI.AuctionScan:StopScan(false)
end end

29
TradeSkillMaster_Crafting/Modules/CraftingGUI.lua

@ -2834,7 +2834,7 @@ function GUI:UpdateGathering()
if task.taskType == L["Search for Mats"] then if task.taskType == L["Search for Mats"] then
availQty = taskQuantity availQty = taskQuantity
end end
if task.taskType == L["Mail Items"] then if task.taskType == L["Mail Items"] or task.taskType == L["Collect Mail"] then
availQty = min(need, taskQuantity) availQty = min(need, taskQuantity)
elseif not crafter == UnitName("player") then elseif not crafter == UnitName("player") then
availQty = min(need, taskQuantity) - (playerBags[itemString] or 0) availQty = min(need, taskQuantity) - (playerBags[itemString] or 0)
@ -2878,16 +2878,18 @@ function GUI:UpdateGathering()
TSM.db.realm.gathering.availableMats = CopyTable(availableMats) TSM.db.realm.gathering.availableMats = CopyTable(availableMats)
GUI.gatheringFrame.gatherButton:SetText(L["Gather Items"]) GUI.gatheringFrame.gatherButton:SetText(L["Gather Items"])
if next(stData) then if next(stData) then
GUI.gatheringFrame.gatherButton:Enable() GUI.gatheringFrame.gatherButton:Enable()
if private.currentTask == L["Visit Vendor"] then if private.currentTask == L["Visit Vendor"] then
GUI.gatheringFrame.gatherButton:SetText(L["Buy Vendor Items"]) GUI.gatheringFrame.gatherButton:SetText(L["Buy Vendor Items"])
elseif private.currentTask == L["Mail Items"] then elseif private.currentTask == L["Mail Items"] then
GUI.gatheringFrame.gatherButton:SetText(L["Mail Items"]) GUI.gatheringFrame.gatherButton:SetText(L["Mail Items"])
elseif private.currentTask == L["Collect Mail"] then
GUI.gatheringFrame.gatherButton:SetText(L["Collect Mail"])
end
else
GUI.gatheringFrame.gatherButton:Disable()
end end
else
GUI.gatheringFrame.gatherButton:Disable()
end
sort(stData, function(a, b) return a.name < b.name end) sort(stData, function(a, b) return a.name < b.name end)
GUI.gatheringFrame.availableST:SetData(stData) GUI.gatheringFrame.availableST:SetData(stData)
@ -2919,7 +2921,12 @@ function GUI:GatheringEventHandler(event)
GUI.gatheringFrame.gatherButton:Disable() GUI.gatheringFrame.gatherButton:Disable()
elseif event == "MAIL_SHOW" then elseif event == "MAIL_SHOW" then
private.currentSource = UnitName("player") private.currentSource = UnitName("player")
private.currentTask = L["Mail Items"] local crafter = TSM.db.realm.gathering.crafter
if crafter and crafter == UnitName("player") then
private.currentTask = L["Collect Mail"]
else
private.currentTask = L["Mail Items"]
end
elseif event == "MAIL_CLOSED" then elseif event == "MAIL_CLOSED" then
private.currentSource = nil private.currentSource = nil
private.currentTask = nil private.currentTask = nil

4
TradeSkillMaster_Crafting/Modules/Gather.lua

@ -36,6 +36,8 @@ function Gather:gatherItems(source, task)
Gather:BuyFromMerchant(items) Gather:BuyFromMerchant(items)
elseif source == UnitName("player") and (task == L["Visit Bank"] or task == L["Visit Guild Bank"]) then elseif source == UnitName("player") and (task == L["Visit Bank"] or task == L["Visit Guild Bank"]) then
Gather:GatherBank(items) Gather:GatherBank(items)
elseif source == UnitName("player") and task == L["Collect Mail"] then
TSMAPI:ModuleAPI("Mailing", "collectItems", items, Gather.PrintMsg)
elseif source == UnitName("player") and task == L["Mail Items"] then elseif source == UnitName("player") and task == L["Mail Items"] then
Gather:MailItems(items) Gather:MailItems(items)
elseif source == L["Auction House"] then elseif source == L["Auction House"] then
@ -185,4 +187,4 @@ function Gather:ShoppingSearch(itemString, need, ignoreMaxQty)
TSMAPI:ModuleAPI("Shopping", "runSearch", TSMAPI:GetSafeItemInfo(itemString) .. "/exact/x" .. need, ShoppingCallback) TSMAPI:ModuleAPI("Shopping", "runSearch", TSMAPI:GetSafeItemInfo(itemString) .. "/exact/x" .. need, ShoppingCallback)
end end
end end
end end

26
TradeSkillMaster_Crafting/Modules/Queue.lua

@ -33,6 +33,9 @@ end
function Queue:CreateRestockQueue(groupInfo) function Queue:CreateRestockQueue(groupInfo)
TSM:UpdateCraftReverseLookup() TSM:UpdateCraftReverseLookup()
local numItems = 0 local numItems = 0
local bestQueued = {}
local bestSpellID = {}
local seenItems = {}
for _, data in pairs(groupInfo) do for _, data in pairs(groupInfo) do
for _, opName in ipairs(data.operations) do for _, opName in ipairs(data.operations) do
@ -42,6 +45,7 @@ function Queue:CreateRestockQueue(groupInfo)
-- it's a valid operation -- it's a valid operation
for itemString in pairs(data.items) do for itemString in pairs(data.items) do
itemString = TSMAPI:GetItemString(itemString) itemString = TSMAPI:GetItemString(itemString)
seenItems[itemString] = true
local spellID = TSM.craftReverseLookup[itemString] and TSM.craftReverseLookup[itemString][1] local spellID = TSM.craftReverseLookup[itemString] and TSM.craftReverseLookup[itemString][1]
if spellID and TSM.db.realm.crafts[spellID] then if spellID and TSM.db.realm.crafts[spellID] then
local maxQueueCount = max(opSettings.maxRestock - TSM.Inventory:GetTotalQuantity(itemString), 0) local maxQueueCount = max(opSettings.maxRestock - TSM.Inventory:GetTotalQuantity(itemString), 0)
@ -61,16 +65,28 @@ function Queue:CreateRestockQueue(groupInfo)
end end
local craft = TSM.db.realm.crafts[spellID] local craft = TSM.db.realm.crafts[spellID]
craft.queued = floor(numToQueue / craft.numResult) local queued = floor(numToQueue / craft.numResult)
craft.queued = craft.queued >= opSettings.minRestock and craft.queued or 0 queued = queued >= opSettings.minRestock and queued or 0
if craft.queued > 0 then if queued > 0 and queued > (bestQueued[itemString] or 0) then
numItems = numItems + 1 bestQueued[itemString] = queued
bestSpellID[itemString] = spellID
end end
end end
end end
end end
end end
end end
for itemString in pairs(seenItems) do
local queued = bestQueued[itemString] or 0
local spellID = bestSpellID[itemString] or (TSM.craftReverseLookup[itemString] and TSM.craftReverseLookup[itemString][1])
if spellID and TSM.db.realm.crafts[spellID] then
TSM.db.realm.crafts[spellID].queued = queued
if queued > 0 then
numItems = numItems + 1
end
end
end
if numItems==0 then if numItems==0 then
TSM:Printf("There are no items to restock.") TSM:Printf("There are no items to restock.")
@ -254,4 +270,4 @@ end
function Queue:getQueue(spellID) function Queue:getQueue(spellID)
local craft = TSM.db.realm.crafts[spellID] local craft = TSM.db.realm.crafts[spellID]
return craft.queued return craft.queued
end end

2
TradeSkillMaster_Crafting/TradeSkillMaster_Crafting.lua

@ -105,7 +105,7 @@ end
-- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule(). -- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule().
function TSM:RegisterModule() function TSM:RegisterModule()
TSM.icons = { { side = "module", desc = "Crafting", slashCommand = "crafting", callback = "Options:LoadCrafting", icon = "Interface\\Icons\\INV_Misc_Gear_08" } } TSM.icons = { { side = "module", desc = "Crafting", slashCommand = "crafting", callback = "Options:LoadCrafting", icon = "Interface\\Icons\\INV_Misc_Gear_08" } }
TSM.operations = { maxOperations = 1, callbackOptions = "Options:Load", callbackInfo = "GetOperationInfo" } TSM.operations = { maxOperations = 5, callbackOptions = "Options:Load", callbackInfo = "GetOperationInfo" }
TSM.priceSources = { TSM.priceSources = {
{ key = "Crafting", label = L["Crafting Cost"], callback = "GetCraftingCost" }, { key = "Crafting", label = L["Crafting Cost"], callback = "GetCraftingCost" },
{ key = "matPrice", label = L["Crafting Material Cost"], callback = "GetCraftingMatCost" }, { key = "matPrice", label = L["Crafting Material Cost"], callback = "GetCraftingMatCost" },

106
TradeSkillMaster_Mailing/Modules/Inbox.lua

@ -74,7 +74,7 @@ function Inbox:CreateTab(parent)
st:SetData({}) st:SetData({})
frame.st = st frame.st = st
local btn = TSMAPI.GUI:CreateButton(frame, 18) local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMMailingOpenAllButton")
btn:SetPoint("BOTTOMLEFT", 5, 30) btn:SetPoint("BOTTOMLEFT", 5, 30)
btn:SetPoint("BOTTOMRIGHT", -5, 30) btn:SetPoint("BOTTOMRIGHT", -5, 30)
btn:SetHeight(20) btn:SetHeight(20)
@ -91,7 +91,7 @@ function Inbox:CreateTab(parent)
local btnWidth = (frame:GetWidth() - label:GetWidth() - 25) / 5 local btnWidth = (frame:GetWidth() - label:GetWidth() - 25) / 5
local btn = TSMAPI.GUI:CreateButton(frame, 18) local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMMailingSalesButton")
btn:SetPoint("BOTTOMLEFT", label, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMLEFT", label, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth) btn:SetWidth(btnWidth)
btn:SetHeight(20) btn:SetHeight(20)
@ -99,7 +99,7 @@ function Inbox:CreateTab(parent)
btn:SetScript("OnClick", function() private:StartAutoLooting("sales") end) btn:SetScript("OnClick", function() private:StartAutoLooting("sales") end)
frame.salesBtn = btn frame.salesBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18) local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMMailingBuysButton")
btn:SetPoint("BOTTOMLEFT", frame.salesBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMLEFT", frame.salesBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth) btn:SetWidth(btnWidth)
btn:SetHeight(20) btn:SetHeight(20)
@ -107,7 +107,7 @@ function Inbox:CreateTab(parent)
btn:SetScript("OnClick", function() private:StartAutoLooting("buys") end) btn:SetScript("OnClick", function() private:StartAutoLooting("buys") end)
frame.buysBtn = btn frame.buysBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18) local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMMailingCancelsButton")
btn:SetPoint("BOTTOMLEFT", frame.buysBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMLEFT", frame.buysBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth) btn:SetWidth(btnWidth)
btn:SetHeight(20) btn:SetHeight(20)
@ -115,7 +115,7 @@ function Inbox:CreateTab(parent)
btn:SetScript("OnClick", function() private:StartAutoLooting("cancels") end) btn:SetScript("OnClick", function() private:StartAutoLooting("cancels") end)
frame.cancelsBtn = btn frame.cancelsBtn = btn
local btn = TSMAPI.GUI:CreateButton(frame, 18) local btn = TSMAPI.GUI:CreateButton(frame, 18, "TSMMailingExpiresButton")
btn:SetPoint("BOTTOMLEFT", frame.cancelsBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMLEFT", frame.cancelsBtn, "BOTTOMRIGHT", 5, 0)
btn:SetWidth(btnWidth) btn:SetWidth(btnWidth)
btn:SetHeight(20) btn:SetHeight(20)
@ -436,6 +436,102 @@ function private:StartAutoLooting(mode)
private:AutoLoot() private:AutoLoot()
end end
local function CanLootItem(itemString, quantity)
if not itemString or not quantity then return false end
local maxStack = select(8, TSMAPI:GetSafeItemInfo(itemString))
local hasPartial = false
local hasEmpty = false
local totalFreeSlots = 0
for bag = 0, NUM_BAG_SLOTS do
if TSMAPI:ItemWillGoInBag(itemString, bag) then
totalFreeSlots = totalFreeSlots + (GetContainerNumFreeSlots(bag) or 0)
for slot = 1, GetContainerNumSlots(bag) do
local iLink = GetContainerItemLink(bag, slot)
if iLink then
if TSMAPI:GetItemString(iLink) == itemString and maxStack then
local stackSize = select(2, GetContainerItemInfo(bag, slot))
if stackSize and (maxStack - stackSize) >= quantity then
hasPartial = true
end
end
else
hasEmpty = true
end
end
end
end
if hasPartial then
return true
end
if not hasEmpty then
return false
end
if TSM.db.global.keepMailSpace and TSM.db.global.keepMailSpace > 0 then
return (totalFreeSlots - 1) >= TSM.db.global.keepMailSpace
end
return true
end
local function HasFittableStack(itemString, needed)
if not itemString or not needed or needed <= 0 then return false end
for i = 1, GetInboxNumItems() do
local _, _, _, _, _, cod, _, hasItem = GetInboxHeaderInfo(i)
if hasItem and hasItem > 0 and (not cod or cod == 0) then
for j = 1, hasItem do
local itemLink = GetInboxItemLink(i, j)
if itemLink and TSMAPI:GetItemString(itemLink) == itemString then
local quantity = select(3, GetInboxItem(i, j)) or 0
if quantity > 0 and quantity <= needed then
return true
end
end
end
end
end
return false
end
function Inbox:CollectItems(items, callback)
if not items or not next(items) then return end
if not MailFrame or not MailFrame:IsShown() then return end
local remaining = CopyTable(items)
local collected = false
for i = GetInboxNumItems(), 1, -1 do
local _, _, _, _, _, cod, _, hasItem = GetInboxHeaderInfo(i)
if hasItem and hasItem > 0 and (not cod or cod == 0) then
for j = hasItem, 1, -1 do
local itemLink = GetInboxItemLink(i, j)
local itemString = itemLink and TSMAPI:GetItemString(itemLink)
local need = itemString and remaining[itemString]
if need and need > 0 then
local quantity = select(3, GetInboxItem(i, j)) or 0
if quantity > 0 and (quantity <= need or not HasFittableStack(itemString, need)) then
if CanLootItem(itemString, quantity) then
TakeInboxItem(i, j)
remaining[itemString] = max(need - quantity, 0)
collected = true
elseif callback then
callback(L["Cannot finish auto looting, inventory is full or too many unique items."])
return
end
end
end
end
end
end
-- Keep looting as new mail indexes shift, while preserving 1 free slot.
if collected then
TSMAPI:CreateTimeDelay("craftingGatherMailLoop", 0.4, function()
Inbox:CollectItems(remaining, callback)
end)
end
end
function private:AutoLoot() function private:AutoLoot()
TSMAPI:CancelFrame("mailSkipDelay") TSMAPI:CancelFrame("mailSkipDelay")

3
TradeSkillMaster_Mailing/TradeSkillMaster_Mailing.lua

@ -62,6 +62,7 @@ function TSM:RegisterModule()
TSM.operations = {maxOperations=12, callbackOptions="Options:Load", callbackInfo="GetOperationInfo"} TSM.operations = {maxOperations=12, callbackOptions="Options:Load", callbackInfo="GetOperationInfo"}
TSM.moduleAPIs = { TSM.moduleAPIs = {
{key="mailItems", callback="AutoMail:SendItems"}, {key="mailItems", callback="AutoMail:SendItems"},
{key="collectItems", callback="Inbox:CollectItems"},
} }
TSMAPI:NewModule(TSM) TSMAPI:NewModule(TSM)
@ -89,4 +90,4 @@ function TSM:GetOperationInfo(operationName)
else else
return format(L["Mailing all to %s."], operation.target) return format(L["Mailing all to %s."], operation.target)
end end
end end

4
TradeSkillMaster_Shopping/Locale/enUS.lua

@ -81,6 +81,8 @@ L["Max Disenchant Level"] = true
L["Max Disenchant Search Percent"] = true L["Max Disenchant Search Percent"] = true
L["Max Shopping Price:"] = true L["Max Shopping Price:"] = true
L["Maximum Auction Price (per item)"] = true L["Maximum Auction Price (per item)"] = true
L["Max Restock Quantity"] = true
L["If set above 0, Shopping will only buy up to this total quantity for items in groups using this operation."] = true
L["Maximum Quantity to Buy:"] = true L["Maximum Quantity to Buy:"] = true
L["Maximum quantity purchased for %s."] = true L["Maximum quantity purchased for %s."] = true
L["Maximum quantity purchased for destroy search."] = true L["Maximum quantity purchased for destroy search."] = true
@ -159,4 +161,4 @@ L["Warning: The max disenchant level must be higher than the min disenchant leve
L["Warning: The min disenchant level must be lower than the max disenchant level."] = true L["Warning: The min disenchant level must be lower than the max disenchant level."] = true
L["What to set the default undercut to when posting items with Shopping."] = true L["What to set the default undercut to when posting items with Shopping."] = true
L["When in destroy mode, you simply enter a target item (ink/pigment, enchanting mat, gem, etc) into the search box to search for everything you can destroy to get that item."] = true L["When in destroy mode, you simply enter a target item (ink/pigment, enchanting mat, gem, etc) into the search box to search for everything you can destroy to get that item."] = true
L["When in normal mode, you may run simple and filtered searches of the auction house."] = true L["When in normal mode, you may run simple and filtered searches of the auction house."] = true

54
TradeSkillMaster_Shopping/TradeSkillMaster_Shopping.lua

@ -53,7 +53,7 @@ end
-- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule(). -- registers this module with TSM by first setting all fields and then calling TSMAPI:NewModule().
function TSM:RegisterModule() function TSM:RegisterModule()
TSM.operations = { maxOperations = 1, callbackOptions = "Options:Load", callbackInfo = "GetOperationInfo" } TSM.operations = { maxOperations = 5, callbackOptions = "Options:Load", callbackInfo = "GetOperationInfo" }
TSM.auctionTab = { callbackShow = "Search:Show", callbackHide = "Search:Hide" } TSM.auctionTab = { callbackShow = "Search:Show", callbackHide = "Search:Hide" }
TSM.tooltipOptions = { callback = "Options:LoadTooltipOptions" } TSM.tooltipOptions = { callback = "Options:LoadTooltipOptions" }
TSM.moduleAPIs = { TSM.moduleAPIs = {
@ -68,6 +68,7 @@ end
TSM.operationDefaults = { TSM.operationDefaults = {
maxPrice = 1, maxPrice = 1,
maxRestock = 0,
evenStacks = nil, evenStacks = nil,
showAboveMaxPrice = nil, showAboveMaxPrice = nil,
ignorePlayer = {}, ignorePlayer = {},
@ -125,6 +126,19 @@ function TSM:GetMaxPrice(operationPrice, itemString)
return price ~= 0 and price or nil, err return price ~= 0 and price or nil, err
end end
function TSM:GetTotalQuantity(itemString)
itemString = TSMAPI:GetBaseItemString(itemString, true) or itemString
local player, alts = TSMAPI:ModuleAPI("ItemTracker", "playertotal", itemString)
if not player then
alts = nil
end
player = player or 0
alts = alts or 0
local guild = TSMAPI:ModuleAPI("ItemTracker", "guildtotal", itemString) or 0
local auctions = TSMAPI:ModuleAPI("ItemTracker", "auctionstotal", itemString) or 0
return player + alts + guild + auctions
end
function TSM:AddSidebarFeature(...) function TSM:AddSidebarFeature(...)
TSM.modules.Sidebar:AddSidebarFeature(...) TSM.modules.Sidebar:AddSidebarFeature(...)
end end
@ -136,23 +150,35 @@ function TSM:GetTooltip(itemString)
itemString = TSMAPI:GetBaseItemString(itemString, true) itemString = TSMAPI:GetBaseItemString(itemString, true)
local operations = TSMAPI:GetItemOperation(itemString, "Shopping") local operations = TSMAPI:GetItemOperation(itemString, "Shopping")
if not operations then return end if not operations then return end
local operationName = operations[1] local maxPrice
TSMAPI:UpdateOperation("Shopping", operationName) local totalQty = TSM:GetTotalQuantity(itemString) or 0
local operation = TSM.operations[operationName] for _, operationName in ipairs(operations) do
if operation then TSMAPI:UpdateOperation("Shopping", operationName)
local maxPrice = TSM:GetMaxPrice(operation.maxPrice, itemString) local operation = TSM.operations[operationName]
if maxPrice then if operation then
local priceText local maxRestock = tonumber(operation.maxRestock) or 0
if moneyCoinsTooltip then if maxRestock > 0 and totalQty >= maxRestock then
priceText = (TSMAPI:FormatTextMoneyIcon(maxPrice, "|cffffffff", true) or "|cffffffff---|r") operation = nil
else end
priceText = (TSMAPI:FormatTextMoney(maxPrice, "|cffffffff", true) or "|cffffffff---|r") end
if operation then
local price = TSM:GetMaxPrice(operation.maxPrice, itemString)
if price then
maxPrice = maxPrice and max(maxPrice, price) or price
end end
tinsert(text, { left = " " .. L["Max Shopping Price:"], right = format("%s", priceText) })
end end
end end
if maxPrice then
local priceText
if moneyCoinsTooltip then
priceText = (TSMAPI:FormatTextMoneyIcon(maxPrice, "|cffffffff", true) or "|cffffffff---|r")
else
priceText = (TSMAPI:FormatTextMoney(maxPrice, "|cffffffff", true) or "|cffffffff---|r")
end
tinsert(text, { left = " " .. L["Max Shopping Price:"], right = format("%s", priceText) })
end
if #text > 0 then if #text > 0 then
tinsert(text, 1, "|cffffff00" .. "TSM Shopping:") tinsert(text, 1, "|cffffff00" .. "TSM Shopping:")
return text return text
end end
end end

15
TradeSkillMaster_Shopping/modules/Options.lua

@ -305,6 +305,18 @@ function Options:DrawOperationGeneral(container, operationName)
disabled = operation.relationships.maxprice, disabled = operation.relationships.maxprice,
tooltip = L["The highest price per item you will pay for items in affected by this operation."], tooltip = L["The highest price per item you will pay for items in affected by this operation."],
}, },
{
type = "Slider",
settingInfo = { operation, "maxRestock" },
label = L["Max Restock Quantity"],
disabled = operation.relationships.maxRestock,
isPercent = false,
min = 0,
max = 5000,
step = 1,
relativeWidth = 0.49,
tooltip = L["If set above 0, Shopping will only buy up to this total quantity for items in groups using this operation."],
},
{ {
type = "CheckBox", type = "CheckBox",
label = L["Show Auctions Above Max Price"], label = L["Show Auctions Above Max Price"],
@ -333,6 +345,7 @@ function Options:DrawOperationRelationships(container, operationName)
{ {
label = L["General Settings"], label = L["General Settings"],
{ key = "maxPrice", label = L["Maximum Auction Price (per item)"] }, { key = "maxPrice", label = L["Maximum Auction Price (per item)"] },
{ key = "maxRestock", label = L["Max Restock Quantity"] },
{ key = "showAboveMaxPrice", label = L["Show Auctions Above Max Price"] }, { key = "showAboveMaxPrice", label = L["Show Auctions Above Max Price"] },
{ key = "evenStacks", label = L["Even (5/10/15/20) Stacks Only"] }, { key = "evenStacks", label = L["Even (5/10/15/20) Stacks Only"] },
}, },
@ -359,4 +372,4 @@ function Options:LoadTooltipOptions(container)
} }
TSMAPI:BuildPage(container, page) TSMAPI:BuildPage(container, page)
end end

8
TradeSkillMaster_Shopping/modules/Util.lua

@ -91,6 +91,12 @@ function private:CreateSearchFrame()
private.controlButtons.cancel:Disable() private.controlButtons.cancel:Disable()
private.controlButtons.post:Disable() private.controlButtons.post:Disable()
end end
if private.controlButtons.buyout:IsEnabled() and TSM.groupBuyoutCheck then
local perItemBuyout = data.auctionRecord.GetItemBuyout and data.auctionRecord:GetItemBuyout() or data.auctionRecord.buyout
if not TSM.groupBuyoutCheck(data.itemString, data.auctionRecord.count, perItemBuyout) then
private.controlButtons.buyout:Disable()
end
end
if private:HasInBags(TSMAPI:GetBaseItemString(data.itemString)) then if private:HasInBags(TSMAPI:GetBaseItemString(data.itemString)) then
private.controlButtons.post:Enable() private.controlButtons.post:Enable()
end end
@ -143,6 +149,8 @@ function Util:HideSearchFrame(forceStop)
TSMAPI.AuctionControl:HideControlButtons() TSMAPI.AuctionControl:HideControlButtons()
TSMAPI.AuctionScan:StopScan(forceStop ~= false) TSMAPI.AuctionScan:StopScan(forceStop ~= false)
TSMAPI.AuctionScan:ClearCache() TSMAPI.AuctionScan:ClearCache()
TSM.searchCallback = nil
TSM.groupBuyoutCheck = nil
end end

122
TradeSkillMaster_Shopping/sidebar/Groups.lua

@ -1,7 +1,25 @@
local TSM = select(2, ...) local TSM = select(2, ...)
local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Shopping") -- loads the localization table local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Shopping") -- loads the localization table
local private = {itemOperations={}} local private = {itemOperations={}, purchasedCounts={}}
local function GetActiveOperations(itemString, operations)
if not operations or #operations == 0 then return end
local totalQty = TSM:GetTotalQuantity(itemString) or 0
totalQty = totalQty + (private.purchasedCounts[itemString] or 0)
local active = {}
for _, opName in ipairs(operations) do
TSMAPI:UpdateOperation("Shopping", opName)
local opSettings = TSM.operations[opName]
if opSettings then
local maxRestock = tonumber(opSettings.maxRestock) or 0
if maxRestock <= 0 or totalQty < maxRestock then
tinsert(active, opSettings)
end
end
end
return active
end
function private.Create(parent) function private.Create(parent)
local frame = CreateFrame("Frame", nil, parent) local frame = CreateFrame("Frame", nil, parent)
@ -39,33 +57,62 @@ function private.ScanCallback(event, ...)
local filter = ... local filter = ...
local maxPrice local maxPrice
for _, itemString in ipairs(filter.items) do for _, itemString in ipairs(filter.items) do
local operation = private.itemOperations[itemString] local operations = GetActiveOperations(itemString, private.itemOperations[itemString])
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString) if not operations or #operations == 0 then return end
if not operationPrice then return end local itemMaxPrice
if operation.showAboveMaxPrice then for _, operation in ipairs(operations) do
if operation.showAboveMaxPrice then
itemMaxPrice = nil
break
end
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString)
if operationPrice then
itemMaxPrice = itemMaxPrice and max(itemMaxPrice, operationPrice) or operationPrice
end
end
if itemMaxPrice == nil then
maxPrice = nil maxPrice = nil
break break
end end
maxPrice = maxPrice and max(maxPrice, operationPrice) or operationPrice if not itemMaxPrice then return end
maxPrice = maxPrice and max(maxPrice, itemMaxPrice) or itemMaxPrice
end end
return maxPrice return maxPrice
elseif event == "process" then elseif event == "process" then
local itemString, auctionItem = ... local itemString, auctionItem = ...
-- filter out auctions according to operation settings -- filter out auctions according to operation settings
itemString = TSMAPI:GetBaseItemString(itemString, true) itemString = TSMAPI:GetBaseItemString(itemString, true)
local operation = private.itemOperations[itemString] local operations = GetActiveOperations(itemString, private.itemOperations[itemString])
if not operation then return end if not operations or #operations == 0 then return end
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString)
if not operationPrice then return end
auctionItem:FilterRecords(function(record) auctionItem:FilterRecords(function(record)
if operation.evenStacks and record.count % 5 ~= 0 then local buyout = record:GetItemBuyout() or 0
return true local totalQty = TSM:GetTotalQuantity(itemString) or 0
end totalQty = totalQty + (private.purchasedCounts[itemString] or 0)
if not operation.showAboveMaxPrice then for _, operation in ipairs(operations) do
return (record:GetItemBuyout() or 0) > operationPrice local maxRestock = tonumber(operation.maxRestock) or 0
if maxRestock > 0 and (totalQty + record.count) > maxRestock then
-- this operation can't accept more of this item
elseif operation.evenStacks and record.count % 5 ~= 0 then
-- not an even stack for this operation
elseif operation.showAboveMaxPrice then
return false
else
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString)
if operationPrice and buyout <= operationPrice then
return false
end
end end
end
return true
end) end)
auctionItem:SetMarketValue(operationPrice) local marketValue
for _, operation in ipairs(operations) do
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString)
if operationPrice then
marketValue = marketValue and max(marketValue, operationPrice) or operationPrice
end
end
auctionItem:SetMarketValue(marketValue)
return auctionItem return auctionItem
elseif event == "done" then elseif event == "done" then
TSM.Search:SetSearchBarDisabled(false) TSM.Search:SetSearchBarDisabled(false)
@ -76,6 +123,39 @@ end
function private.StartScan() function private.StartScan()
TSMAPI:FireEvent("SHOPPING:GROUPS:STARTSCAN") TSMAPI:FireEvent("SHOPPING:GROUPS:STARTSCAN")
wipe(private.itemOperations) wipe(private.itemOperations)
wipe(private.purchasedCounts)
TSM.searchCallback = function(event, auction)
if event == "OnBuyout" and auction then
local linkItemString = auction.link and TSMAPI:GetItemString(auction.link)
if linkItemString then
local itemString = TSMAPI:GetBaseItemString(linkItemString, true)
private.purchasedCounts[itemString] = (private.purchasedCounts[itemString] or 0) + (auction.count or 0)
end
end
end
TSM.groupBuyoutCheck = function(itemString, count, buyoutPerItem)
itemString = TSMAPI:GetBaseItemString(itemString, true)
local operations = GetActiveOperations(itemString, private.itemOperations[itemString])
if not operations or #operations == 0 then return false end
for _, operation in ipairs(operations) do
local maxRestock = tonumber(operation.maxRestock) or 0
local totalQty = TSM:GetTotalQuantity(itemString) or 0
totalQty = totalQty + (private.purchasedCounts[itemString] or 0)
if maxRestock > 0 and (totalQty + count) > maxRestock then
-- doesn't fit this operation
elseif operation.evenStacks and count % 5 ~= 0 then
-- not an even stack for this operation
elseif operation.showAboveMaxPrice then
return true
else
local operationPrice = TSM:GetMaxPrice(operation.maxPrice, itemString)
if operationPrice and buyoutPerItem and buyoutPerItem > 0 and buyoutPerItem <= operationPrice then
return true
end
end
end
return false
end
for groupName, data in pairs(private.groupTree:GetSelectedGroupInfo()) do for groupName, data in pairs(private.groupTree:GetSelectedGroupInfo()) do
groupName = TSMAPI:FormatGroupPath(groupName, true) groupName = TSMAPI:FormatGroupPath(groupName, true)
for _, opName in ipairs(data.operations) do for _, opName in ipairs(data.operations) do
@ -87,11 +167,17 @@ function private.StartScan()
else else
-- it's a valid operation -- it's a valid operation
for itemString in pairs(data.items) do for itemString in pairs(data.items) do
local baseItemString = TSMAPI:GetBaseItemString(itemString, true) or itemString
local _, err = TSM:GetMaxPrice(opSettings.maxPrice, itemString) local _, err = TSM:GetMaxPrice(opSettings.maxPrice, itemString)
if err then if err then
TSM:Printf(L["Invalid custom price source for %s. %s"], TSMAPI:GetSafeItemInfo(itemString) or itemString, err) TSM:Printf(L["Invalid custom price source for %s. %s"], TSMAPI:GetSafeItemInfo(itemString) or itemString, err)
else else
private.itemOperations[itemString] = opSettings local totalQty = TSM:GetTotalQuantity(itemString) or 0
local maxRestock = tonumber(opSettings.maxRestock) or 0
if maxRestock <= 0 or totalQty < maxRestock then
private.itemOperations[baseItemString] = private.itemOperations[baseItemString] or {}
tinsert(private.itemOperations[baseItemString], opName)
end
end end
end end
end end
@ -110,4 +196,4 @@ end
do do
TSM:AddSidebarFeature(L["TSM Groups"], private.Create) TSM:AddSidebarFeature(L["TSM Groups"], private.Create)
end end

18
TradeSkillMaster_Shopping/sidebar/Other.lua

@ -230,9 +230,21 @@ function private.SniperScanCallback(event, itemString, auctionItem)
vendorPrice = vendor vendorPrice = vendor
end end
local operations = TSMAPI:GetItemOperation(itemString, "Shopping") local operations = TSMAPI:GetItemOperation(itemString, "Shopping")
local opSettings = operations and operations[1] and TSM.operations[operations[1]] local totalQty = TSM:GetTotalQuantity(itemString) or 0
if opSettings and opSettings.maxPrice then for _, opName in ipairs(operations or {}) do
maxPrice = TSM:GetMaxPrice(opSettings.maxPrice, itemString) TSMAPI:UpdateOperation("Shopping", opName)
local opSettings = TSM.operations[opName]
if opSettings and opSettings.maxPrice then
local maxRestock = tonumber(opSettings.maxRestock) or 0
if maxRestock > 0 and totalQty >= maxRestock then
-- skip this operation if we're already restocked
else
local opPrice = TSM:GetMaxPrice(opSettings.maxPrice, itemString)
if opPrice then
maxPrice = maxPrice and max(maxPrice, opPrice) or opPrice
end
end
end
end end
customPrice = TSM:GetMaxPrice(TSM.db.global.sniperCustomPrice, itemString) customPrice = TSM:GetMaxPrice(TSM.db.global.sniperCustomPrice, itemString)
end end

Loading…
Cancel
Save