-- Chat Config values local TRADE_GOLD_RECEIVED_ANNOUNCEMENT = "%s Bets %s!"; -- First %s is the players name, second %s is the gold amount local TRADE_GOLD_GIVEN_ANNOUNCEMENT = "%s received %s!"; -- First %s is the players name, second %s is the gold amount local GOLD = "%d Gold"; local SILVER = "%d Silver"; local COPPER = "%d Copper"; -- Dice Config Values local GAME_DICE_KEYWORD_OVER = "over"; local GAME_DICE_KEYWORD_UNDER = "under"; local GAME_DICE_WIN_MESSAGE = "Congratulations %s! You won the dice game! We rolled %s and you picked %s."; -- First %s is the players name, second %s is the total rolled, third %s is the players choice (over or under) local GAME_DICE_LOSE_MESSAGE = "Sorry %s! You lost the dice game! We rolled %s and you picked %s."; -- First %s is the players name, second %s is the total rolled, third %s is the players choice (over or under) -- Don't change anything below this line local GAME_DICE_ROLL_COUNT = 2; -- Don't change! There is a hard check for the value 7 in this addon. Any change will break the game. -- Prize Stuff local OPEN_PRIZES = {}; local function AddOpenPrize(playerName, amount) if (OPEN_PRIZES[playerName] == nil) then OPEN_PRIZES[playerName] = amount; else OPEN_PRIZES[playerName] = OPEN_PRIZES[playerName] + amount; end end local function HasOpenPrize(playerName) return OPEN_PRIZES[playerName] ~= nil and OPEN_PRIZES[playerName] > 0; end local function GetOpenPrize(playerName) return OPEN_PRIZES[playerName] or 0; end local function UpdateOpenPrize(playerName, amount) if (OPEN_PRIZES[playerName] == nil) then OPEN_PRIZES[playerName] = 0; return; end OPEN_PRIZES[playerName] = math.max(0, OPEN_PRIZES[playerName] - amount); end -- Game stuff local CURRENT_GAMES = {}; local function StartNewGame(playerName, betAmount) CURRENT_GAMES[playerName] = { gamemode = "dice", player = playerName, choice = nil, -- over or under bet = betAmount, rolls = {}, total = 0, winner = nil }; end local function RemoveFinishedGame(game) CURRENT_GAMES[game.player] = nil; end local function HasCurrentGame(playerName) return CURRENT_GAMES[playerName] ~= nil; end local function GetCurrentGame(playerName) return CURRENT_GAMES[playerName]; end local function DoGameRolls(game) if (game.gamemode == "dice") then for i=1, GAME_DICE_ROLL_COUNT do RandomRoll(1, 6); end end end local function IsGameUnfinished(game) if (game.gamemode == "dice") then return game.winner == nil and game.choice ~= nil end end local function GetFirstUnfinishedGame() for playerName, game in pairs(CURRENT_GAMES) do if IsGameUnfinished(game) then return game; end end return nil; end local function AssignRollToGame(game, roll) if (game.gamemode == "dice") then game.rolls[#game.rolls + 1] = roll; game.total = game.total + roll; end end local function HandleGameLogic(game) if (game.gamemode == "dice") then if (#game.rolls < GAME_DICE_ROLL_COUNT) then return; -- Not enough rolls yet end if (game.choice == GAME_DICE_KEYWORD_OVER and game.total > 7) or (game.choice == GAME_DICE_KEYWORD_UNDER and game.total < 7) then game.winner = game.player; local msg = GAME_DICE_WIN_MESSAGE:format(game.player, game.total, game.choice); SendChatMessage(msg, "YELL"); AddOpenPrize(game.player, game.bet * 2); InitiateTrade(game.player); else game.winner = UnitName("player"); local msg = GAME_DICE_LOSE_MESSAGE:format(game.player, game.total, game.choice); SendChatMessage(msg, "YELL"); end RemoveFinishedGame(game); end end -- Trade stuff local ROLL_PATTERN = RANDOM_ROLL_RESULT :gsub("[%-%(%)]", "%%%1") -- Escape special chars :gsub("%%%d%$s", "(%%S+)") -- Prepare player name :gsub("%%%d%$d", "(%%d+)") -- Prepare roll numbers local CURRENT_TRADE = { name = "", playerGold = 0, targetGold = 0 } local function ResetCurrentTrade() CURRENT_TRADE.name = ""; CURRENT_TRADE.playerGold = 0; CURRENT_TRADE.targetGold = 0; end local function CopperToMoneyString(copper) if (copper == nil or copper <= 0) then return "-Nothing-"; end local gold = math.floor(copper / 10000); local silver = math.floor((copper % 10000) / 100); local copper = copper % 100; return string.trim(string.format("%s %s %s", gold > 0 and string.format(GOLD, gold) or "", silver > 0 and string.format(SILVER, silver) or "", copper > 0 and string.format(COPPER, copper) or "")); end local function TradeComplete() if (TRADE_GOLD_RECEIVED_ANNOUNCEMENT ~= "" and CURRENT_TRADE.targetGold > 0) then local msg = TRADE_GOLD_RECEIVED_ANNOUNCEMENT:format(CURRENT_TRADE.name, CopperToMoneyString(CURRENT_TRADE.targetGold)); SendChatMessage(msg, "YELL"); end if (TRADE_GOLD_GIVEN_ANNOUNCEMENT ~= "" and CURRENT_TRADE.playerGold > 0) then local msg = TRADE_GOLD_GIVEN_ANNOUNCEMENT:format(CURRENT_TRADE.name, CopperToMoneyString(CURRENT_TRADE.playerGold)); SendChatMessage(msg, "YELL"); UpdateOpenPrize(CURRENT_TRADE.name, tonumber(CURRENT_TRADE.playerGold)); end if (CURRENT_TRADE.targetGold > 0) then StartNewGame(CURRENT_TRADE.name, CURRENT_TRADE.targetGold); end ResetCurrentTrade(); end local function OnTradeRequestCancel() ResetCurrentTrade(); end local function OnTradeShow() local traderName = strtrim(_G.TradeFrameRecipientNameText:GetText()); ResetCurrentTrade(); CURRENT_TRADE.name = traderName; CURRENT_TRADE.playerGold = 0; CURRENT_TRADE.targetGold = 0; if (HasOpenPrize(traderName)) then local openPrize = GetOpenPrize(traderName); print("Open prize found for "..traderName..": "..CopperToMoneyString(openPrize)); end end local function OnTradeMoneyChanged() CURRENT_TRADE.playerGold = tonumber(GetPlayerTradeMoney()) or 0; CURRENT_TRADE.targetGold = tonumber(GetTargetTradeMoney()) or 0; end local function OnUiInfoMessage(message) if (message == ERR_TRADE_COMPLETE) then TradeComplete(); end end local TIMER_ELAPSED = 0; local function OnUpdate(elapsed) if (not TradeFrame:IsShown()) then return; end TIMER_ELAPSED = TIMER_ELAPSED + elapsed; if (TIMER_ELAPSED > 0.05) then CURRENT_TRADE.playerGold = tonumber(GetPlayerTradeMoney()) or 0; CURRENT_TRADE.targetGold = tonumber(GetTargetTradeMoney()) or 0; end end -- General stuff local function OnSystemMessage(message) local name, roll, min, max = message:match(ROLL_PATTERN) if name and name == UnitName("player") then -- Only handle rolls for us local game = GetFirstUnfinishedGame(); if (game == nil) then return; -- No game to handle end AssignRollToGame(game, tonumber(roll)); HandleGameLogic(game) end end local function OnChatMessage(message, playerName) if (HasCurrentGame(playerName)) then local lowerMessage = string.lower(message); if (lowerMessage == string.lower(GAME_DICE_KEYWORD_OVER) or lowerMessage == string.lower(GAME_DICE_KEYWORD_UNDER)) then local game = GetCurrentGame(playerName); game.choice = lowerMessage; DoGameRolls(game); end end end local eventHandlers = { ["CHAT_MSG_SYSTEM"] = OnSystemMessage, ["CHAT_MSG_SAY"] = OnChatMessage, ["TRADE_REQUEST_CANCEL"] = OnTradeRequestCancel, ["TRADE_SHOW"] = OnTradeShow, ["TRADE_MONEY_CHANGED"] = OnTradeMoneyChanged, ["UI_INFO_MESSAGE"] = OnUiInfoMessage } local frame = CreateFrame("Frame"); frame:RegisterEvent("CHAT_MSG_SYSTEM"); frame:RegisterEvent("CHAT_MSG_SAY"); frame:RegisterEvent("TRADE_ACCEPT_UPDATE"); frame:RegisterEvent("TRADE_REQUEST_CANCEL"); frame:RegisterEvent("TRADE_SHOW"); frame:RegisterEvent("TRADE_CLOSED"); frame:RegisterEvent("TRADE_MONEY_CHANGED"); frame:RegisterEvent("UI_INFO_MESSAGE") frame:SetScript("OnEvent", function(self, event, ...) local args = {...}; local eventHandler = eventHandlers[event]; if eventHandler then eventHandler(unpack(args)); end end); frame:HookScript("OnUpdate", function(self, elapsed) OnUpdate(elapsed); end); SLASH_DICEGAMES1 = "/dicegames"; SLASH_DICEGAMES2 = "/dg"; SlashCmdList["DICEGAMES"] = function(message) print("Open prizes:"); for player, amount in pairs(OPEN_PRIZES) do if (amount >= 1) then print(player..": "..CopperToMoneyString(amount)); end end print("Open games:"); for playerName, game in pairs(CURRENT_GAMES) do print(playerName, game, game.bet, game.choice); end end