From eaabb6d43f72fee07918db4b5629090099447c8c Mon Sep 17 00:00:00 2001 From: Nikolaj Danger Date: Wed, 5 Aug 2020 18:15:45 +0200 Subject: [PATCH] :game_die: monopoly framework --- .gitignore | 1 + Gwendolyn.py | 21 ++- funcs/__init__.py | 6 +- funcs/games/__init__.py | 5 +- funcs/games/monopoly.py | 124 ++++++++++++++++++ funcs/games/monopolyDraw.py | 57 ++++++++ funcs/miscFuncs.py | 29 +++- gameLoops.py | 47 ++++++- resources/errorCodes.txt | 11 ++ resources/games/monopolyBoard.png | Bin 0 -> 23558 bytes .../monopolyBoards/monopolyBoardtest.png | Bin 0 -> 23921 bytes resources/startingFiles.json | 4 +- 12 files changed, 285 insertions(+), 20 deletions(-) create mode 100644 funcs/games/monopoly.py create mode 100644 funcs/games/monopolyDraw.py create mode 100644 resources/games/monopolyBoard.png create mode 100644 resources/games/monopolyBoards/monopolyBoardtest.png diff --git a/.gitignore b/.gitignore index e09e81f..76cf4ae 100644 --- a/.gitignore +++ b/.gitignore @@ -153,6 +153,7 @@ token.txt resources/starWars/swcharacters.json resources/games/games.json resources/games/hexGames.json +resources/games/monopolyGames.json resources/games/blackjackCards/ resources/games/hilo/ resources/starWars/destinyPoints.txt diff --git a/Gwendolyn.py b/Gwendolyn.py index 96bc45b..ce549b1 100644 --- a/Gwendolyn.py +++ b/Gwendolyn.py @@ -10,9 +10,9 @@ import random #import math import os -from funcs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, emojiToNumber, fiarReactionTest, deleteGame, stopServer, checkBalance, giveMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, spellFunc, monsterFunc, nameGen, tavernGen, movieFunc, roll_dice, parseChar, parseRoll, critRoll, parseDestiny, parseHex, addToDict +from funcs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, emojiToCommand, fiarReactionTest, deleteGame, stopServer, checkBalance, giveMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, spellFunc, monsterFunc, nameGen, tavernGen, movieFunc, roll_dice, parseChar, parseRoll, critRoll, parseDestiny, parseHex, addToDict, monopolyReactionTest -from gameLoops import fiar, blackjackLoop, runHex +from gameLoops import fiar, blackjackLoop, runHex, runMonopoly commandPrefix = "!" @@ -569,6 +569,14 @@ async def parseCommands(message,content): except: logThis("Something went wrong (error code 1500)") + # Runs a game of monopoly + elif content.startswith("monopoly"): + try: + command = content.replace("monopoly","",1) + await runMonopoly(message.channel,command,"#"+str(message.author.id)) + except: + logThis("Something went wrong (error code 1600)") + # Not a command else: logThis("That's not a command (error code 001)",str(message.channel)) @@ -615,11 +623,16 @@ async def on_reaction_add(reaction,user): message = reaction.message channel = message.channel logThis(user.display_name+" reacted to a message",str(channel)) - fourInARowTheirTurn, piece = fiarReactionTest(channel,message,"#"+str(user.id)) + try: + fourInARowTheirTurn, piece = fiarReactionTest(channel,message,"#"+str(user.id)) + except: + fourInARowTheirTurn = False if fourInARowTheirTurn: - place = emojiToNumber(reaction.emoji) + place = emojiToCommand(reaction.emoji) await fiar(channel," place "+str(piece)+" "+str(place),user.id) + elif monopolyReactionTest(channel,message): + await runMonopoly(channel,"roll","#"+str(user.id)) # Runs the whole shabang client.run(token) diff --git a/funcs/__init__.py b/funcs/__init__.py index 581b835..c9aff3d 100644 --- a/funcs/__init__.py +++ b/funcs/__init__.py @@ -1,10 +1,10 @@ """A collection of all Gwendolyn functions.""" -__all__ = ["helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToNumber", "fiarReactionTest", "deleteGame", "stopServer", "checkBalance", "giveMoney", "addMoney", "triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "parseChar", "parseRoll", "critRoll", "parseDestiny", "parseHex", "addToDict", "getName", "getID","replaceMultiple","hexAI"] +__all__ = ["helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToCommand", "fiarReactionTest", "deleteGame", "stopServer", "checkBalance", "giveMoney", "addMoney", "triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "parseChar", "parseRoll", "critRoll", "parseDestiny", "parseHex", "addToDict", "getName", "getID", "replaceMultiple", "hexAI", "parseMonopoly", "monopolyContinue", "monopolyReactionTest"] -from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToNumber, fiarReactionTest, deleteGame, stopServer, addToDict, getName, getID +from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToCommand, fiarReactionTest, deleteGame, stopServer, addToDict, getName, getID, monopolyReactionTest -from .games import checkBalance, giveMoney, addMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, parseHex, hexAI +from .games import checkBalance, giveMoney, addMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, parseHex, hexAI, parseMonopoly, monopolyContinue from .lookup import spellFunc, monsterFunc diff --git a/funcs/games/__init__.py b/funcs/games/__init__.py index e577d3e..38b3487 100644 --- a/funcs/games/__init__.py +++ b/funcs/games/__init__.py @@ -1,9 +1,10 @@ """Functions for games Gwendolyn can play.""" -__all__ = ["checkBalance", "giveMoney", "addMoney","triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "parseHex"] +__all__ = ["checkBalance", "giveMoney", "addMoney","triviaCountPoints", "triviaStart", "triviaAnswer", "blackjackShuffle", "blackjackStart", "blackjackPlayerDrawHand", "blackjackContinue", "blackjackFinish", "blackjackHit", "blackjackStand", "blackjackDouble", "blackjackSplit", "parseFourInARow", "fourInARowAI", "parseHex", "parseMonopoly", "monopolyContinue"] from .money import checkBalance, giveMoney, addMoney from .trivia import triviaCountPoints, triviaStart, triviaAnswer from .blackjack import blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit from .fourInARow import parseFourInARow, fourInARowAI -from .hex import parseHex, hexAI \ No newline at end of file +from .hex import parseHex, hexAI +from .monopoly import parseMonopoly, monopolyContinue \ No newline at end of file diff --git a/funcs/games/monopoly.py b/funcs/games/monopoly.py new file mode 100644 index 0000000..4990add --- /dev/null +++ b/funcs/games/monopoly.py @@ -0,0 +1,124 @@ +import json, random + +from funcs import getName, logThis +from . import monopolyDraw + +def monopolyStart(channel): + logThis("Starting a monopoly game") + with open("resources/games/monopolyGames.json", "r") as f: + data = json.load(f) + + if channel not in data: + buildings = [0] * 40 + + data[channel] = {"players" : {}, "player list" : [],"turn" : 0, "buildings" : buildings, "last roll" : [0,0], "started" : False} + + with open("resources/games/monopolyGames.json", "w") as f: + json.dump(data,f,indent=4) + + try: + monopolyDraw.drawImage(channel) + except: + logThis("Error drawing board (error code 1640)") + + return "Started a monopoly game. Use \"!monopoly join\" to join within the next minute.", True, False, True, True + else: + return "There's already a monopoly game going on.", False, False, False, False + +def monopolyJoin(channel,user): + with open("resources/games/monopolyGames.json", "r") as f: + data = json.load(f) + + if channel in data: + if not data[channel]["started"]: + if user not in data[channel]["players"]: + if len(data[channel]["players"]) < 6: + + data[channel]["players"][user] = {"position" : 0, "properties" : [], "money" : 1500, "doubles" : 0} + + with open("resources/games/monopolyGames.json", "w") as f: + json.dump(data,f,indent=4) + + return getName(user)+" has joined the game.", False, False, False, False + else: + return "There are already 6 players in the game.", False, False, False, False + else: + return "You're already in the game!", False, False, False, False + else: + return "It's too late to join.", False, False, False, False + else: + return "There's no game going on.", False, False, False, False + +def parseMonopoly(command, channel, user): + logThis("Parsing "+command) + commands = command.split() + if command in [" ", ""] or commands[0] == "start": + try: + return monopolyStart(channel) + except: + logThis("Error starting game (error code 1620)") + elif commands[0] == "join": + try: + return monopolyJoin(channel,user) + except: + logThis("Error joining game (error code 1630)") + elif commands[0] == "roll": + try: + return monopolyRoll(channel,user) + except: + logThis("Error rolling (error code 1650)") + else: + return "I didn't understand that (error code 1602)", False, False, False, False + +def monopolyContinue(channel): + with open("resources/games/monopolyGames.json", "r") as f: + data = json.load(f) + + if channel in data: + if data[channel]["started"] == False: + data[channel]["started"] = True + playerList = list(data[channel]["players"].keys()) + random.shuffle(playerList) + data[channel]["player list"] = playerList + turn = 0 + + else: + turn = (data[channel]["turn"])%len(data[channel]["player list"]) + data[channel]["turn"] = turn + playerList = list(data[channel]["players"].keys()) + + with open("resources/games/monopolyGames.json", "w") as f: + json.dump(data,f,indent=4) + + try: + monopolyDraw.drawImage(channel) + except: + logThis("Error drawing board (error code 1640)") + + message = "It's "+getName(playerList[turn])+"'s turn. Use the 🎲 reaction to roll. You can also use \"!monopoly trade\" at any time." + return message, True, True, False + +def monopolyRoll(channel,user): + with open("resources/games/monopolyGames.json", "r") as f: + data = json.load(f) + + turn = data[channel]["turn"] + currentPlayer = data[channel]["player list"][turn] + + if user == currentPlayer: + rolls = [random.randint(1,6),random.randint(1,6)] + roll = rolls[0] + rolls[1] + newPosition = (data[channel]["players"][user]["position"] + roll)%40 + data[channel]["players"][user]["position"] = newPosition + data[channel]["last roll"] = rolls + + with open("resources/games/monopolyGames.json", "w") as f: + json.dump(data,f,indent=4) + + try: + monopolyDraw.drawImage(channel) + except: + logThis("Error drawing board (error code 1640)") + + return "Rolled a "+str(rolls[0])+" and a "+str(rolls[1])+".", True, True, False, True + else: return "", False, False, False, False diff --git a/funcs/games/monopolyDraw.py b/funcs/games/monopolyDraw.py new file mode 100644 index 0000000..598cc8c --- /dev/null +++ b/funcs/games/monopolyDraw.py @@ -0,0 +1,57 @@ +import math, json + +from funcs import logThis + +from PIL import Image, ImageDraw + +w, h = 1440, 1440 +largeSpace = 191 +smallSpace = math.floor((w - 2*largeSpace)/9) +avatarSize = 50 +avatarHalf = math.floor(avatarSize/2) + +def drawImage(channel): + logThis("Drawing monopoly board for "+channel) + with open("resources/games/monopolyGames.json", "r") as f: + data = json.load(f) + + board = Image.open("resources/games/monopolyBoard.png") + d = ImageDraw.Draw(board,"RGBA") + + for key, value in list(data[channel]["players"].items()): + logThis("Drawing "+key) + try: + x, y = getPosition(value["position"]) + except: + logThis("Error getting position (error code 1641)") + print(str(x)+", "+str(y)) + d.ellipse([(x-avatarHalf,y-avatarHalf),(x+avatarHalf,y+avatarHalf)],fill=(255,0,0)) + + board.save("resources/games/monopolyBoards/monopolyBoard"+channel+".png") + + +def getPosition(positionNumber): + print(positionNumber) + + x, y = 0, 0 + if positionNumber == 0 or positionNumber >= 30: + x = math.floor(largeSpace/2) + elif positionNumber > 0 and positionNumber < 10: + x = math.floor(largeSpace - (smallSpace/2)) + (smallSpace*positionNumber) + elif positionNumber >= 10 and positionNumber <= 20: + x = w - math.floor(largeSpace/2) + elif positionNumber > 20 and positionNumber < 30: + x = w - math.floor(largeSpace - (smallSpace/2)) - (smallSpace*(positionNumber - 20)) + + if positionNumber >= 0 and positionNumber <= 9: + y = math.floor(largeSpace/2) + elif positionNumber > 10 and positionNumber < 19: + y = math.floor(largeSpace - (smallSpace/2)) + (smallSpace*(positionNumber-10)) + elif positionNumber >= 20 and positionNumber <= 30: + y = h - math.floor(largeSpace/2) + elif positionNumber > 30: + y = h - math.floor(largeSpace - (smallSpace/2)) - (smallSpace*(positionNumber - 30)) + + return x, y + + diff --git a/funcs/miscFuncs.py b/funcs/miscFuncs.py index b7fbf78..6e17e5d 100644 --- a/funcs/miscFuncs.py +++ b/funcs/miscFuncs.py @@ -186,7 +186,7 @@ def replaceMultiple(mainString, toBeReplaces, newString): return mainString -def emojiToNumber(emoji): +def emojiToCommand(emoji): if emoji == "1️⃣": return 1 elif emoji == "2️⃣": @@ -201,6 +201,8 @@ def emojiToNumber(emoji): return 6 elif emoji == "7️⃣": return 7 + elif emoji == "🎲": + return "roll" else: return "" def fiarReactionTest(channel,message,user): @@ -223,16 +225,31 @@ def fiarReactionTest(channel,message,user): else: return False, 0 +def monopolyReactionTest(channel,message): + with open("resources/games/oldImages/monopoly"+str(channel), "r") as f: + oldImage = int(f.read()) + + if message.id == oldImage: + logThis("They reacted to the monopoly game") + return True + else: + return False + def stopServer(): with open("resources/games/games.json","r") as f: - data = json.load(f) + games = json.load(f) - data["trivia questions"] = {} - data["blackjack games"] = {} - data["4 in a row games"] = {} + games["trivia questions"] = {} + games["blackjack games"] = {} + games["4 in a row games"] = {} with open("resources/games/games.json","w") as f: - json.dump(data,f,indent=4) + json.dump(games,f,indent=4) + + emptyDict = {} + + with open("resources/games/monopolyGames.json", "w") as f: + json.dump(emptyDict,f,indent=4) def deleteGame(gameType,channel): with open("resources/games/games.json", "r") as f: diff --git a/gameLoops.py b/gameLoops.py index e8ef39f..058f033 100644 --- a/gameLoops.py +++ b/gameLoops.py @@ -2,7 +2,7 @@ import asyncio import discord import json -from funcs import logThis, addMoney, deleteGame, parseFourInARow, fourInARowAI, blackjackContinue, blackjackFinish, parseHex, hexAI +from funcs import logThis, addMoney, deleteGame, parseFourInARow, fourInARowAI, blackjackContinue, blackjackFinish, parseHex, hexAI, parseMonopoly, monopolyContinue # Deletes a message async def deleteMessage(imageLocation,channel): @@ -119,9 +119,6 @@ async def fiar(channel,command,user): await oldImage.add_reaction(reaction) except: logThis("Image deleted before I could react to all of them") -# else: -# with open("resources/games/oldImages/fourInARow"+str(channel), "w") as f: -# f.write(str(oldImage.id)) if gameDone: with open("resources/games/games.json", "r") as f: @@ -192,3 +189,45 @@ async def blackjackLoop(channel,gameRound,gameID): logThis("Ending loop on round "+str(gameRound),str(channel)) else: logThis("Ending loop on round "+str(gameRound),str(channel)) + +async def runMonopoly(channel, command, user): + try: + response, showImage, deleteImage, gameStarted, gameContinue = parseMonopoly(command,str(channel),user) + except: + logThis("Error parsing command (error code 1610)") + if response != "": + await channel.send(response) + logThis(response,str(channel)) + if showImage: + if deleteImage: + try: + oldImage = await deleteMessage("monopoly"+str(channel),channel) + except: + logThis("Error deleting message (error code 1601)") + oldImage = await channel.send(file = discord.File("resources/games/monopolyBoards/monopolyBoard"+str(channel)+".png")) + with open("resources/games/oldImages/monopoly"+str(channel), "w") as f: + f.write(str(oldImage.id)) + + if gameContinue: + if gameStarted: + await asyncio.sleep(60) + else: + await asyncio.sleep(5) + response, showImage, deleteImage, gameDone = monopolyContinue(str(channel)) + em = discord.Embed(description=response,colour = 0x59f442) + await channel.send(embed=em) + if showImage: + if deleteImage: + try: + oldImage = await deleteMessage("monopoly"+str(channel),channel) + except: + logThis("Error deleting message (error code 1601)") + oldImage = await channel.send(file = discord.File("resources/games/monopolyBoards/monopolyBoard"+str(channel)+".png")) + with open("resources/games/oldImages/monopoly"+str(channel), "w") as f: + f.write(str(oldImage.id)) + if gameDone == False: + try: + await oldImage.add_reaction("🎲") + except: + logThis("Image deleted before I could react to all of them") + \ No newline at end of file diff --git a/resources/errorCodes.txt b/resources/errorCodes.txt index adde8e4..1e08b02 100644 --- a/resources/errorCodes.txt +++ b/resources/errorCodes.txt @@ -113,3 +113,14 @@ 1531 - Invalid position 1532 - Cannot place on existing piece 1533 - Position out of bounds + +16 - Monopoly +1600 - Unspecified error +1601 - Error deleting old image +1602 - Not a command +1610 - Unspecified parsing error +1620 - Unspecified monopolyStart() error +1630 - Unspecified monopolyJoin() error +1640 - Unspecified monopolyDraw error +1641 - Error in getPosition() +1650 - Error in monopolyRoll() diff --git a/resources/games/monopolyBoard.png b/resources/games/monopolyBoard.png new file mode 100644 index 0000000000000000000000000000000000000000..a7cb5c8eb03f7fd0236155b361b09e89bf381873 GIT binary patch literal 23558 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 E0M$H#m;e9( literal 0 HcmV?d00001 diff --git a/resources/games/monopolyBoards/monopolyBoardtest.png b/resources/games/monopolyBoards/monopolyBoardtest.png new file mode 100644 index 0000000000000000000000000000000000000000..50d8787946f2373e839a28ad49e99eb6bc35f2e9 GIT binary patch literal 23921 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