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