vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Auctioneer Addon for World of Warcraft(tm).
Version: 3.9.0.1000 (Kangaroo)
Revision: $Id: AucBidManager.lua 927 2006-07-06 02:15:28Z mentalpower $
BidManager - manages bid requests in the AH
License:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program(see GPL.txt); if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
--]]
-------------------------------------------------------------------------------
-- Data Members
-------------------------------------------------------------------------------
-- Queue of bid requests to be worked on
local LastRequest;
local RequestQueue = {};
local ProcessingRequestQueue = false;
-- Bid queue actions
local BID_AUCTION = "bid";
local BUYOUT_AUCTION = "buyout";
-- Parameters of QueryAuctionItems() last time it was called.
local CurrentSearchParams =
{
name = nil;
minLevel = nil;
maxLevel = nil;
invTypeIndex = nil;
classIndex = nil;
subclassIndex = nil;
page = nil;
isUsable = nil;
qualityIndex = nil;
queryTime = nil; -- Time that the query was made or the last response was received
queryResponse = true; -- Flag indicates if any response has been received
queryComplete = true; -- Flag indicates if the entire response has been received
targetCountForPage = nil; -- Number of items expected on the page (nil for unknown)
};
-- Queue of bids submitted to the server, but not yet accepted or rejected
local PendingBids = {};
-- Function hooks that are used when processing requests
local Original_CanSendAuctionQuery;
local Original_AuctionFrameBrowse_OnEvent;
local Original_AuctionFrameBrowse_Update;
-- Result codes for bid requests.
BidResultCodes = {}
BidResultCodes["BidAccepted"] = 0;
BidResultCodes["ItemNotFound"] = 1;
BidResultCodes["NotEnoughMoney"] = 2;
BidResultCodes["OwnAuction"] = 3;
BidResultCodes["AlreadyHigherBid"] = 4;
BidResultCodes["AlreadyHighBidder"] = 5;
BidResultCodes["CurrentBidLower"] = 6;
BidResultCodes["MaxBidsReached"] = 7;
-------------------------------------------------------------------------------
-- Function Prototypes
-------------------------------------------------------------------------------
local addPlayerToAccount;
local isPlayerOnAccount;
local isBidInProgress;
local addPendingBid;
local removePendingBid;
local placeAuctionBidHook;
local onBidResponse;
local isQueryInProgress;
local queryAuctionItemsHook;
local checkQueryComplete;
local addRequestToQueue;
local removeRequestFromQueue;
local isProcessingRequest;
local getRequestCount;
local beginProcessingRequestQueue;
local endProcessingRequestQueue;
local processRequestQueue;
local processPage;
local nilSafe;
local boolString;
local chatPrint;
local debugPrint;
local bidAuction;
local dumpState;
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManagerFrame_OnLoad()
this:RegisterEvent("ADDON_LOADED");
this:RegisterEvent("AUCTION_ITEM_LIST_UPDATE");
this:RegisterEvent("AUCTION_HOUSE_CLOSED");
Stubby.RegisterFunctionHook("PlaceAuctionBid", -50, placeAuctionBidHook)
Stubby.RegisterFunctionHook("QueryAuctionItems", -50, queryAuctionItemsHook)
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManagerFrame_OnEvent(event)
if (event == "ADDON_LOADED" and string.lower(arg1) == "auctioneer") then
addPlayerToAccount(UnitName("player"));
this:UnregisterEvent("ADDON_LOADED");
elseif (event == "AUCTION_ITEM_LIST_UPDATE") then
debugPrint(event);
checkQueryComplete();
elseif (event == "CHAT_MSG_SYSTEM" and arg1) then
debugPrint(event);
if (arg1) then debugPrint(" "..arg1) end;
if (arg1 == ERR_AUCTION_BID_PLACED) then
onBidResponse(BidResultCodes["BidAccepted"]);
end
elseif (event == "UI_ERROR_MESSAGE" and arg1) then
debugPrint(event);
if (arg1) then debugPrint(" "..arg1) end;
if (arg1 == ERR_ITEM_NOT_FOUND) then
onBidResponse(BidResultCodes["ItemNotFound"]);
elseif (arg1 == ERR_NOT_ENOUGH_MONEY) then
onBidResponse(BidResultCodes["NotEnoughMoney"]);
elseif (arg1 == ERR_AUCTION_BID_OWN) then
onBidResponse(BidResultCodes["OwnAuction"]);
elseif (arg1 == ERR_AUCTION_HIGHER_BID) then
onBidResponse(BidResultCodes["AlreadyHigherBid"]);
end
elseif (event == "AUCTION_HOUSE_CLOSED") then
endProcessingRequestQueue();
end
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManagerFrame_OnUpdate()
processRequestQueue();
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManager_CanSendAuctionQuery()
-- Intentionally empty; don't allow the auction UI to update while we're processing requests
return false;
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManager_AuctionFrameBrowse_OnEvent()
-- Intentionally empty; don't allow the auction UI to update while we're processing requests
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function AucBidManager_AuctionFrameBrowse_Update()
-- Intentionally empty; don't allow the auction UI to update while we're processing requests
end
-------------------------------------------------------------------------------
-- Adds a player to the list of players on the current account.
-------------------------------------------------------------------------------
function addPlayerToAccount(player)
-- List of players on the same account as the current player (including the
-- current player). Auctions owned by these players cannot be bid on.
if (not AuctionConfig.players) then AuctionConfig.players = {}; end
if (not isPlayerOnAccount(player)) then
table.insert(AuctionConfig.players, player);
end
end
-------------------------------------------------------------------------------
-- Checks if a player is on the same account as the current player.
-------------------------------------------------------------------------------
function isPlayerOnAccount(player)
if (not AuctionConfig.players) then AuctionConfig.players = {}; end
for _, p in pairs(AuctionConfig.players) do
if (p == player) then
return true;
end
end
return false;
end
-------------------------------------------------------------------------------
-- Returns true if a bid request is in flight to the server
-------------------------------------------------------------------------------
function isBidInProgress()
return (table.getn(PendingBids) > 0);
end
-------------------------------------------------------------------------------
-- Adds a pending bid to the queue.
-------------------------------------------------------------------------------
function addPendingBid(name, count, bid, owner, request)
-- Add a pending bid to the queue.
local pendingBid = {};
pendingBid.name = name;
pendingBid.count = count;
pendingBid.bid = bid;
pendingBid.owner = owner;
pendingBid.request = request;
table.insert(PendingBids, pendingBid);
debugPrint("addPendingBid() - Added pending bid");
if (request) then
debugPrint("addPendingBid() - Associated request with pending bid "..table.getn(PendingBids));
end
-- Register for the response events if this is the first pending bid.
if (table.getn(PendingBids) == 1) then
debugPrint("addPendingBid() - Registering for CHAT_MSG_SYSTEM and UI_ERROR_MESSAGE");
AucBidManagerFrame:RegisterEvent("CHAT_MSG_SYSTEM");
AucBidManagerFrame:RegisterEvent("UI_ERROR_MESSAGE");
end
end
-------------------------------------------------------------------------------
-- Removes the pending bid from the queue.
-------------------------------------------------------------------------------
function removePendingBid()
if (table.getn(PendingBids) > 0) then
-- Remove the first pending bid.
local bid = PendingBids[1];
table.remove(PendingBids, 1);
debugPrint("removePendingBid() - Removed pending bid");
-- Unregister for the response events if this is the last pending bid.
if (table.getn(PendingBids) == 0) then
debugPrint("removePendingBid() - Unregistering for CHAT_MSG_SYSTEM and UI_ERROR_MESSAGE");
AucBidManagerFrame:UnregisterEvent("CHAT_MSG_SYSTEM");
AucBidManagerFrame:UnregisterEvent("UI_ERROR_MESSAGE");
end
return bid;
end
-- No pending bid to remove!
return nil;
end
-------------------------------------------------------------------------------
-- Called before PlaceAuctionBid()
-------------------------------------------------------------------------------
function placeAuctionBidHook(_, _, listType, index, bid, request)
local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo(listType, index);
if (name and count and bid) then
addPendingBid(name, count, bid, owner, request);
return "setparams", {listType, index, bid};
else
debugPrint("PlaceAuctionBid() - Ignoring bid");
return "abort";
end
end
-------------------------------------------------------------------------------
-- Called whenever a response to a bid is received
-------------------------------------------------------------------------------
function onBidResponse(result)
if (table.getn(PendingBids) > 0) then
-- We always assume the bid response is for the next bid in PendingBids.
local bid = removePendingBid();
-- If there is an associated request, add our result to it.
local request = bid.request;
if (request) then
debugPrint("Found request associated with bid");
if (result == BidResultCodes["BidAccepted"]) then
table.insert(request.results, result);
if (request.bid == request.buyout) then
local output = string.format(_AUCT('FrmtBoughtAuction'), request.name, request.count);
chatPrint(output);
else
local output = string.format(_AUCT('FrmtBidAuction'), request.name, request.count);
chatPrint(output);
end
elseif (result == BidResultCodes["ItemNotFound"]) then
-- nothing to do
elseif (result == BidResultCodes["NotEnoughMoney"]) then
table.insert(request.results, result);
local output = string.format(_AUCT('FrmtNotEnoughMoney'), request.name, request.count);
chatPrint(output);
elseif (result == BidResultCodes["OwnAuction"]) then
table.insert(request.results, result);
local output = string.format(_AUCT('FrmtSkippedBiddingOnOwnAuction'), request.name, request.count);
chatPrint(output);
elseif (result == BidResultCodes["AlreadyHigherBid"]) then
if (request.bid ~= request.buyout) then
table.insert(request.results, result);
local output = string.format(_AUCT('FrmtSkippedAuctionWithHigherBid'), request.name, request.count);
chatPrint(output);
else
debugPrint("Attempted to buyout the same auction");
end
end
else
debugPrint("Did not find request associated with bid");
end
-- Process the bid result .
if (result == BidResultCodes["BidAccepted"] and request) then
-- Check if there is a corresponding request and upate it to
-- reflect the successful bid.
if (request) then
request.bidCount = request.bidCount + 1;
-- Increment the request's current index if the auction was not bought out.
if (request.bid ~= request.buyout) then
request.currentIndex = request.currentIndex + 1;
debugPrint("Incrementing the request's currentIndex to "..request.currentIndex);
end
end
elseif (result ~= BidResultCodes["BidAccepted"]) then
-- We were expecting the list to update after our bid/buyout, but
-- our bid/buyout failed so we won't be getting an update.
CurrentSearchParams.queryComplete = true;
CurrentSearchParams.queryResponse = true;
CurrentSearchParams.targetCountForPage = nil;
-- Skip over the auction we failed to bid on.
if (request) then
request.currentIndex = request.currentIndex + 1;
debugPrint("Incrementing the request's currentIndex to "..request.currentIndex);
end
if (result == BidResultCodes["OwnAuction"] and bid.owner) then
-- We tried bidding on our own auction! Blizzard doesn't
-- allow bids from any player on the account that posted
-- the auction. Therefore we keep a dynamic list of all
-- of these failures so we can avoid these auctions in the
-- future.
addPlayerToAccount(bid.owner);
end
end
else
-- We got out of sync somehow... this indicates a bug in how we determine
-- the results of bid requests.
chatPrint(_AUCT('FrmtBidQueueOutOfSync'));
end
end
-------------------------------------------------------------------------------
-- Returns true if a query is in progress
-------------------------------------------------------------------------------
function isQueryInProgress()
return (not CurrentSearchParams.queryComplete);
end
-------------------------------------------------------------------------------
-- Wrapper around CanSendAuctionQuery() that always calls the Blizzard version.
-------------------------------------------------------------------------------
function canSendAuctionQuery()
if (Original_CanSendAuctionQuery) then
return Original_CanSendAuctionQuery();
end
return CanSendAuctionQuery();
end
-------------------------------------------------------------------------------
-- Called before QueryAuctionItems()
-------------------------------------------------------------------------------
function queryAuctionItemsHook(_, _, name, minLevel, maxLevel, invTypeIndex, classIndex, subclassIndex, page, isUsable, qualityIndex)
if (not Auctioneer.Scanning.IsScanningRequested and canSendAuctionQuery()) then
CurrentSearchParams.name = name;
CurrentSearchParams.minLevel = minLevel;
CurrentSearchParams.maxLevel = maxLevel;
CurrentSearchParams.invTypeIndex = invTypeIndex;
CurrentSearchParams.classIndex = classIndex;
CurrentSearchParams.subclassIndex = subclassIndex;
CurrentSearchParams.page = page;
CurrentSearchParams.isUsable = isUsable;
CurrentSearchParams.qualityIndex = qualityIndex;
CurrentSearchParams.queryTime = time();
CurrentSearchParams.queryResponse = false;
CurrentSearchParams.queryComplete = false;
CurrentSearchParams.targetCountForPage = nil;
debugPrint("queryAuctionItemsHook()");
else
CurrentSearchParams.name = nil;
CurrentSearchParams.minLevel = nil;
CurrentSearchParams.maxLevel = nil;
CurrentSearchParams.invTypeIndex = nil;
CurrentSearchParams.classIndex = nil;
CurrentSearchParams.subclassIndex = nil;
CurrentSearchParams.page = nil;
CurrentSearchParams.isUsable = nil;
CurrentSearchParams.qualityIndex = nil;
CurrentSearchParams.queryTime = time();
CurrentSearchParams.queryResponse = true;
CurrentSearchParams.queryComplete = true;
CurrentSearchParams.targetCountForPage = nil;
debugPrint("queryAuctionItemsHook() - ignoring");
end
-- Toss the information about the last request processed.
LastRequest = nil;
end
-------------------------------------------------------------------------------
-- Checks a query to see if its complete. Often times the owner information
-- of auctions are missing at first. Asking for it triggers another update
-- of the auction list.
-------------------------------------------------------------------------------
function checkQueryComplete()
if (not CurrentSearchParams.queryComplete) then
-- Get the number of auctions on the page.
local lastIndexOnPage, totalAuctions = GetNumAuctionItems("list");
debugPrint("LastIndexOnPage = "..lastIndexOnPage);
debugPrint("TotalAuctions = "..totalAuctions);
if (CurrentSearchParams.targetCountForPage == nil or CurrentSearchParams.targetCountForPage == lastIndexOnPage) then
-- Assume true until otherwise proven false.
CurrentSearchParams.queryTime = time();
CurrentSearchParams.queryResponse = true;
CurrentSearchParams.queryComplete = true;
for indexOnPage = 1, lastIndexOnPage do
local _,_,_,_,_,_,_,_,_,_,_, owner = GetAuctionItemInfo("list", indexOnPage);
if (owner == nil) then
-- No dice... there are more updates coming...
CurrentSearchParams.queryComplete = false;
break;
end
end
if (CurrentSearchParams.queryComplete) then
debugPrint("checkQueryComplete() - true");
else
debugPrint("checkQueryComplete() - false (waiting for owner information on auctions)");
end
else
debugPrint("checkQueryComplete() - false (waiting for "..CurrentSearchParams.targetCountForPage.." auctions on page)");
end
end
end
-------------------------------------------------------------------------------
-- Adds a request to the queue.
-------------------------------------------------------------------------------
function addRequestToQueue(request)
-- Add the request state information
request.bidAttempts = 0;
request.bidCount = 0;
request.currentPage = 0;
request.currentIndex = 1;
request.continuation = false;
request.results = {};
-- Check if the previous request is the same as this request. If so we
-- want to pickup where the last request left off.
if (table.getn(RequestQueue) == 0 and
LastRequest ~= nil and
LastRequest.id == request.id and
LastRequest.rprop == request.rprop and
LastRequest.enchant == request.enchant and
LastRequest.name == request.name and
LastRequest.count == request.count and
LastRequest.min == request.min and
LastRequest.buyout == request.buyout and
LastRequest.unique == request.unique and
LastRequest.bid == request.bid) then
request.currentPage = LastRequest.currentPage;
request.currentIndex = LastRequest.currentIndex;
request.continuation = true;
end
-- Add the request to the queue.
table.insert(RequestQueue, request);
debugPrint("Added request to queue: "..request.name..", "..request.count..", "..nilSafe(request.buyout)..", "..nilSafe(request.bid));
end
-------------------------------------------------------------------------------
-- Removes a request at the head of the queue.
-------------------------------------------------------------------------------
function removeRequestFromQueue()
if (table.getn(RequestQueue) > 0) then
-- Remove the request from the queue.
local request = RequestQueue[1];
table.remove(RequestQueue, 1);
debugPrint("Removed request from queue: "..request.name..", "..request.count..", "..nilSafe(request.buyout)..", "..nilSafe(request.bid));
-- Make the callback, if requested.
local callback = request.callback;
if (callback and callback.func) then
callback.func(callback.param, request);
end
-- Inform the user if no auctions were found.
if (table.getn(request.results) == 0) then
if (request.continuation) then
local output = string.format(_AUCT('FrmtNoMoreAuctionsFound'), request.name, request.count);
chatPrint(output);
else
local output = string.format(_AUCT('FrmtNoAuctionsFound'), request.name, request.count);
chatPrint(output);
end
end
-- Check if the next request is the same as the previous. If so we
-- want to pickup where the last request left off.
if (LastRequest ~= nil and table.getn(RequestQueue) > 0) then
local nextRequest = RequestQueue[1];
if (LastRequest.id == nextRequest.id and
LastRequest.rprop == nextRequest.rprop and
LastRequest.enchant == nextRequest.enchant and
LastRequest.name == nextRequest.name and
LastRequest.count == nextRequest.count and
LastRequest.min == nextRequest.min and
LastRequest.buyout == nextRequest.buyout and
LastRequest.unique == nextRequest.unique and
LastRequest.bid == nextRequest.bid) then
nextRequest.currentPage = LastRequest.currentPage;
nextRequest.currentIndex = LastRequest.currentIndex;
nextRequest.continuation = true;
end
end
end
end
-------------------------------------------------------------------------------
-- Checks if the BidManager is currently working on a request.
-------------------------------------------------------------------------------
function isProcessingRequest()
return ProcessingRequestQueue;
end
-------------------------------------------------------------------------------
-- Gets the number of pending requests.
-------------------------------------------------------------------------------
function getRequestCount()
return table.getn(RequestQueue);
end
-------------------------------------------------------------------------------
-- Starts processing the request queue if possible. Returns true if started.
-------------------------------------------------------------------------------
function beginProcessingRequestQueue()
if (not ProcessingRequestQueue and
AuctionFrame and AuctionFrame:IsVisible() and
table.getn(RequestQueue) > 0 and
not Auctioneer.Scanning.IsScanningRequested and
not isQueryInProgress() and
not isBidInProgress()) then
ProcessingRequestQueue = true;
AucBidManagerFrame:Show();
debugPrint("Begin processing the bid queue");
-- Hook the functions to disable the Browse UI
if (not Original_CanSendAuctionQuery) then
Original_CanSendAuctionQuery = CanSendAuctionQuery;
CanSendAuctionQuery = AucBidManager_CanSendAuctionQuery;
end
if (not Original_AuctionFrameBrowse_OnEvent) then
Original_AuctionFrameBrowse_OnEvent = AuctionFrameBrowse_OnEvent;
AuctionFrameBrowse_OnEvent = AucBidManager_AuctionFrameBrowse_OnEvent;
end
if (not Original_AuctionFrameBrowse_Update) then
Original_AuctionFrameBrowse_Update = AuctionFrameBrowse_Update;
AuctionFrameBrowse_Update = AucBidManager_AuctionFrameBrowse_Update;
end
-- Hide the UI from any current results, show the no results text so we can use it
BrowseNoResultsText:Show();
BrowseNoResultsText:SetText(_AUCT('UiProcessingBidRequests'));
for iButton = 1, NUM_BROWSE_TO_DISPLAY do
button = getglobal("BrowseButton"..iButton);
button:Hide();
end
BrowsePrevPageButton:Hide();
BrowseNextPageButton:Hide();
BrowseSearchCountText:Hide();
BrowseBidButton:Disable();
BrowseBuyoutButton:Disable();
end
return ProcessingRequestQueue;
end
-------------------------------------------------------------------------------
-- Ends processing the request queue
-------------------------------------------------------------------------------
function endProcessingRequestQueue()
if (ProcessingRequestQueue) then
ProcessingRequestQueue = false;
AucBidManagerFrame:Hide();
debugPrint("End processing the bid queue");
-- Unhook the functions
if( Original_CanSendAuctionQuery ) then
CanSendAuctionQuery = Original_CanSendAuctionQuery;
Original_CanSendAuctionQuery = nil;
end
if( Original_AuctionFrameBrowse_OnEvent ) then
AuctionFrameBrowse_OnEvent = Original_AuctionFrameBrowse_OnEvent;
Original_AuctionFrameBrowse_OnEvent = nil;
end
if( Original_AuctionFrameBrowse_Update ) then
AuctionFrameBrowse_Update = Original_AuctionFrameBrowse_Update;
Original_AuctionFrameBrowse_Update = nil;
end
-- Update the Browse UI.
BrowseNoResultsText:Hide();
BrowseNoResultsText:SetText("");
AuctionFrameBrowse_Update();
end
end
-------------------------------------------------------------------------------
-- Attempt to process the request queue. Based on the current state, this
-- method performs the next action needed to process the queue.
-------------------------------------------------------------------------------
function processRequestQueue()
-- Check if we should toss the results of the last query. Sometimes
-- Blizzard never updates all the owner information. We give it 20
-- seconds, then give up and try again.
if (CurrentSearchParams.queryResponse == true and
CurrentSearchParams.queryComplete == false and
CurrentSearchParams.queryTime and
time() - CurrentSearchParams.queryTime >= 20) then
-- Discard the results of the search and try again.
CurrentSearchParams.name = nil;
CurrentSearchParams.minLevel = nil;
CurrentSearchParams.maxLevel = nil;
CurrentSearchParams.invTypeIndex = nil;
CurrentSearchParams.classIndex = nil;
CurrentSearchParams.subclassIndex = nil;
CurrentSearchParams.page = nil;
CurrentSearchParams.isUsable = nil;
CurrentSearchParams.qualityIndex = nil;
CurrentSearchParams.queryTime = nil;
CurrentSearchParams.queryResponse = true;
CurrentSearchParams.queryComplete = true;
CurrentSearchParams.targetCountForPage = nil;
Auctioneer.Util.ChatPrint(string.format(_AUCT('AuctionScanRedo'), 20));
end
-- Process the bid queue!
if (beginProcessingRequestQueue()) then
while (table.getn(RequestQueue) > 0 and not isQueryInProgress() and not isBidInProgress()) do
local request = RequestQueue[1];
--debugPrint("Processing bid queue: "..request.name..", "..request.count..", "..nilSafe(request.owner)..", "..nilSafe(request.bid)..", "..nilSafe(request.buyout));
--debugPrint("CurrentSearchParams: ");
--debugPrint(" name: "..nilSafe(CurrentSearchParams.name));
--debugPrint(" minLevel: "..nilSafe(CurrentSearchParams.minLevel));
--debugPrint(" maxLevel: "..nilSafe(CurrentSearchParams.maxLevel));
if (CurrentSearchParams.name and
CurrentSearchParams.name == request.name and
CurrentSearchParams.minLevel == "" and
CurrentSearchParams.maxLevel == "" and
CurrentSearchParams.invTypeIndex == nil and
CurrentSearchParams.classIndex == nil and
CurrentSearchParams.page == request.currentPage and
CurrentSearchParams.isUsable == nil and
CurrentSearchParams.qualityIndex == nil) then
processPage();
elseif (canSendAuctionQuery()) then
QueryAuctionItems(request.name, "", "", nil, nil, nil, request.currentPage, nil, nil);
else
-- We gotta wait to be able to send a query.
break;
end
end
-- If we've emptied the RequestQueue, then end the processing
if (table.getn(RequestQueue) == 0) then
endProcessingRequestQueue();
end
end
end
-------------------------------------------------------------------------------
-- Searches the current page for an auction matching the first request in
-- the request queue. If it finds the auction, it carries out the specified
-- action (bid/buyout).
-------------------------------------------------------------------------------
function processPage()
local request = RequestQueue[1];
-- Iterate through each item on the page, searching for a match
local lastIndexOnPage, totalAuctions = GetNumAuctionItems("list");
debugPrint("Processing page "..request.currentPage.." starting at index "..request.currentIndex.." ("..lastIndexOnPage.." on page; "..totalAuctions.." in total)");
debugPrint("Searching for item: "..request.id..", "..request.rprop..", "..request.enchant..", "..request.name..", "..request.count..", "..request.min..", "..request.buyout..", "..request.unique..", "..request.bid);
local foundMatchingAuction = false;
for indexOnPage = request.currentIndex, lastIndexOnPage do
-- Check if this item matches
local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo("list", indexOnPage);
local link = GetAuctionItemLink("list", indexOnPage);
local id, rprop, enchant, unique = EnhTooltip.BreakLink(link);
debugPrint("Processing item "..indexOnPage..": "..id..", "..rprop..", "..enchant..", "..name..", "..count..", "..minBid..", "..buyoutPrice..", "..unique..", "..bidAmount);
if ((request.id == id) and
(request.rprop == rprop) and
(request.enchant == enchant) and
(request.name == name) and
(request.count == count) and
(request.min == minBid) and
(request.buyout == buyoutPrice) and
(request.unique == unique)) then
local bid = nil;
-- Check if the auction is owned by the player.
if (isPlayerOnAccount(owner)) then
table.insert(request.results, BidResultCodes["OwnAuction"]);
local output = string.format(_AUCT('FrmtSkippedBiddingOnOwnAuction'), request.name, request.count);
chatPrint(output);
-- Check for a buyout request
elseif (request.buyout == request.bid) then
bid = request.buyout;
-- Otherwise it must be a bid request
else
-- Check if we are already the high bidder
if (highBidder) then
table.insert(request.results, BidResultCodes["AlreadyHighBidder"]);
local output = string.format(_AUCT('FrmtAlreadyHighBidder'), request.name, request.count);
chatPrint(output);
-- Check if the item has been bid on
elseif (bidAmount ~= 0) then
-- Check the bid matches what we are looking for
if (bidAmount == request.bid) then
bid = bidAmount + minIncrement;
-- Check if there is already a higher bidder
elseif (bidAmount > request.bid) then
table.insert(request.results, BidResultCodes["AlreadyHigherBid"]);
local output = string.format(_AUCT('FrmtSkippedAuctionWithHigherBid'), request.name, request.count);
chatPrint(output);
-- Otherwise the bid must be lower...
else
table.insert(request.results, BidResultCodes["CurrentBidLower"]);
local output = string.format(_AUCT('FrmtSkippedAuctionWithLowerBid'), request.name, request.count);
chatPrint(output);
end
-- Otherwise the item hasn't been bid on
else
-- Check the bid matches what we are looking for
if (minBid == request.bid) then
bid = minBid;
-- Otherwise the min bid is lower...
else
table.insert(request.results, BidResultCodes["CurrentBidLower"]);
local output = string.format(_AUCT('FrmtSkippedAuctionWithLowerBid'), request.name, request.count);
chatPrint(output);
end
end
end
-- If we've settled on a bid, do it now!
if (bid) then
foundMatchingAuction = true;
-- Check if we've reached the bid limit on this request.
if (request.bidCount == request.maxBids) then
-- Report that the maximum number of bids has been reached.
local output = string.format(_AUCT('FrmtMaxBidsReached'), request.name, request.count, request.maxBids);
chatPrint(output);
debugPrint("Reached max bids!");
-- Add the bid result to the request.
table.insert(request.results, BidResultCodes["MaxBidsReached"]);
-- Since this request didn't fully completed due to bid
-- limits, update the currentIndex and save it as the
-- last request. If the next request is for the same item,
-- it will pickup where this request left off.
LastRequest = request;
request.currentIndex = indexOnPage;
removeRequestFromQueue();
else
-- Successful bid/buyouts result in the query results being
-- updated. To prevent additional queries from being sent
-- until the list is updated, we flip the complete flag
-- back to false. If the bid fails we'll manually flip
-- the flag back to true again.
CurrentSearchParams.queryTime = time();
CurrentSearchParams.queryResponse = false;
CurrentSearchParams.queryComplete = false;
if (bid == buyoutPrice) then
CurrentSearchParams.targetCountForPage = lastIndexOnPage - 1;
end
-- Update the starting point for this page
request.currentIndex = indexOnPage;
request.bidAttempts = request.bidAttempts + 1;
-- Place the bid! This MUST be done last since the response
-- can be received during the call to PlaceAuctionBid.
debugPrint("Placing bid on "..name.. " at "..bid.." (index "..indexOnPage..")");
PlaceAuctionBid("list", indexOnPage, bid, request);
end
break;
end
end
end
-- If an item was not found to bid on...
if (not foundMatchingAuction) then
-- When an item is bought out on the page, the item is not replaced
-- with an item from a subsequent page. Nor is the item removed from
-- the total count. Thus if there were 7 items total before the buyout,
-- GetNumAuctionItems() will report 6 items on the page and but still
-- 7 total after the buyout.
if (lastIndexOnPage == 0 or
request.currentPage * NUM_AUCTION_ITEMS_PER_PAGE + lastIndexOnPage == totalAuctions) then
-- Reached the end of the line for this item, remove it from the queue
request.currentIndex = lastIndexOnPage + 1;
removeRequestFromQueue();
else
-- Continue looking for items on the next page.
request.currentPage = request.currentPage + 1;
request.currentIndex = 1;
end
end
end
-------------------------------------------------------------------------------
-- Adds a bid request to the queue. For bids, the bid parameter should be the
-- current bid (or minimum bid in the case the item isn't bid on). For buyouts,
-- the bid parameter should be the buyout price.
-------------------------------------------------------------------------------
function bidAuction(bid, signature, maxBids, callbackFunc, callbackParam)
debugPrint("BidAuction("..bid..", "..signature..")");
local id,rprop,enchant,name,count,min,buyout,unique = Auctioneer.Core.GetItemSignature(signature);
if (bid and id and rprop and enchant and name and count and min and buyout and unique) then
-- Make sure we have a valid maxBids
if (maxBids == nil or maxBids < 1) then
maxBids = 25;
end
-- Create a bid request.
local request = {};
request.id = id;
request.rprop = rprop;
request.enchant = enchant;
request.name = name;
request.count = count;
request.min = min;
request.buyout = buyout;
request.unique = unique;
request.bid = bid;
request.maxBids = maxBids;
request.callback = { func = callbackFunc, param = callbackParam };
-- Queue the bid request and kick off request processing!
addRequestToQueue(request);
processRequestQueue();
end
end
-------------------------------------------------------------------------------
-- Dumps the state of the BidManager to the chat window.
-------------------------------------------------------------------------------
function dumpState()
chatPrint("BidManager State:");
chatPrint(" IsBidInProgress: "..boolString(isBidInProgress()));
chatPrint(" IsQueryInProgress: "..boolString(isQueryInProgress()));
chatPrint(" RequestQueue ("..table.getn(RequestQueue).."):");
chatPrint(" PendingBids ("..table.getn(PendingBids).."):");
chatPrint(" CurrentSearchParams:");
chatPrint(" name: "..nilSafe(CurrentSearchParams.name));
chatPrint(" minLevel: "..nilSafe(CurrentSearchParams.minLevel));
chatPrint(" maxLevel: "..nilSafe(CurrentSearchParams.maxLevel));
chatPrint(" invTypeIndex: "..nilSafe(CurrentSearchParams.invTypeIndex));
chatPrint(" classIndex: "..nilSafe(CurrentSearchParams.classIndex));
chatPrint(" subclassIndex: "..nilSafe(CurrentSearchParams.subclassIndex));
chatPrint(" page: "..nilSafe(CurrentSearchParams.page));
chatPrint(" isUsable: "..boolString(CurrentSearchParams.isUsable));
chatPrint(" qualityIndex: "..nilSafe(CurrentSearchParams.qualityIndex));
chatPrint(" queryResponse: "..boolString(CurrentSearchParams.queryResponse));
chatPrint(" queryComplete: "..boolString(CurrentSearchParams.queryComplete));
chatPrint(" targetCountForPage: "..nilSafe(CurrentSearchParams.targetCountForPage));
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function nilSafe(string)
if (string) then
return string;
end
return "<nil>";
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
function boolString(value)
if (value) then
return "true";
end
return "false";
end
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
chatPrint = Auctioneer.Util.ChatPrint;
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
debugPrint = EnhTooltip.DebugPrint;
-------------------------------------------------------------------------------
-- Public API
-------------------------------------------------------------------------------
AucBidManager =
{
-- Exported functions
BidAuction = bidAuction;
IsProcessingRequest = isProcessingRequest;
GetRequestCount = getRequestCount;
DumpState = dumpState;
};