--[[------------------- NOTICE: -----------------------------
Until I get a UI for this running, modify these values to
tweak your auctions.
---------------------------------------------------------]]--
-- Base time alotted for each auction (in seconds)
local auctionBaseTime = 10;
-- Time alotted to extend auction during active bidding (in seconds)
local auctionExtendTime = 5;
-- Time alotted to allow players to call other bids (in seconds x 2)
local auctionCallTime = 3;
-- Time to wait between Q'ed auctions (in seconds)
local auctionTimeBetween = 3;
-- Starting auction points per player
local auctionStartingPoints = 10;
-- Minimum bid on set items
local auctionMinSetBid = 5;
-- Minimum bid on Blue and higher items
local auctionMinBlueBid = 5;
--[[-----------------------------------------------------------------
DON'T TOUCH ANYTHING BELOW THIS UNLESS YOU KNOW WHAT YOU'RE DOING
-----------------------------------------------------------------]]--
-- The Item currently being auctioned
local itemCurrentAuction = {};
-- Arbitary value?
MASTERLOOTER_DROPDOWNBUTTON_VALUE = 1337;
-- Hooks -- To Be Removed on successful test
local bliz_GroupLootDropDown_Initialize;
local bliz_GroupLootDropDown_OnLoad;
-- Loot q
local lootQ = {};
-- Auction status: "NOAUCTION", "STARTED", "ACTIVEBIDDING", "GOINGONCE"
-- "GOINGTWICE", "BETWEENAUCTIONS", "ROLLING"
local auctionStatus = "NOAUCTION";
-- Auction timer: startTime, allocTime
local auctionTimer = {};
-- Currently winning bidder's info: name, index, points, bid, status
local auctionWinner = {};
-- The list of players: name, index, points, status
local playerList = {};
-- Is our time up?
function IsTimeUp()
if (GetTime() - auctionTimer.startTime >= auctionTimer.allocTime) then
return true
else
return false
end
end
-- Returns "RAID" if in raid, "PARTY" if in party
function IsRaidOrParty()
if (GetNumRaidMembers() > 0) then
return "RAID"
else
return "PARTY"
end
end
-- Get the elapsed time
function GetElapsedTime()
return GetTime() - auctionTimer.startTime
end
-- Start the timer and give it the base timetime
function StartAuctionTimer()
auctionTimer.startTime = GetTime();
auctionTimer.allocTime = auctionBaseTime;
end
-- Process party chat messages
function MasterLooter_OnChatMsgParty(playerName, msg)
-- if we're not currently auctioning, or we're in a raid, ignore the message
if (auctionStatus == "NOAUCTION" or auctionStatus == "BETWEENAUCTIONS" or IsRaidOrParty() == "RAID") then
return
end
-- Check to see if text was a bid and if so, a valid one
local bidTag = ValidateBid(playerName, msg);
if (bidTag == "INVALID") then
-- Either the message wasn't a bid or an error ocurred
return;
end
-- Text was in fact a bid. Process the bid.
ProcessBid(playerName, tonumber(msg), bidTag);
end
-- Todo: process bids and post notification
function ProcessBid(playerName, bid, bidTag)
if (bidTag == "VALID") then
-- todo: account for multiple winners
if (bid > auctionWinner.bid) then
-- We have a new winner
local newWinner = GetPlayerByName(playerName);
if (newWinner) then
auctionWinner = newWinner;
auctionWinner.bid = bid;
end
end
return
end
if (bidTag == "INVALID_ZEROORLESS") then
-- Notify the player of his dumbass bid
SendChatMessage("You can't break me with that bid, sorry. Nice try, tho. :)", "WHISPER", "COMMON", playerName);
return
end
if (bidTag == "INVALID_NOTENUFFPTS") then
-- Notify the player of his invalid bid and inform him of his current points
end
end
-- Is this a bid? If so, is it a valid one? Find out and tag it.
-- Returns: "VALID", "VALID_TIE", "INVALID", "INVALID_ZEROORLESS",
-- "INVALID_NOTENUFFPTS", "INVALID_TIE", "SPECIAL_TIE"
function ValidateBid(playerName, msg)
-- Who is this guy?
local biddingPlayer = GetPlayerByName(playerName);
if (not biddingPlayer) then
-- ERRORS BAAAAD!
message("function ValidateBid("..playerName..", msg) fudged up. Should never see this, btw.");
return "INVALID";
end
-- Let's go thru and check all the things that might make this an invalid bid
if (tonumber(msg) <= 0) then
-- You can't bid zero or less dumbass
return "INVALID_ZEROORLESS"
end
if (tonumber(msg) > biddingPlayer.points) then
-- you don't have that many pts dumbass
return "INVALID_NOTENUFFPTS"
end
-- Looks like a bid. Check to see if this bid ties with the winner's.
if (tonumber(msg) == auctionWinner.bid) then
-- Ohh, boy. This *might* be an invalid bid, but we need to find
-- the player that placed the bid and see if they're both maxed out
-- before we'll know for sure.
-- TODO: add a table of winners for rolling
if (biddingPlayer.points == auctionWinner.bid == auctionWinner.points) then
-- We have a valid tie.
return "VALID_TIE"
end
-- This could be a special case in which the bidding player has spent all his points
-- in tying with a winner who still has more points to spend. In this case, the player
-- spending all his points should become the new winner and the old winner should be
-- notified of the case.
if (biddingPlayer.points < auctionWinner.points) then
return "SPECIAL_TIE"
end
-- I'm sorry, I can't do that Dave.
return "INVALID_TIE"
end
-- We got thru everything, it's a valid bid
return "VALID"
end
-- Returns named player in the player list. Returns nil on failure.
function GetPlayerByName(name)
-- Loop thru and find him
for i = 1, table.getn(playerList), 1 do
if (playerList[i].name == name) then
-- We have a winner
return playerList[i];
end
end
-- I've failed you, father!
return nil
end
-- Allocate time
-- todo: fix this function so that it takes into account total added time
function AllocateAuctionTime(allocTime)
auctionTimer.allocTime = auctionTimer.allocTime + allocTime;
end
-- Add an item to the end of the lootQ
function AddToLootQ(item)
table.insert(lootQ, item);
end
-- Remove an item from the lootQ and put it in itemCurrentAuction
function NextInLootQ()
itemCurrentAuction = table.remove(lootQ, 1);
end
-- Are there items in the lootQ?
function IsItemInQ()
if (table.getn(lootQ) > 0) then
return true
else
return false
end
end
-- Hack the game's built in Master Loot drop down
function MasterLooter_GroupLootDropDown_Initialize()
-- I'm done - Call the original
bliz_GroupLootDropDown_Initialize();
-- Info struct for adding a drop down button
local info = {};
info.text = "- Auction with MasterLooter";
info.textHeight = 12;
info.value = MASTERLOOTER_DROPDOWNBUTTON_VALUE; -- Arbitary value?
info.r = 255; -- Red Text
info.g = 1;
info.b = 1;
info.notCheckable = 1;
info.func = MasterLooter_AuctionLoot;
UIDropDownMenu_AddButton(info);
end
-- Greed the current item
function GreedItem()
-- Find out who has next greed and give them the item
local greedyPlayer = table.remove(playerList, 1);
-- Give the item
GiveMasterLoot(currentAuctionItem.selectedSlot, greedyPlayer.index);
-- Potential problems: what if player is no longer in group? or is out of
-- range/not in instance?
-- Announce the win
local msg = GetLootSlotLink(itemCurrentAuction.selectedSlot).." greeded to "..greedyPlayer.name..".";
SendChatMessage(msg, IsRaidOrParty());
-- Put them on the bottom of the player list
table.insert(playerList, greedyPlayer);
-- Notify next player
SendChatMessage("You are next in the Greed Queue.", "WHISPER", "Common", playerList[1].name);
end
-- Add a *new* party member to the playerList
-- todo
function AddPlayer(playerName)
end
-- Used to sort players alphabetically
function PlayerSort(player1, player2)
return player1.name < player2.name
end
-- Generate a list of players
function ResetPlayerList()
if (GetNumRaidMembers() > 0) then
-- We're in a raid
for i = 1, 40, 1 do
local playerName = GetMasterLootCandidate(i);
if (playerName) then
local player = {};
player.index = i;
player.name = playerName;
player.points = auctionStartingPoints;
table.insert(playerList, player);
end
end
else
-- We're in a party
for i=1, MAX_PARTY_MEMBERS+1, 1 do
local playerName = GetMasterLootCandidate(i);
if (playerName) then
local player = {};
player.index = i;
player.name = playerName;
player.points = auctionStartingPoints;
table.insert(playerList, player);
end
end
end
-- Sort the greedlist alphabetically
table.sort(playerList, PlayerSort);
end
-- Add this loot the the queue of loot-to-be-auctioned
function MasterLooter_AuctionLoot()
-- Get the item we clicked and add it to the q
local item = {};
item.name = LootFrame.selectedItemName;
item.slot = LootFrame.selectedSlot;
item.quality = LootFrame.selectedQuality;
AddToLootQ(item);
-- to be safe
CloseDropDownMenus();
end
function HookGroupLootDropDown()
if (GroupLootDropDown_Initialize and GroupLootDropDown_OnLoad) then
-- Average Joe Hook - Leaving in for now until next successful test
bliz_GroupLootDropDown_Initialize = GroupLootDropDown_Initialize;
GroupLootDropDown_Initialize = MasterLooter_GroupLootDropDown_Initialize;
bliz_GroupLootDropDown_OnLoad = GroupLootDropDown_OnLoad;
GroupLootDropDown_OnLoad = MasterLooter_GroupLootDropDown_OnLoad;
MasterLooter_GroupLootDropDown_OnLoad();
return
else
message("Functions not hooked");
end
end
-- Register events
function MasterLooter_RegisterEvents()
this:RegisterEvent("CHAT_MSG_PARTY");
this:RegisterEvent("CHAT_MSG_RAID");
this:RegisterEvent("CHAT_MSG_SYSTEM");
end
-- Hookie!
function MasterLooter_Init()
HookGroupLootDropDown();
MasterLooter_RegisterEvents();
end
-- Rewrite the GroupLootDropDown
function MasterLooter_GroupLootDropDown_OnLoad()
UIDropDownMenu_Initialize(GroupLootDropDown, MasterLooter_GroupLootDropDown_Initialize, "MENU");
end
function MasterLooter_OnUpdate()
if (auctionStatus == "NOAUCTION" and not IsItemInQ()) then
return
end
-- Handle auction events
if ((auctionStatus == "NOAUCTION" and IsItemInQ())) then
-- Get the item out of the Q
NextInLootQ();
-- Announce Item for auctioning
local msg = "Place your bids for "..GetLootSlotLink(itemCurrentAuction.selectedSlot)..".";
SendChatMessage(msg, IsRaidOrParty());
-- Start the timer
StartAuctionTimer();
-- Start the auction
auctionStatus = "STARTED";
return
end
if (auctionStatus == "STARTED") then
-- todo: Check for bids, if there have been bids, then verify
-- the bids, extend the auction, make it active
-- and return
-- todo: clean up this check
if (IsTimeUp() and auctionWinner.index) then
-- The auction ended without anyone bidding
-- Greed list the item
GreedItem();
-- todo: Announce results
if (IsItemInQ()) then
-- We are now in between auctions, allocate time
auctionStatus = "BETWEENAUCTIONS";
AllocateAuctionTime(auctionTimeBetween);
else
-- No auctions left
auctionStatus = "NOAUCTION";
end
end
end
if (auctionStatus == "BETWEENAUCTIONS") then
if (IsTimeUp()) then
-- it's time for the next auction
auctionStatus = "NOAUCTION";
end
end
if (auctionStatus == "ACTIVEBIDDING") then
-- todo: process bids, if there are bids, extend active bidding
-- and return
if (IsTimeUp()) then
-- todo: Active bidding has subsided, "Going Once"
AllocateAuctionTime(auctionCallTime);
auctionStatus = "GOINGONCE";
return
end
end
if (auctionStatus == "GOINGONCE") then
-- todo: process bids, if there are bids, switch back to active
-- extend time and return
if (IsTimeUp()) then
-- todo: Still no bids, "Going Twice"
AllocateAuctionTime(auctionCallTime);
auctionStatus = "GOINGTWICE";
return
end
end
if (auctionStatus == "GOINGTWICE") then
-- todo: process bids, if there are bids, switch back to active bidding,
-- extend time and return
if (IsTimeUp()) then
-- todo: time is up on the auction and the item is sold. Announce
-- the winner, distribute the item, deduct points from winner's total
if (IsItemInQ()) then
-- There's another item in the q to be auctioned, we're between auctions
AllocateAuctionTime(auctionTimeBetween);
auctionStatus = "BETWEENAUCTIONS";
return
else
-- Nothing left in the q
auctionStatus = "NOAUCTION";
return
end
end
end
end