local TSM = select ( 2 , ... )
local L = LibStub ( " AceLocale-3.0 " ) : GetLocale ( " TradeSkillMaster_Shopping " ) -- loads the localization table
local private = { sniperItemQuantities = { } , sniperOperationSettings = { } , sniperItemMaxPrices = { } }
local function GetSniperItemQuantity ( itemString )
local quantity = private.sniperItemQuantities [ itemString ]
if quantity == nil then
quantity = TSM : GetTotalQuantity ( itemString ) or 0
private.sniperItemQuantities [ itemString ] = quantity
end
return quantity
end
local function GetSniperOperationSettings ( opName )
local settings = private.sniperOperationSettings [ opName ]
if settings == nil then
TSMAPI : UpdateOperation ( " Shopping " , opName )
settings = TSM.operations [ opName ]
private.sniperOperationSettings [ opName ] = settings or false
end
return settings ~= false and settings or nil
end
local function GetSniperOperationMaxPrice ( itemString , opName , opSettings )
private.sniperItemMaxPrices [ itemString ] = private.sniperItemMaxPrices [ itemString ] or { }
local cached = private.sniperItemMaxPrices [ itemString ] [ opName ]
if cached ~= nil then
return cached ~= false and cached or nil
end
local opPrice = TSM : GetMaxPrice ( opSettings.maxPrice , itemString )
private.sniperItemMaxPrices [ itemString ] [ opName ] = opPrice or false
return opPrice
end
function private . Create ( parent )
local frame = CreateFrame ( " Frame " , nil , parent )
frame : SetAllPoints ( )
private.frame = frame
frame : SetScript ( " OnShow " , function ( )
local lastScan = TSMAPI : ModuleAPI ( " AuctionDB " , " lastCompleteScan " )
for itemID , data in pairs ( lastScan or { } ) do
TSMAPI : GetSafeItemInfo ( itemID ) -- request item info from the server ahead of time
end
end )
local helpText = TSMAPI.GUI : CreateLabel ( frame )
helpText : SetPoint ( " TOPLEFT " )
helpText : SetPoint ( " TOPRIGHT " )
helpText : SetHeight ( 35 )
helpText : SetJustifyH ( " CENTER " )
helpText : SetJustifyV ( " CENTER " )
helpText : SetText ( L [ " The vendor search looks for items on the AH below their vendor sell price. " ] )
local startBtn = TSMAPI.GUI : CreateButton ( frame , 16 )
startBtn : SetPoint ( " TOPLEFT " , helpText , " BOTTOMLEFT " , 3 , - 3 )
startBtn : SetPoint ( " TOPRIGHT " , helpText , " BOTTOMRIGHT " , - 3 , - 3 )
startBtn : SetHeight ( 20 )
startBtn : SetText ( L [ " Start Vendor Search " ] )
startBtn : SetScript ( " OnClick " , private.StartVendorSearch )
TSMAPI.GUI : CreateHorizontalLine ( frame , - 75 )
local helpText2 = TSMAPI.GUI : CreateLabel ( frame )
helpText2 : SetPoint ( " TOPLEFT " , 0 , - 80 )
helpText2 : SetPoint ( " TOPRIGHT " , 0 , - 80 )
helpText2 : SetHeight ( 75 )
helpText2 : SetJustifyH ( " CENTER " )
helpText2 : SetJustifyV ( " CENTER " )
helpText2 : SetText ( L [ " The disenchant search looks for items on the AH below their disenchant value. You can set the maximum percentage of disenchant value to search for in the Shopping General options " ] )
local startBtn2 = TSMAPI.GUI : CreateButton ( frame , 16 )
startBtn2 : SetPoint ( " TOPLEFT " , helpText2 , " BOTTOMLEFT " , 0 , - 3 )
startBtn2 : SetPoint ( " TOPRIGHT " , helpText2 , " BOTTOMRIGHT " , 0 , - 3 )
startBtn2 : SetHeight ( 20 )
startBtn2 : SetText ( L [ " Start Disenchant Search " ] )
startBtn2 : SetScript ( " OnClick " , private.StartDisenchantSearch )
TSMAPI.GUI : CreateHorizontalLine ( frame , - 200 )
local helpText3 = TSMAPI.GUI : CreateLabel ( frame )
helpText3 : SetPoint ( " TOPLEFT " , 0 , - 225 )
helpText3 : SetPoint ( " TOPRIGHT " , 0 , - 225 )
helpText3 : SetHeight ( 80 )
helpText3 : SetJustifyH ( " CENTER " )
helpText3 : SetJustifyV ( " CENTER " )
helpText3 : SetText ( L [ " The Sniper feature will look in real-time for items that have recently been posted to the AH which are worth snatching! You can configure the parameters of Sniper in the Shopping options. " ] )
local helpText4 = TSMAPI.GUI : CreateLabel ( frame )
helpText4 : SetPoint ( " TOPLEFT " , helpText3 , " BOTTOMLEFT " , 0 , - 5 )
helpText4 : SetPoint ( " TOPRIGHT " , helpText3 , " BOTTOMRIGHT " , 0 , - 5 )
helpText4 : SetHeight ( 35 )
helpText4 : SetJustifyH ( " CENTER " )
helpText4 : SetJustifyV ( " CENTER " )
helpText4 : SetText ( L [ " NOTE: The scan must be stopped before you can buy anything. " ] )
local startBtn = TSMAPI.GUI : CreateButton ( frame , 16 )
startBtn : SetPoint ( " TOPLEFT " , helpText4 , " BOTTOMLEFT " , 0 , - 5 )
startBtn : SetWidth ( ( frame : GetWidth ( ) / 2 ) - 2.5 )
startBtn : SetHeight ( 20 )
startBtn : SetText ( L [ " Start Sniper " ] )
startBtn : SetScript ( " OnClick " , private.StartSniperSearch )
local stopBtn = TSMAPI.GUI : CreateButton ( frame , 16 )
stopBtn : SetPoint ( " TOPRIGHT " , helpText4 , " BOTTOMRIGHT " , 0 , - 5 )
stopBtn : SetWidth ( ( frame : GetWidth ( ) / 2 ) - 2.5 )
stopBtn : SetHeight ( 20 )
stopBtn : SetText ( L [ " Stop Sniper " ] )
stopBtn : SetScript ( " OnClick " , private.StopSniperSearch )
return frame
end
function private . VendorSearchCallback ( event , ... )
if event == " filter " then
local filter = ...
local maxPrice
for _ , itemString in ipairs ( filter.items ) do
local vendor = select ( 11 , TSMAPI : GetSafeItemInfo ( itemString ) )
maxPrice = maxPrice and max ( maxPrice , vendor ) or vendor
end
return maxPrice
elseif event == " process " then
local itemString , auctionItem = ...
local vendor = select ( 11 , TSMAPI : GetSafeItemInfo ( itemString ) )
if not vendor then return end
auctionItem : FilterRecords ( function ( record )
return ( record : GetItemBuyout ( ) or 0 ) >= vendor
end )
auctionItem : SetMarketValue ( vendor )
return auctionItem
elseif event == " done " then
local auctions = ...
local profit = 0
for itemString , data in pairs ( auctions ) do
local link = select ( 2 , TSMAPI : GetSafeItemInfo ( itemString ) )
local vendor = select ( 11 , TSMAPI : GetSafeItemInfo ( itemString ) )
for _ , record in ipairs ( data.records ) do
profit = profit + vendor * record.count - record.buyout
end
end
TSM : Printf ( L [ " Vendor Search Profit: %s " ] , TSMAPI : FormatTextMoney ( profit ) )
TSM.Search : SetSearchBarDisabled ( false )
return
end
end
function private : StartVendorSearch ( )
local itemList = { }
local lastScan = TSMAPI : ModuleAPI ( " AuctionDB " , " lastCompleteScan " )
if not lastScan then
TSM : Print ( L [ " No recent AuctionDB scan data found. " ] )
return
end
local count = 0
for itemID , data in pairs ( lastScan ) do
-- this must be GetItemInfo since these are itemIDs
local link = select ( 2 , GetItemInfo ( itemID ) )
local vendor = select ( 11 , GetItemInfo ( itemID ) )
if link and data.minBuyout and data.minBuyout < vendor then
tinsert ( itemList , TSMAPI : GetItemString ( link ) )
end
end
TSM.Search : SetSearchBarDisabled ( true )
TSM.Util : ShowSearchFrame ( nil , L [ " % Vendor Price " ] )
TSM.Util : StartItemScan ( itemList , private.VendorSearchCallback )
TSMAPI : FireEvent ( " SHOPPING:SEARCH:STARTVENDORSCAN " , { num =# itemList } )
end
do
TSM : AddSidebarFeature ( OTHER , private.Create )
end
function private : StartDisenchantSearch ( )
local itemList = { }
local lastScan = TSMAPI : ModuleAPI ( " AuctionDB " , " lastCompleteScan " )
if not lastScan then
TSM : Print ( L [ " No recent AuctionDB scan data found. " ] )
return
end
for itemID , data in pairs ( lastScan ) do
-- this must be GetItemInfo since these are itemIDs
local _ , link , _ , iLvl = GetItemInfo ( itemID )
if iLvl and iLvl >= TSM.db . global.minDeSearchLvl and iLvl <= TSM.db . global.maxDeSearchLvl then
local deValue = TSMAPI : ModuleAPI ( " TradeSkillMaster " , " deValue " , link )
-- if link and data.minBuyout and deValue * (TSM.db.global.maxDeSearchPercent or 1) > data.minBuyout then
if link and data.minBuyout and ( data.minBuyout / deValue ) < ( TSM.db . global.maxDeSearchPercent or 1 ) then
tinsert ( itemList , TSMAPI : GetItemString ( link ) )
end
end
end
TSM.Search : SetSearchBarDisabled ( true )
TSM.Util : ShowSearchFrame ( nil , L [ " % DE Value " ] )
TSM.Util : StartItemScan ( itemList , private.DisenchantSearchCallback )
end
function private . DisenchantSearchCallback ( event , ... )
if event == " filter " then
local filter = ...
local maxPrice
for _ , itemString in ipairs ( filter.items ) do
local deValue = TSMAPI : ModuleAPI ( " TradeSkillMaster " , " deValue " , itemString )
maxPrice = maxPrice and max ( maxPrice , deValue ) or deValue
end
return maxPrice
elseif event == " process " then
local itemString , auctionItem = ...
local deValue = TSMAPI : ModuleAPI ( " TradeSkillMaster " , " deValue " , itemString )
if not deValue then return end
auctionItem : FilterRecords ( function ( record )
return ( record : GetItemBuyout ( ) or 0 ) >= deValue
end )
auctionItem : SetMarketValue ( deValue )
return auctionItem
elseif event == " done " then
local auctions = ...
local profit = 0
for itemString , data in pairs ( auctions ) do
local link = select ( 2 , TSMAPI : GetSafeItemInfo ( itemString ) )
local deValue = TSMAPI : ModuleAPI ( " TradeSkillMaster " , " deValue " , itemString )
for _ , record in ipairs ( data.records ) do
profit = profit + deValue * record.count - record.buyout
end
end
TSM : Printf ( L [ " Disenchant Search Profit: %s " ] , TSMAPI : FormatTextMoney ( profit ) )
TSM.Search : SetSearchBarDisabled ( false )
return
end
end
function private : StartSniperSearch ( )
private.sniperItemQuantities = { }
private.sniperOperationSettings = { }
private.sniperItemMaxPrices = { }
TSM.Util : ShowSearchFrame ( nil , L [ " % Market Value " ] )
TSM.Search : SetSearchBarDisabled ( true )
TSM.Util : StartLastPageScan ( private.SniperScanCallback )
TSMAPI : FireEvent ( " SHOPPING:SEARCH:STARTSNIPER " )
end
function private : StopSniperSearch ( )
TSM.Search : SetSearchBarDisabled ( false )
TSM.Util : StopScan ( )
end
function private . SniperScanCallback ( event , itemString , auctionItem )
if event == " process " then
local vendorPrice , maxPrice , customPrice
do
local vendor = select ( 11 , TSMAPI : GetSafeItemInfo ( itemString ) )
if vendor then
vendorPrice = vendor
end
local operations = TSMAPI : GetItemOperation ( itemString , " Shopping " )
local totalQty = GetSniperItemQuantity ( itemString )
for _ , opName in ipairs ( operations or { } ) do
local opSettings = GetSniperOperationSettings ( 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 = GetSniperOperationMaxPrice ( itemString , opName , opSettings )
if opPrice then
maxPrice = maxPrice and max ( maxPrice , opPrice ) or opPrice
end
end
end
end
customPrice = TSM : GetMaxPrice ( TSM.db . global.sniperCustomPrice , itemString )
end
auctionItem : FilterRecords ( function ( record )
local itemBuyout = record : GetItemBuyout ( )
if not itemBuyout or itemBuyout == 0 then return true end
if TSM.db . global.sniperVendorPrice and vendorPrice and itemBuyout <= vendorPrice then
return false
end
if TSM.db . global.sniperMaxPrice and maxPrice and itemBuyout <= maxPrice then
return false
end
if customPrice and itemBuyout <= customPrice then
return false
end
return true
end )
auctionItem : SetMarketValue ( TSM : GetMaxPrice ( TSM.db . global.marketValueSource , itemString ) )
if # auctionItem.records == 0 then return end
auctionItem.shouldCompact = true
auctionItem : PopulateCompactRecords ( )
return auctionItem
end
end