:spakles: Database and OOP

This commit is contained in:
NikolajDanger
2020-08-13 16:31:28 +02:00
parent f431c079d1
commit 4127e537a1
31 changed files with 3674 additions and 3731 deletions

1
.gitignore vendored
View File

@ -151,6 +151,7 @@ static
.vscode/
token.txt
credentials.txt
options.txt
resources/starWars/swcharacters.json
resources/games/games.json
resources/games/hexGames.json

View File

@ -2,7 +2,7 @@ import discord, os, finnhub, pymongo
from discord.ext import commands
from pymongo import MongoClient
from funcs import logThis, makeFiles, transferUsers
from funcs import logThis, makeFiles, transferUsers, Money, Funcs, SwChar, SwDestiny, SwRoll, Games
commandPrefix = "!"
@ -30,8 +30,22 @@ class Gwendolyn(commands.Bot):
self.options = Options()
self.credentials = Credentials()
self.finnhubClient = finnhub.Client(api_key = self.credentials.finnhubKey)
self.MongoClient = MongoClient(f"mongodb+srv://{self.credentials.mongoDBUser}:{self.credentials.mongoDBPassword}@gwendolyn.qkwfy.mongodb.net/Gwendolyn-Test?retryWrites=true&w=majority")
self.database = self.MongoClient["Gwendolyn-Test"]
self.MongoClient = MongoClient(f"mongodb+srv://{self.credentials.mongoDBUser}:{self.credentials.mongoDBPassword}@gwendolyn.qkwfy.mongodb.net/Gwendolyn?retryWrites=true&w=majority")
if self.options.testing:
self.database = self.MongoClient["Gwendolyn-Test"]
else:
self.database = self.MongoClient["Gwendolyn"]
self.swchar = SwChar(self)
self.swroll = SwRoll(self)
self.swdestiny = SwDestiny(self)
Games(self)
self.money = Money(self)
self.funcs = Funcs(self)
super().__init__(command_prefix=commandPrefix, case_insensitive=True)
# Creates the required files

View File

@ -1,7 +1,7 @@
import discord, asyncio
from discord.ext import commands
from funcs import logThis, triviaAnswer, triviaCountPoints, triviaStart, deleteGame, checkBalance, giveMoney, parseBlackjack, parseInvest, fiar, runMonopoly, runHex, runHangman
from funcs import logThis
class GamesCog(commands.Cog):
@ -12,7 +12,7 @@ class GamesCog(commands.Cog):
# Checks user balance
@commands.command(aliases = ["b"])
async def balance(self, ctx):
response = checkBalance("#"+str(ctx.message.author.id))
response = self.client.money.checkBalance("#"+str(ctx.message.author.id))
if response == 1:
new_message = ctx.message.author.display_name + " has " + str(response) + " GwendoBuck"
else:
@ -25,7 +25,7 @@ class GamesCog(commands.Cog):
commands = content.split(" ")
if len(commands) == 2:
amount = int(commands[1])
response = giveMoney("#"+str(ctx.message.author.id),commands[0],amount)
response = self.client.money.giveMoney("#"+str(ctx.message.author.id),commands[0],amount)
await ctx.send(response)
else:
logThis("I didn't understand that (error code 1222)",str(ctx.message.channel.id))
@ -34,7 +34,7 @@ class GamesCog(commands.Cog):
# Invest GwendoBucks in the stock market
@commands.command(aliases=["i"])
async def invest(self, ctx, *, content = "check"):
response = parseInvest(content,"#"+str(ctx.message.author.id),self.client.finnhubClient)
response = self.client.invest.parseInvest(content,"#"+str(ctx.message.author.id))
if response.startswith("**"):
responses = response.split("\n")
em = discord.Embed(title=responses[0],description="\n".join(responses[1:]),colour=0x00FF00)
@ -46,7 +46,7 @@ class GamesCog(commands.Cog):
@commands.command()
async def trivia(self, ctx, *, content = ""):
if content == "":
question, answers, correctAnswer = triviaStart(str(ctx.message.channel.id))
question, answers, correctAnswer = self.client.trivia.triviaStart(str(ctx.message.channel.id))
if answers != "":
results = "**"+question+"**\n"
for x, answer in enumerate(answers):
@ -56,9 +56,9 @@ class GamesCog(commands.Cog):
await asyncio.sleep(60)
triviaCountPoints(str(ctx.message.channel.id))
self.client.trivia.triviaCountPoints(str(ctx.message.channel.id))
deleteGame("trivia questions",str(ctx.message.channel.id))
self.client.funcs.deleteGame("trivia questions",str(ctx.message.channel.id))
logThis("Time's up for the trivia question",str(ctx.message.channel.id))
await ctx.send("Time's up The answer was \""+chr(correctAnswer)+") "+answers[correctAnswer-97]+"\". Anyone who answered that has gotten 1 GwendoBuck")
@ -66,7 +66,7 @@ class GamesCog(commands.Cog):
await ctx.send(question)
elif content in ["a","b","c","d"]:
response = triviaAnswer("#"+str(ctx.message.author.id),str(ctx.message.channel.id),content)
response = self.client.trivia.triviaAnswer("#"+str(ctx.message.author.id),str(ctx.message.channel.id),content)
if response.startswith("Locked in "):
await ctx.message.add_reaction("👍")
else:
@ -78,27 +78,27 @@ class GamesCog(commands.Cog):
# Runs a game of blackjack
@commands.command(aliases = ["bj"])
async def blackjack(self, ctx, *, content = ""):
await parseBlackjack(content,ctx)
await self.client.blackjack.parseBlackjack(content,ctx)
# Runs a game of Connect four
@commands.command(aliases = ["fiar","connect4","connectfour","4iar","4inarow"])
async def fourinarow(self, ctx, *, content = ""):
await fiar(ctx.message.channel,content,"#"+str(ctx.message.author.id))
# Runs a game of Hex
@commands.command(name="hex")
async def hexCommand(self, ctx, *, content = ""):
await runHex(ctx.message.channel,content,"#"+str(ctx.message.author.id))
await self.client.gameLoops.fiar(ctx.message.channel,content,"#"+str(ctx.message.author.id))
# Runs a game of Monopoly
@commands.command(aliases = ["m","mon","mono"])
async def monopoly(self, ctx, *, content = ""):
await runMonopoly(ctx.message.channel,content,"#"+str(ctx.message.author.id))
await self.client.gameLoops.runMonopoly(ctx.message.channel,content,"#"+str(ctx.message.author.id))
# Runs a game of Hangman
@commands.command(aliases = ["hm"])
async def hangman(self, ctx, *, content = "start"):
await runHangman(ctx.message.channel,"#"+str(ctx.message.author.id),self.client.credentials.wordnikKey,content)
await self.client.gameLoops.runHangman(ctx.message.channel,"#"+str(ctx.message.author.id),content)
# Runs a game of Hex
@commands.command(name="hex")
async def hexCommand(self, ctx, *, content = ""):
await self.client.gameLoops.runHex(ctx.message.channel,content,"#"+str(ctx.message.author.id))
def setup(client):
client.add_cog(GamesCog(client))

View File

@ -1,7 +1,7 @@
import discord, codecs, string
from discord.ext import commands
from funcs import logThis, stopServer, helloFunc, roll_dice, imageFunc, nameGen, tavernGen, movieFunc, cap, findWikiPage
from funcs import logThis, helloFunc, roll_dice, imageFunc, nameGen, tavernGen, movieFunc, cap, findWikiPage
class MiscCog(commands.Cog):
@ -40,7 +40,7 @@ class MiscCog(commands.Cog):
if "#"+str(ctx.message.author.id) in ["#266269899859427329", "#380732645602230272"]:
await ctx.send("Pulling git repo and restarting...")
stopServer()
self.client.funcs.stopServer()
await self.client.logout()
else:

View File

@ -1,6 +1,6 @@
from discord.ext import commands
from funcs import logThis, fiarReactionTest, monopolyReactionTest, emojiToCommand, fiar, runMonopoly, hangmanReactionTest, runHangman
from funcs import logThis, emojiToCommand
class ReactionCog(commands.Cog):
def __init__(self, client):
@ -14,17 +14,17 @@ class ReactionCog(commands.Cog):
channel = message.channel
logThis(user.display_name+" reacted to a message",str(channel.id))
try:
fourInARowTheirTurn, piece = fiarReactionTest(channel,message,"#"+str(user.id))
fourInARowTheirTurn, piece = self.client.funcs.fiarReactionTest(channel,message,"#"+str(user.id))
except:
fourInARowTheirTurn = False
if fourInARowTheirTurn:
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))
elif hangmanReactionTest(channel,message):
await self.client.gameLoops.fiar(channel," place "+str(piece)+" "+str(place),user.id)
elif self.client.funcs.monopolyReactionTest(channel,message):
await self.client.gameLoops.runMonopoly(channel,"roll","#"+str(user.id))
elif self.client.funcs.hangmanReactionTest(channel,message):
guess = chr(ord(reaction.emoji)-127397)
await runHangman(channel,"#"+str(user.id),command="guess "+guess)
await self.client.gameLoops.runHangman(channel,"#"+str(user.id),command="guess "+guess)
def setup(client):
client.add_cog(ReactionCog(client))

View File

@ -1,7 +1,7 @@
import discord, string
from discord.ext import commands
from funcs import parseRoll, parseDestiny, critRoll, parseChar, cap
from funcs import cap
class SwCog(commands.Cog):
@ -13,7 +13,7 @@ class SwCog(commands.Cog):
@commands.command()
async def swroll(self, ctx, *, content):
command = cap(content)
newMessage = parseRoll("#"+str(ctx.message.author.id),command)
newMessage = self.client.swroll.parseRoll("#"+str(ctx.message.author.id),command)
messageList = newMessage.split("\n")
for messageItem in messageList:
await ctx.send(messageItem)
@ -21,7 +21,7 @@ class SwCog(commands.Cog):
# Controls destiny points
@commands.command()
async def swd(self, ctx, *, content):
newMessage = parseDestiny("#"+str(ctx.message.author.id),content)
newMessage = self.client.swdestiny.parseDestiny("#"+str(ctx.message.author.id),content)
messageList = newMessage.split("\n")
for messageItem in messageList:
await ctx.send(messageItem)
@ -29,7 +29,7 @@ class SwCog(commands.Cog):
# Rolls for critical injuries
@commands.command()
async def swcrit(self, ctx, arg : int = 0):
newMessage = critRoll(int(arg))
newMessage = self.client.swroll.critRoll(int(arg))
messageList = newMessage.split("\n")
for messageItem in messageList:
@ -40,7 +40,7 @@ class SwCog(commands.Cog):
@commands.command(aliases=["sw"])
async def swchar(self, ctx, *, content = ""):
command = string.capwords(content.replace("+","+ ").replace("-","- ").replace(",",", "))
title, desc = parseChar("#"+str(ctx.message.author.id),command)
title, desc = self.client.swchar.parseChar("#"+str(ctx.message.author.id),command)
if title != "":
em1 = discord.Embed(title = title, description = desc, colour=0xDEADBF)
await ctx.send(embed = em1)

View File

@ -1,10 +1,12 @@
"""A collection of all Gwendolyn functions."""
__all__ = ["helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToCommand", "fiarReactionTest", "deleteGame", "stopServer", "checkBalance", "giveMoney", "addMoney", "triviaCountPoints", "triviaStart", "triviaAnswer", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "parseChar", "parseRoll", "critRoll", "parseDestiny", "addToDict", "getName", "getID", "replaceMultiple", "monopolyReactionTest","parseInvest", "fiar", "runMonopoly", "runHex", "runHangman","hangmanReactionTest", "parseBlackjack","transferUsers"]
#__all__ = ["Games" ,"helloFunc", "cap", "imageFunc", "logThis", "findWikiPage", "makeFiles", "emojiToCommand", "Money", "spellFunc", "monsterFunc", "nameGen", "tavernGen", "movieFunc", "roll_dice", "SwChar", "SwDestiny", "SwRoll", "addToDict", "replaceMultiple", "transferUsers","Funcs"]
from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToCommand, fiarReactionTest, deleteGame, stopServer, addToDict, getName, getID, monopolyReactionTest, hangmanReactionTest, transferUsers
from .miscFuncs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, replaceMultiple, emojiToCommand, addToDict, transferUsers
from .games import checkBalance, giveMoney, addMoney, triviaCountPoints, triviaStart, triviaAnswer, fiar, runMonopoly, runHex, runHangman, parseBlackjack, parseInvest
from .funcs import Funcs
from .games import Money, Games
from .lookup import spellFunc, monsterFunc
@ -12,4 +14,4 @@ from .other import nameGen, tavernGen, movieFunc
from .roll import roll_dice
from .swfuncs import parseChar, parseRoll, parseDestiny, critRoll
from .swfuncs import SwChar, SwDestiny, SwRoll

84
funcs/funcs.py Normal file
View File

@ -0,0 +1,84 @@
from .miscFuncs import logThis
import git # Used by stopServer()
class Funcs():
def __init__(self,bot):
self.bot = bot
def getName(self,userID):
user = self.bot.database["users"].find_one({"_id":userID})
if user != None:
return user["user name"]
else:
logThis("Couldn't find user "+userID)
return userID
def getID(self,userName):
user = self.bot.database["users"].find_one({"user name":userName})
if user != None:
return user["_id"]
else:
logThis("Couldn't find user "+userName)
return None
def deleteGame(self, gameType,channel):
self.bot.database[gameType].delete_one({"_id":channel})
def stopServer(self):
self.bot.database["trivia questions"].delete_many({})
self.bot.database["blackjack games"].delete_many({})
self.bot.database["4 in a row games"].delete_many({})
self.bot.database["hangman games"].delete_many({})
self.bot.database["hex games"].delete_many({})
self.bot.database["monopoly games"].delete_many({})
g = git.cmd.Git("")
g.pull()
def fiarReactionTest(self,channel,message,user):
game = self.bot.database["4 in a row games"].find_one({"_id":str(channel.id)})
with open("resources/games/oldImages/fourInARow"+str(channel.id), "r") as f:
oldImage = int(f.read())
if message.id == oldImage:
logThis("They reacted to the fourinarow game")
turn = game["turn"]
if user == game["players"][turn]:
return True, turn+1
else:
logThis("It wasn't their turn")
return False, 0
else:
return False, 0
def monopolyReactionTest(self,channel,message):
try:
with open("resources/games/oldImages/monopoly"+str(channel.id), "r") as f:
oldImage = int(f.read())
except:
return False
if message.id == oldImage:
logThis("They reacted to the monopoly game")
return True
else:
return False
def hangmanReactionTest(self, channel,message):
try:
with open("resources/games/oldImages/hangman"+str(channel.id), "r") as f:
oldMessages = f.read().splitlines()
except:
return False
gameMessage = False
for oldMessage in oldMessages:
oldMessageID = int(oldMessage)
if message.id == oldMessageID:
logThis("They reacted to the hangman game")
gameMessage = True
return gameMessage

View File

@ -1,9 +1,6 @@
"""Functions for games Gwendolyn can play."""
__all__ = ["checkBalance", "giveMoney", "addMoney","triviaCountPoints", "triviaStart", "triviaAnswer", "parseInvest", "blackjackLoop", "fiar", "runMonopoly", "runHex", "runHangman", "parseBlackjack"]
#__all__ = ["Money", "Games"]
from .money import checkBalance, giveMoney, addMoney
from .trivia import triviaCountPoints, triviaStart, triviaAnswer
from .invest import parseInvest
from .gameLoops import fiar, runMonopoly, runHex, runHangman
from .blackjackLoop import blackjackLoop, parseBlackjack
from .money import Money
from .games import Games

File diff suppressed because it is too large Load Diff

View File

@ -1,140 +1,142 @@
import json
from PIL import Image, ImageDraw, ImageFont
from funcs import logThis, getName
from funcs import logThis
border = 100
placement = [0,0]
rotation = 0
def drawImage(channel):
logThis("Drawing blackjack table",channel)
with open("resources/games/games.json", "r") as f:
data = json.load(f)
fnt = ImageFont.truetype('resources/futura-bold.ttf', 50)
fntSmol = ImageFont.truetype('resources/futura-bold.ttf', 40)
borderSmol = int(border/3.5)
class DrawBlackjack():
def __init__(self,bot):
self.bot = bot
table = Image.open("resources/games/blackjackTable.png")
placement = [2,1,3,0,4]
textImage = ImageDraw.Draw(table)
hands = data["blackjack games"][channel]["user hands"]
def drawImage(self,channel):
logThis("Drawing blackjack table",channel)
game = self.bot.database["blackjack games"].find_one({"_id":channel})
dealerBusted = data["blackjack games"][channel]["dealer busted"]
dealerBlackjack = data["blackjack games"][channel]["dealer blackjack"]
fnt = ImageFont.truetype('resources/futura-bold.ttf', 50)
fntSmol = ImageFont.truetype('resources/futura-bold.ttf', 40)
borderSmol = int(border/3.5)
try:
if data["blackjack games"][channel]["all standing"] == False:
dealerHand = drawHand(data["blackjack games"][channel]["dealer hand"],True,False,False)
else:
dealerHand = drawHand(data["blackjack games"][channel]["dealer hand"],False,dealerBusted,dealerBlackjack)
except:
logThis("Error drawing dealer hand (error code 1341a)")
table = Image.open("resources/games/blackjackTable.png")
placement = [2,1,3,0,4]
textImage = ImageDraw.Draw(table)
hands = game["user hands"]
table.paste(dealerHand,(800-borderSmol,20-borderSmol),dealerHand)
dealerBusted = game["dealer busted"]
dealerBlackjack = game["dealer blackjack"]
for x in range(len(hands)):
key, value = list(hands.items())[x]
key = getName(key)
#logThis("Drawing "+key+"'s hand")
userHand = drawHand(value["hand"],False,value["busted"],value["blackjack"])
try:
if value["split"] == 3:
table.paste(userHand,(32-borderSmol+(384*placement[x]),280-borderSmol),userHand)
userOtherHand = drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userOtherHand)
userThirdHand = drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userThirdHand)
userFourthHand = drawHand(value["fourth hand"]["hand"],False,value["fourth hand"]["busted"],value["fourth hand"]["blackjack"])
table.paste(userFourthHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userFourthHand)
elif value["split"] == 2:
table.paste(userHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userHand)
userOtherHand = drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userOtherHand)
userThirdHand = drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userThirdHand)
elif value["split"] == 1:
table.paste(userHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userHand)
userOtherHand = drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userOtherHand)
if game["all standing"] == False:
dealerHand = self.drawHand(game["dealer hand"],True,False,False)
else:
table.paste(userHand,(32-borderSmol+(384*placement[x]),680-borderSmol),userHand)
dealerHand = self.drawHand(game["dealer hand"],False,dealerBusted,dealerBlackjack)
except:
logThis("Error drawing player hands (error code 1341b)")
logThis("Error drawing dealer hand (error code 1341a)")
textWidth = fnt.getsize(key)[0]
if textWidth < 360:
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1005),key,fill=(255,255,255), font=fnt)
else:
textWidth = fntSmol.getsize(key)[0]
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1015),key,fill=(255,255,255), font=fntSmol)
table.paste(dealerHand,(800-borderSmol,20-borderSmol),dealerHand)
logThis("Saving table image")
table.save("resources/games/blackjackTables/blackjackTable"+channel+".png")
for x in range(len(hands)):
key, value = list(hands.items())[x]
key = self.bot.funcs.getName(key)
#logThis("Drawing "+key+"'s hand")
userHand = self.drawHand(value["hand"],False,value["busted"],value["blackjack"])
try:
if value["split"] == 3:
table.paste(userHand,(32-borderSmol+(384*placement[x]),280-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userThirdHand)
userFourthHand = self.drawHand(value["fourth hand"]["hand"],False,value["fourth hand"]["busted"],value["fourth hand"]["blackjack"])
table.paste(userFourthHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userFourthHand)
elif value["split"] == 2:
table.paste(userHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userThirdHand)
elif value["split"] == 1:
table.paste(userHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userOtherHand)
else:
table.paste(userHand,(32-borderSmol+(384*placement[x]),680-borderSmol),userHand)
except:
logThis("Error drawing player hands (error code 1341b)")
return
textWidth = fnt.getsize(key)[0]
if textWidth < 360:
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1005),key,fill=(255,255,255), font=fnt)
else:
textWidth = fntSmol.getsize(key)[0]
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1015),key,fill=(255,255,255), font=fntSmol)
def drawHand(hand, dealer, busted, blackjack):
logThis("Drawing hand "+str(hand))
fnt = ImageFont.truetype('resources/futura-bold.ttf', 200)
fnt2 = ImageFont.truetype('resources/futura-bold.ttf', 120)
length = len(hand)
background = Image.new("RGBA", ((border*2)+691+(125*(length-1)),(border*2)+1065),(0,0,0,0))
textImage = ImageDraw.Draw(background)
logThis("Saving table image")
table.save("resources/games/blackjackTables/blackjackTable"+channel+".png")
if dealer:
img = Image.open("resources/games/cards/"+hand[0].upper()+".png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(border+placement[0],border+placement[1]),img)
img = Image.open("resources/games/cards/red_back.png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(125+border+placement[0],border+placement[1]),img)
else:
for x in range(length):
img = Image.open("resources/games/cards/"+hand[x].upper()+".png")
return
def drawHand(self, hand, dealer, busted, blackjack):
logThis("Drawing hand "+str(hand)+", "+str(busted)+", "+str(blackjack))
fnt = ImageFont.truetype('resources/futura-bold.ttf', 200)
fnt2 = ImageFont.truetype('resources/futura-bold.ttf', 120)
length = len(hand)
background = Image.new("RGBA", ((border*2)+691+(125*(length-1)),(border*2)+1065),(0,0,0,0))
textImage = ImageDraw.Draw(background)
if dealer:
img = Image.open("resources/games/cards/"+hand[0].upper()+".png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(border+(x*125)+placement[0],border+placement[1]),img)
w, h = background.size
textHeight = 290+border
background.paste(img,(border+placement[0],border+placement[1]),img)
img = Image.open("resources/games/cards/red_back.png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(125+border+placement[0],border+placement[1]),img)
else:
for x in range(length):
img = Image.open("resources/games/cards/"+hand[x].upper()+".png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(border+(x*125)+placement[0],border+placement[1]),img)
#logThis("Drawing busted/blackjack")
if busted:
textWidth = fnt.getsize("BUSTED")[0]
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight+5),"BUSTED",fill=(255,255,225), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight+5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BUSTED",fill=(255,50,50), font=fnt)
elif blackjack:
textWidth = fnt2.getsize("BLACKJACK")[0]
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BLACKJACK",fill=(155,123,0), font=fnt2)
#logThis("Returning resized image")
return background.resize((int(w/3.5),int(h/3.5)),resample=Image.BILINEAR)
w, h = background.size
textHeight = 290+border
#logThis("Drawing busted/blackjack")
if busted:
textWidth = fnt.getsize("BUSTED")[0]
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight+5),"BUSTED",fill=(255,255,225), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight+5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BUSTED",fill=(255,50,50), font=fnt)
elif blackjack:
textWidth = fnt2.getsize("BLACKJACK")[0]
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BLACKJACK",fill=(155,123,0), font=fnt2)
#logThis("Returning resized image")
return background.resize((int(w/3.5),int(h/3.5)),resample=Image.BILINEAR)

View File

@ -1,231 +0,0 @@
import discord, json, os, asyncio
from .blackjack import blackjackContinue, blackjackSplit, blackjackShuffle, blackjackStart, blackjackFinish, blackjackPlayerDrawHand, blackjackHit, blackjackStand, blackjackDouble
from funcs import logThis
# Loop of blackjack game rounds
async def blackjackLoop(channel,gameRound,gameID):
logThis("Loop "+str(gameRound),str(channel.id))
with open("resources/games/oldImages/blackjack"+str(channel.id), "r") as f:
oldImage = await channel.fetch_message(int(f.read()))
new_message, allStanding, gamedone = blackjackContinue(str(channel.id))
if new_message != "":
logThis(new_message,str(channel.id))
await channel.send(new_message)
if gamedone == False:
await oldImage.delete()
oldImage = await channel.send(file = discord.File("resources/games/blackjackTables/blackjackTable"+str(channel.id)+".png"))
with open("resources/games/oldImages/blackjack"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
try:
if allStanding:
await asyncio.sleep(5)
else:
await asyncio.sleep(120)
except:
logThis("Loop "+str(gameRound)+" interrupted (error code 1321)")
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if str(channel.id) in data["blackjack games"]:
realRound = data["blackjack games"][str(channel.id)]["round"]
realGameID = data["blackjack games"][str(channel.id)]["id"]
if gameRound == realRound and realGameID == gameID:
if gamedone == False:
logThis("Loop "+str(gameRound)+" calling blackjackLoop()",str(channel.id))
await blackjackLoop(channel,gameRound+1,gameID)
else:
try:
new_message = blackjackFinish(str(channel.id))
except:
logThis("Something fucked up (error code 1310)")
await channel.send(new_message)
else:
logThis("Ending loop on round "+str(gameRound),str(channel.id))
else:
logThis("Ending loop on round "+str(gameRound),str(channel.id))
async def parseBlackjack(content, ctx):
# Blackjack shuffle variables
blackjackMinCards = 50
blackjackDecks = 4
channel = ctx.message.channel.id
# Starts the game
if content == "":
cardsLeft = 0
if os.path.exists("resources/games/blackjackCards/"+str(channel)+".txt"):
with open("resources/games/blackjackCards/"+str(channel)+".txt","r") as f:
for _ in f:
cardsLeft += 1
# Shuffles if not enough cards
if cardsLeft < blackjackMinCards:
blackjackShuffle(blackjackDecks,str(channel))
logThis("Shuffling the blackjack deck...",str(channel))
await ctx.send("Shuffling the deck...")
new_message = blackjackStart(str(channel))
if new_message == "started":
new_message = "Blackjack game started. Use \"!blackjack bet [amount]\" to enter the game within the next 30 seconds."
await ctx.send(new_message)
oldImage = await ctx.send(file = discord.File("resources/games/blackjackTables/blackjackTable"+str(channel)+".png"))
with open("resources/games/oldImages/blackjack"+str(channel), "w") as f:
f.write(str(oldImage.id))
await asyncio.sleep(30)
gamedone = False
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if len(data["blackjack games"][str(channel)]["user hands"]) == 0:
gamedone = True
await ctx.send("No one entered the game. Ending the game.")
gameID = data["blackjack games"][str(channel)]["id"]
# Loop of game rounds
if gamedone == False:
logThis("!blackjack calling blackjackLoop()",str(channel))
await blackjackLoop(ctx.message.channel,1,gameID)
else:
new_message = blackjackFinish(str(channel))
await ctx.send(new_message)
else:
await ctx.send(new_message)
# Entering game and placing bet
elif content.startswith("bet"):
commands = content.split(" ")
amount = int(commands[1])
response = blackjackPlayerDrawHand(str(channel),"#"+str(ctx.message.author.id),amount)
await ctx.send(response)
# Hitting
elif content.startswith("hit"):
if content == "hit":
response = blackjackHit(str(channel),"#"+str(ctx.message.author.id))
else:
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response = blackjackHit(str(channel),"#"+str(ctx.message.author.id),handNumber)
if response.startswith("accept"):
await ctx.message.add_reaction("👍")
try:
if response[6] == "T":
with open("resources/games/games.json", "r") as f:
gameID = json.load(f)["blackjack games"][str(channel)]["id"]
logThis("Hit calling blackjackLoop()",str(channel))
await blackjackLoop(ctx.message.channel,int(response[7:])+1,gameID)
except:
logThis("Something fucked up (error code 1320)",str(channel))
else:
await ctx.send(response)
# Standing
elif content.startswith("stand"):
if content == "hit":
response = blackjackStand(str(channel),"#"+str(ctx.message.author.id))
else:
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response = blackjackStand(str(channel),"#"+str(ctx.message.author.id),handNumber)
if response.startswith("accept"):
await ctx.message.add_reaction("👍")
try:
if response[6] == "T":
with open("resources/games/games.json", "r") as f:
gameID = json.load(f)["blackjack games"][str(channel)]["id"]
logThis("Stand calling blackjackLoop()",str(channel))
await blackjackLoop(ctx.message.channel,int(response[7:])+1,gameID)
except:
logThis("Something fucked up (error code 1320)",str(channel))
else:
await ctx.send(response)
# Doubling bet
elif content.startswith("double"):
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response, roundDone = blackjackDouble(str(channel),"#"+str(ctx.message.author.id),handNumber)
await ctx.send(response)
try:
if roundDone[0] == "T":
with open("resources/games/games.json", "r") as f:
gameID = json.load(f)["blackjack games"][str(channel)]["id"]
logThis("Double calling blackjackLoop()",str(channel))
await blackjackLoop(ctx.message.channel,int(roundDone[1:])+1,gameID)
except:
logThis("Something fucked up (error code 1320)",str(channel))
# Splitting hand
elif content.startswith("split"):
commands = content.split(" ")
try:
handNumber = int(commands[1])
except:
handNumber = 0
response, roundDone = blackjackSplit(str(channel),"#"+str(ctx.message.author.id),handNumber)
await ctx.send(response)
try:
if roundDone[0] == "T":
with open("resources/games/games.json", "r") as f:
gameID = json.load(f)["blackjack games"][str(channel)]["id"]
logThis("Split calling blackjackLoop()",str(channel))
await blackjackLoop(ctx.message.channel,int(roundDone[1:])+1,gameID)
except:
logThis("Something fucked up (error code 1320)")
# Returning current hi-lo value
elif content.startswith("hilo") and "#"+str(ctx.message.author.id) == "#266269899859427329":
if os.path.exists("resources/games/blackjackCards/"+str(channel)+".txt"):
with open("resources/games/hilo/"+str(channel)+".txt", "r") as f:
data = f.read()
else:
data = "0"
await ctx.send(data)
# Shuffles the blackjack deck
elif content.startswith("shuffle"):
blackjackShuffle(blackjackDecks,str(channel))
logThis("Shuffling the blackjack deck...",str(channel))
await ctx.send("Shuffling the deck...")
# Tells you the amount of cards left
elif content.startswith("cards"):
cardsLeft = 0
if os.path.exists("resources/games/blackjackCards/"+str(channel)+".txt"):
with open("resources/games/blackjackCards/"+str(channel)+".txt","r") as f:
for _ in f:
cardsLeft += 1
decksLeft = round(cardsLeft/52,1)
await ctx.send(str(cardsLeft)+" cards, "+str(decksLeft)+" decks")
else:
logThis("Not a command (error code 1301)")
await ctx.send("I didn't quite understand that (error code 1301)")

View File

@ -1,11 +1,10 @@
import json
import random
import copy
import math
import asyncio
from . import fourInARowDraw
from funcs import logThis, getName, getID
from .fourInARowDraw import DrawFourInARow
from funcs import logThis
AIScores = {
"middle": 3,
@ -22,328 +21,322 @@ rowCount = 6
columnCount = 7
easy = True
# Starts the game
def fourInARowStart(channel, user, opponent):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
class FourInARow():
def __init__(self,bot):
self.bot = bot
self.draw = DrawFourInARow(bot)
if channel not in data["4 in a row games"]:
# Starts the game
def fourInARowStart(self, channel, user, opponent):
game = self.bot.database["4 in a row games"].find_one({"_id":channel})
if opponent in ["1","2","3","4","5"]:
difficulty = int(opponent)
diffText = " with difficulty "+opponent
opponent = "Gwendolyn"
elif opponent.lower() == "gwendolyn":
difficulty = 3
diffText = " with difficulty 3"
opponent = "Gwendolyn"
else:
try:
int(opponent)
return "That difficulty doesn't exist", False, False, False, False
except:
# Opponent is another player
opponent = getID(opponent)
if opponent != None:
difficulty = 5
diffText = ""
else:
return "I can't find that user", False, False, False, False
if user == opponent:
return "You can't play against yourself", False, False, False, False
if game == None:
board = [ [ 0 for i in range(columnCount) ] for j in range(rowCount) ]
players = [user,opponent]
random.shuffle(players)
data["4 in a row games"][channel] = {"board": board,"winner":0,"win direction":"",
"win coordinates":[0,0],"players":players,"turn":0,"difficulty":difficulty}
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
fourInARowDraw.drawImage(channel)
gwendoTurn = False
if players[0] == "Gwendolyn":
gwendoTurn = True
return "Started game against "+getName(opponent)+diffText+". It's "+getName(players[0])+"'s turn", True, False, False, gwendoTurn
else:
return "There's already a 4 in a row game going on in this channel", False, False, False, False
# Places a piece at the lowest available point in a specific column
def placePiece(channel : str,player : int,column : int):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if channel in data["4 in a row games"]:
board = data["4 in a row games"][channel]["board"]
board = placeOnBoard(board,player,column)
if board != None:
data["4 in a row games"][channel]["board"] = board
turn = (data["4 in a row games"][channel]["turn"]+1)%2
data["4 in a row games"][channel]["turn"] = turn
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
logThis("Checking for win")
won, winDirection, winCoordinates = isWon(data["4 in a row games"][channel]["board"])
if won != 0:
gameWon = True
data["4 in a row games"][channel]["winner"] = won
data["4 in a row games"][channel]["win direction"] = winDirection
data["4 in a row games"][channel]["win coordinates"] = winCoordinates
message = getName(data["4 in a row games"][channel]["players"][won-1])+" placed a piece in column "+str(column+1)+" and won."
winAmount = int(data["4 in a row games"][channel]["difficulty"])**2+5
if data["4 in a row games"][channel]["players"][won-1] != "Gwendolyn":
message += " Adding "+str(winAmount)+" GwendoBucks to their account."
elif 0 not in board[0]:
gameWon = True
message = "It's a draw!"
if opponent in ["1","2","3","4","5"]:
difficulty = int(opponent)
diffText = " with difficulty "+opponent
opponent = "Gwendolyn"
elif opponent.lower() == "gwendolyn":
difficulty = 3
diffText = " with difficulty 3"
opponent = "Gwendolyn"
else:
gameWon = False
message = getName(data["4 in a row games"][channel]["players"][player-1])+" placed a piece in column "+str(column+1)+". It's now "+getName(data["4 in a row games"][channel]["players"][turn])+"'s turn."
try:
int(opponent)
return "That difficulty doesn't exist", False, False, False, False
except:
# Opponent is another player
opponent = self.bot.funcs.getID(opponent)
if opponent != None:
difficulty = 5
diffText = ""
else:
return "I can't find that user", False, False, False, False
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
if user == opponent:
return "You can't play against yourself", False, False, False, False
board = [ [ 0 for i in range(columnCount) ] for j in range(rowCount) ]
players = [user,opponent]
random.shuffle(players)
newGame = {"_id":channel,"board": board,"winner":0,"win direction":"",
"win coordinates":[0,0],"players":players,"turn":0,"difficulty":difficulty}
self.bot.database["4 in a row games"].insert_one(newGame)
self.draw.drawImage(channel)
gwendoTurn = False
if data["4 in a row games"][channel]["players"][turn] == "Gwendolyn":
logThis("It's Gwendolyn's turn")
if players[0] == "Gwendolyn":
gwendoTurn = True
fourInARowDraw.drawImage(channel)
return message, True, True, gameWon, gwendoTurn
return "Started game against "+self.bot.funcs.getName(opponent)+diffText+". It's "+self.bot.funcs.getName(players[0])+"'s turn", True, False, False, gwendoTurn
else:
return "There isn't any room in that column", True, True, False, False
else:
return "There's no game in this channel", False, False, False, False
return "There's already a 4 in a row game going on in this channel", False, False, False, False
# Returns a board where a piece has been placed in the column
def placeOnBoard(board,player,column):
placementx, placementy = -1, column
# Places a piece at the lowest available point in a specific column
def placePiece(self, channel : str,player : int,column : int):
game = self.bot.database["4 in a row games"].find_one({"_id":channel})
for x in range(len(board)):
if board[x][column] == 0:
placementx = x
if game != None:
board = game["board"]
board[placementx][placementy] = player
board = self.placeOnBoard(board,player,column)
if placementx == -1:
return None
else:
return board
if board != None:
self.bot.database["4 in a row games"].update_one({"_id":channel},{"$set":{"board":board}})
turn = (game["turn"]+1)%2
self.bot.database["4 in a row games"].update_one({"_id":channel},{"$set":{"turn":turn}})
# Parses command
def parseFourInARow(command, channel, user):
commands = command.split()
if command == "" or command == " ":
return "I didn't get that. Use \"!fourinarow start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False
elif commands[0] == "start":
# Starting a game
if len(commands) == 1: # if the commands is "!fourinarow start", the opponent is Gwendolyn
commands.append("3")
return fourInARowStart(channel,user,commands[1]) # commands[1] is the opponent
logThis("Checking for win")
won, winDirection, winCoordinates = self.isWon(board)
# Stopping the game
elif commands[0] == "stop":
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if won != 0:
gameWon = True
self.bot.database["4 in a row games"].update_one({"_id":channel},{"$set":{"winner":won}})
self.bot.database["4 in a row games"].update_one({"_id":channel},{"$set":{"win direction":winDirection}})
self.bot.database["4 in a row games"].update_one({"_id":channel},
{"$set":{"win coordinates":winCoordinates}})
if user in data["4 in a row games"][channel]["players"]:
return "Ending game.", False, False, True, False
message = self.bot.funcs.getName(game["players"][won-1])+" placed a piece in column "+str(column+1)+" and won."
winAmount = int(game["difficulty"])**2+5
if game["players"][won-1] != "Gwendolyn":
message += " Adding "+str(winAmount)+" GwendoBucks to their account."
elif 0 not in board[0]:
gameWon = True
message = "It's a draw!"
else:
gameWon = False
message = self.bot.funcs.getName(game["players"][player-1])+" placed a piece in column "+str(column+1)+". It's now "+self.bot.funcs.getName(game["players"][turn])+"'s turn."
gwendoTurn = False
if game["players"][turn] == "Gwendolyn":
logThis("It's Gwendolyn's turn")
gwendoTurn = True
self.draw.drawImage(channel)
return message, True, True, gameWon, gwendoTurn
else:
return "There isn't any room in that column", True, True, False, False
else:
return "You can't end a game where you're not a player.", False, False, False, False
return "There's no game in this channel", False, False, False, False
# Placing manually
elif commands[0] == "place":
try:
return placePiece(channel,int(commands[1]),int(commands[2])-1)
except:
return "I didn't get that. To place a piece use \"!fourinarow place [player number] [column]\" or press the corresponding message-reaction beneath the board.", False, False, False, False
else:
return "I didn't get that. Use \"!fourinarow start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False
# Returns a board where a piece has been placed in the column
def placeOnBoard(self,board,player,column):
placementx, placementy = -1, column
# Checks if someone has won the game and returns the winner
def isWon(board):
won = 0
winDirection = ""
winCoordinates = [0,0]
for x in range(len(board)):
if board[x][column] == 0:
placementx = x
for row in range(len(board)):
for place in range(len(board[row])):
if won == 0:
piecePlayer = board[row][place]
if piecePlayer != 0:
# Checks horizontal
if place <= columnCount-4:
pieces = [board[row][place+1],board[row][place+2],board[row][place+3]]
else:
pieces = [0]
board[placementx][placementy] = player
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "h"
winCoordinates = [row,place]
if placementx == -1:
return None
else:
return board
# Checks vertical
if row <= rowCount-4:
pieces = [board[row+1][place],board[row+2][place],board[row+3][place]]
else:
pieces = [0]
# Parses command
def parseFourInARow(self, command, channel, user):
commands = command.split()
if command == "" or command == " ":
return "I didn't get that. Use \"!fourinarow start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False
elif commands[0] == "start":
# Starting a game
if len(commands) == 1: # if the commands is "!fourinarow start", the opponent is Gwendolyn
commands.append("3")
return self.fourInARowStart(channel,user,commands[1]) # commands[1] is the opponent
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "v"
winCoordinates = [row,place]
# Stopping the game
elif commands[0] == "stop":
game = self.bot.database["4 in a row games"].find_one({"_id":channel})
# Checks right diagonal
if row <= rowCount-4 and place <= columnCount-4:
pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
else:
pieces = [0]
if user in game["players"]:
return "Ending game.", False, False, True, False
else:
return "You can't end a game where you're not a player.", False, False, False, False
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "r"
winCoordinates = [row,place]
# Placing manually
elif commands[0] == "place":
try:
return self.placePiece(channel,int(commands[1]),int(commands[2])-1)
except:
return "I didn't get that. To place a piece use \"!fourinarow place [player number] [column]\" or press the corresponding message-reaction beneath the board.", False, False, False, False
else:
return "I didn't get that. Use \"!fourinarow start [opponent]\" to start a game. To play against the computer, use difficulty 1 through 5 as the [opponent].", False, False, False, False
# Checks left diagonal
if row <= rowCount-4 and place >= 3:
pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
else:
pieces = [0]
# Checks if someone has won the game and returns the winner
def isWon(self, board):
won = 0
winDirection = ""
winCoordinates = [0,0]
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "l"
winCoordinates = [row,place]
for row in range(len(board)):
for place in range(len(board[row])):
if won == 0:
piecePlayer = board[row][place]
if piecePlayer != 0:
# Checks horizontal
if place <= columnCount-4:
pieces = [board[row][place+1],board[row][place+2],board[row][place+3]]
else:
pieces = [0]
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "h"
winCoordinates = [row,place]
# Checks vertical
if row <= rowCount-4:
pieces = [board[row+1][place],board[row+2][place],board[row+3][place]]
else:
pieces = [0]
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "v"
winCoordinates = [row,place]
# Checks right diagonal
if row <= rowCount-4 and place <= columnCount-4:
pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
else:
pieces = [0]
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "r"
winCoordinates = [row,place]
# Checks left diagonal
if row <= rowCount-4 and place >= 3:
pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
else:
pieces = [0]
if all(x == piecePlayer for x in pieces):
won = piecePlayer
winDirection = "l"
winCoordinates = [row,place]
return won, winDirection, winCoordinates
return won, winDirection, winCoordinates
# Plays as the AI
async def fourInARowAI(channel):
logThis("Figuring out best move")
with open("resources/games/games.json", "r") as f:
data = json.load(f)
# Plays as the AI
async def fourInARowAI(self, channel):
logThis("Figuring out best move")
game = self.bot.database["4 in a row games"].find_one({"_id":channel})
board = data["4 in a row games"][channel]["board"]
player = data["4 in a row games"][channel]["players"].index("Gwendolyn")+1
difficulty = data["4 in a row games"][channel]["difficulty"]
board = game["board"]
player = game["players"].index("Gwendolyn")+1
difficulty = game["difficulty"]
scores = [-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf]
for column in range(0,columnCount):
testBoard = copy.deepcopy(board)
testBoard = placeOnBoard(testBoard,player,column)
if testBoard != None:
scores[column] = await minimax(testBoard,difficulty,player%2+1,player,-math.inf,math.inf,False)
logThis("Best score for column "+str(column)+" is "+str(scores[column]))
possibleScores = scores.copy()
while (min(possibleScores) <= (max(possibleScores) - max(possibleScores)/10)) and len(possibleScores) != 1:
possibleScores.remove(min(possibleScores))
highest_score = random.choice(possibleScores)
indices = [i for i, x in enumerate(scores) if x == highest_score]
placement = random.choice(indices)
return placePiece(channel,player,placement)
# Calculates points for a board
def AICalcPoints(board,player):
score = 0
otherPlayer = player%2+1
# Adds points for middle placement
# Checks horizontal
for row in range(rowCount):
if board[row][3] == player:
score += AIScores["middle"]
rowArray = [int(i) for i in list(board[row])]
for place in range(columnCount-3):
window = rowArray[place:place+4]
score += evaluateWindow(window,player,otherPlayer)
# Checks Vertical
for column in range(columnCount):
columnArray = [int(i[column]) for i in list(board)]
for place in range(rowCount-3):
window = columnArray[place:place+4]
score += evaluateWindow(window,player,otherPlayer)
# Checks right diagonal
for row in range(rowCount-3):
for place in range(columnCount-3):
window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
score += evaluateWindow(window,player,otherPlayer)
for place in range(3,columnCount):
window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
score += evaluateWindow(window,player,otherPlayer)
## Checks if anyone has won
#won = isWon(board)[0]
## Add points if AI wins
#if won == player:
# score += AIScores["win"]
return score
def evaluateWindow(window,player,otherPlayer):
if window.count(player) == 4:
return AIScores["win"]
elif window.count(player) == 3 and window.count(0) == 1:
return AIScores["three in a row"]
elif window.count(player) == 2 and window.count(0) == 2:
return AIScores["two in a row"]
elif window.count(otherPlayer) == 4:
return AIScores["enemy win"]
else:
return 0
async def minimax(board, depth, player , originalPlayer, alpha, beta, maximizingPlayer):
#terminal = ((0 not in board[0]) or (isWon(board)[0] != 0))
terminal = 0 not in board[0]
points = AICalcPoints(board,originalPlayer)
# The depth is how many moves ahead the computer checks. This value is the difficulty.
if depth == 0 or terminal or (points > 5000 or points < -6000):
return points
if maximizingPlayer:
value = -math.inf
scores = [-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf,-math.inf]
for column in range(0,columnCount):
testBoard = copy.deepcopy(board)
testBoard = placeOnBoard(testBoard,player,column)
testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None:
evaluation = await minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False)
if evaluation < -9000: evaluation += AIScores["avoid losing"]
value = max(value,evaluation)
alpha = max(alpha,evaluation)
if beta <= alpha: break
return value
else:
value = math.inf
for column in range(0,columnCount):
testBoard = copy.deepcopy(board)
testBoard = placeOnBoard(testBoard,player,column)
if testBoard != None:
evaluation = await minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True)
if evaluation < -9000: evaluation += AIScores["avoid losing"]
value = min(value,evaluation)
beta = min(beta,evaluation)
if beta <= alpha: break
return value
scores[column] = await self.minimax(testBoard,difficulty,player%2+1,player,-math.inf,math.inf,False)
logThis("Best score for column "+str(column)+" is "+str(scores[column]))
possibleScores = scores.copy()
while (min(possibleScores) <= (max(possibleScores) - max(possibleScores)/10)) and len(possibleScores) != 1:
possibleScores.remove(min(possibleScores))
highest_score = random.choice(possibleScores)
indices = [i for i, x in enumerate(scores) if x == highest_score]
placement = random.choice(indices)
return self.placePiece(channel,player,placement)
# Calculates points for a board
def AICalcPoints(self,board,player):
score = 0
otherPlayer = player%2+1
# Adds points for middle placement
# Checks horizontal
for row in range(rowCount):
if board[row][3] == player:
score += AIScores["middle"]
rowArray = [int(i) for i in list(board[row])]
for place in range(columnCount-3):
window = rowArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer)
# Checks Vertical
for column in range(columnCount):
columnArray = [int(i[column]) for i in list(board)]
for place in range(rowCount-3):
window = columnArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer)
# Checks right diagonal
for row in range(rowCount-3):
for place in range(columnCount-3):
window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
score += self.evaluateWindow(window,player,otherPlayer)
for place in range(3,columnCount):
window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
score += self.evaluateWindow(window,player,otherPlayer)
## Checks if anyone has won
#won = isWon(board)[0]
## Add points if AI wins
#if won == player:
# score += AIScores["win"]
return score
def evaluateWindow(self, window,player,otherPlayer):
if window.count(player) == 4:
return AIScores["win"]
elif window.count(player) == 3 and window.count(0) == 1:
return AIScores["three in a row"]
elif window.count(player) == 2 and window.count(0) == 2:
return AIScores["two in a row"]
elif window.count(otherPlayer) == 4:
return AIScores["enemy win"]
else:
return 0
async def minimax(self, board, depth, player , originalPlayer, alpha, beta, maximizingPlayer):
#terminal = ((0 not in board[0]) or (isWon(board)[0] != 0))
terminal = 0 not in board[0]
points = self.AICalcPoints(board,originalPlayer)
# The depth is how many moves ahead the computer checks. This value is the difficulty.
if depth == 0 or terminal or (points > 5000 or points < -6000):
return points
if maximizingPlayer:
value = -math.inf
for column in range(0,columnCount):
testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False)
if evaluation < -9000: evaluation += AIScores["avoid losing"]
value = max(value,evaluation)
alpha = max(alpha,evaluation)
if beta <= alpha: break
return value
else:
value = math.inf
for column in range(0,columnCount):
testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True)
if evaluation < -9000: evaluation += AIScores["avoid losing"]
value = min(value,evaluation)
beta = min(beta,evaluation)
if beta <= alpha: break
return value

View File

@ -1,154 +1,156 @@
import json
import math
from PIL import Image, ImageDraw, ImageFont
from funcs import logThis, getName
from funcs import logThis
# Draws the whole thing
def drawImage(channel):
logThis("Drawing four in a row board")
with open("resources/games/games.json", "r") as f:
data = json.load(f)
class DrawFourInARow():
def __init__(self,bot):
self.bot = bot
board = data["4 in a row games"][channel]["board"]
# Draws the whole thing
def drawImage(self, channel):
logThis("Drawing four in a row board")
game = self.bot.database["4 in a row games"].find_one({"_id":channel})
border = 40
gridBorder = 40
cornerSize = 300
boardOutlineSize = 10
pieceOutlineSize = 10
emptyOutlineSize = 0
bottomBorder = 110
exampleCircles = 100
w, h = 2800,2400
backgroundColor = (230,230,234,255)
boardOutlineColor = (0,0,0)
pieceOutlineColor = (244,244,248)
emptyOutlineColor = (0,0,0)
player1Color = (254,74,73)
player2Color = (254,215,102)
boardColor = (42,183,202)
placeSize = 300
white = (255,255,255,160)
winBarColor = (250,250,250,255)
board = game["board"]
fnt = ImageFont.truetype('resources/futura-bold.ttf', exampleCircles)
border = 40
gridBorder = 40
cornerSize = 300
boardOutlineSize = 10
pieceOutlineSize = 10
emptyOutlineSize = 0
bottomBorder = 110
exampleCircles = 100
w, h = 2800,2400
backgroundColor = (230,230,234,255)
boardOutlineColor = (0,0,0)
pieceOutlineColor = (244,244,248)
emptyOutlineColor = (0,0,0)
player1Color = (254,74,73)
player2Color = (254,215,102)
boardColor = (42,183,202)
placeSize = 300
white = (255,255,255,160)
winBarColor = (250,250,250,255)
boardSize = [w-(2*(border+gridBorder)),h-(2*(border+gridBorder))]
placeGridSize = [math.floor(boardSize[0]/7),math.floor(boardSize[1]/6)]
pieceStartx = (border+gridBorder)+math.floor(placeGridSize[0]/2)-math.floor(placeSize/2)
pieceStarty = (border+gridBorder)+math.floor(placeGridSize[1]/2)-math.floor(placeSize/2)
fnt = ImageFont.truetype('resources/futura-bold.ttf', exampleCircles)
if data["4 in a row games"][channel]["players"][0] == "Gwendolyn":
player1 = "Gwendolyn"
else:
player1 = getName(data["4 in a row games"][channel]["players"][0])
boardSize = [w-(2*(border+gridBorder)),h-(2*(border+gridBorder))]
placeGridSize = [math.floor(boardSize[0]/7),math.floor(boardSize[1]/6)]
pieceStartx = (border+gridBorder)+math.floor(placeGridSize[0]/2)-math.floor(placeSize/2)
pieceStarty = (border+gridBorder)+math.floor(placeGridSize[1]/2)-math.floor(placeSize/2)
if data["4 in a row games"][channel]["players"][1] == "Gwendolyn":
player2 = "Gwendolyn"
else:
player2 = getName(data["4 in a row games"][channel]["players"][1])
if game["players"][0] == "Gwendolyn":
player1 = "Gwendolyn"
else:
player1 = self.bot.funcs.getName(game["players"][0])
if game["players"][1] == "Gwendolyn":
player2 = "Gwendolyn"
else:
player2 = self.bot.funcs.getName(game["players"][1])
background = Image.new("RGB", (w,h+bottomBorder),backgroundColor)
d = ImageDraw.Draw(background,"RGBA")
background = Image.new("RGB", (w,h+bottomBorder),backgroundColor)
d = ImageDraw.Draw(background,"RGBA")
# This whole part was the easiest way to make a rectangle with rounded corners and an outline
# - Corners:
d.ellipse([(border,border),(border+cornerSize,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Rectangle:
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Removing outline on the inside:
d.rectangle([(border+math.floor(cornerSize/2),border+math.floor(cornerSize/2)),(w-(border+math.floor(cornerSize/2)),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
d.rectangle([(border+math.floor(cornerSize/2),border+boardOutlineSize),(w-(border+math.floor(cornerSize/2)),h-(border+boardOutlineSize))],fill=boardColor)
d.rectangle([(border+boardOutlineSize,border+math.floor(cornerSize/2)),(w-(border+boardOutlineSize),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
# This whole part was the easiest way to make a rectangle with rounded corners and an outline
# - Corners:
d.ellipse([(border,border),(border+cornerSize,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Rectangle:
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Removing outline on the inside:
d.rectangle([(border+math.floor(cornerSize/2),border+math.floor(cornerSize/2)),(w-(border+math.floor(cornerSize/2)),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
d.rectangle([(border+math.floor(cornerSize/2),border+boardOutlineSize),(w-(border+math.floor(cornerSize/2)),h-(border+boardOutlineSize))],fill=boardColor)
d.rectangle([(border+boardOutlineSize,border+math.floor(cornerSize/2)),(w-(border+boardOutlineSize),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
for x, line in enumerate(board):
for y, piece in enumerate(line):
for x, line in enumerate(board):
for y, piece in enumerate(line):
if piece == 1:
pieceColor = player1Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
elif piece == 2:
pieceColor = player2Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
else:
pieceColor = backgroundColor
outlineWidth = emptyOutlineSize
outlineColor = emptyOutlineColor
if piece == 1:
pieceColor = player1Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
elif piece == 2:
pieceColor = player2Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
else:
pieceColor = backgroundColor
outlineWidth = emptyOutlineSize
outlineColor = emptyOutlineColor
startx = pieceStartx + placeGridSize[0]*y
starty = pieceStarty + placeGridSize[1]*x
startx = pieceStartx + placeGridSize[0]*y
starty = pieceStarty + placeGridSize[1]*x
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=outlineColor,width=outlineWidth)
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=outlineColor,width=outlineWidth)
if data["4 in a row games"][channel]["winner"] != 0:
coordinates = data["4 in a row games"][channel]["win coordinates"]
startx = border + placeGridSize[0]*coordinates[1] + gridBorder
starty = border + placeGridSize[1]*coordinates[0] + gridBorder
a = (placeGridSize[0]*4-gridBorder-border)**2
b = (placeGridSize[1]*4-gridBorder-border)**2
diagonalLength = (math.sqrt(a+b))/placeGridSize[0]
diagonalAngle = math.degrees(math.atan(placeGridSize[1]/placeGridSize[0]))
if game["winner"] != 0:
coordinates = game["win coordinates"]
startx = border + placeGridSize[0]*coordinates[1] + gridBorder
starty = border + placeGridSize[1]*coordinates[0] + gridBorder
a = (placeGridSize[0]*4-gridBorder-border)**2
b = (placeGridSize[1]*4-gridBorder-border)**2
diagonalLength = (math.sqrt(a+b))/placeGridSize[0]
diagonalAngle = math.degrees(math.atan(placeGridSize[1]/placeGridSize[0]))
if data["4 in a row games"][channel]["win direction"] == "h":
winBar = Image.new("RGBA",(placeGridSize[0]*4,placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*3),0),(placeGridSize[0]*4,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*3.5),placeGridSize[1])],fill=white)
if game["win direction"] == "h":
winBar = Image.new("RGBA",(placeGridSize[0]*4,placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*3),0),(placeGridSize[0]*4,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*3.5),placeGridSize[1])],fill=white)
elif data["4 in a row games"][channel]["win direction"] == "v":
winBar = Image.new("RGBA",(placeGridSize[0],placeGridSize[1]*4),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([(0,(placeGridSize[1]*3)),(placeGridSize[0],placeGridSize[1]*4)],fill=white)
winD.rectangle([0,(int(placeGridSize[1]*0.5)),(placeGridSize[0],int(placeGridSize[1]*3.5))],fill=white)
elif game["win direction"] == "v":
winBar = Image.new("RGBA",(placeGridSize[0],placeGridSize[1]*4),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([(0,(placeGridSize[1]*3)),(placeGridSize[0],placeGridSize[1]*4)],fill=white)
winD.rectangle([0,(int(placeGridSize[1]*0.5)),(placeGridSize[0],int(placeGridSize[1]*3.5))],fill=white)
elif data["4 in a row games"][channel]["win direction"] == "r":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(-diagonalAngle,expand=1)
startx -= 90
starty -= 100
elif game["win direction"] == "r":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(-diagonalAngle,expand=1)
startx -= 90
starty -= 100
elif data["4 in a row games"][channel]["win direction"] == "l":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(diagonalAngle,expand=1)
startx -= placeGridSize[0]*3 + 90
starty -= gridBorder + 60
elif game["win direction"] == "l":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(diagonalAngle,expand=1)
startx -= placeGridSize[0]*3 + 90
starty -= gridBorder + 60
mask = winBar.copy()#.convert("L")
#mask.putalpha(128)
#mask.save("test.png")
mask = winBar.copy()#.convert("L")
#mask.putalpha(128)
#mask.save("test.png")
winBarImage = Image.new("RGBA",mask.size,color=winBarColor)
background.paste(winBarImage,(startx,starty),mask)
winBarImage = Image.new("RGBA",mask.size,color=winBarColor)
background.paste(winBarImage,(startx,starty),mask)
# Bottom
textPadding = 20
# Bottom
textPadding = 20
exampleHeight = h - border + int((bottomBorder+border)/2) - int(exampleCircles/2)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=player1Color,outline=boardOutlineColor,width=3)
d.text((border+exampleCircles+textPadding,exampleHeight),player1,font=fnt,fill=(0,0,0))
exampleHeight = h - border + int((bottomBorder+border)/2) - int(exampleCircles/2)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=player1Color,outline=boardOutlineColor,width=3)
d.text((border+exampleCircles+textPadding,exampleHeight),player1,font=fnt,fill=(0,0,0))
textWidth = fnt.getsize(player2)[0]
d.ellipse([(w-border-exampleCircles-textWidth-textPadding,exampleHeight),(w-border-textWidth-textPadding),(exampleHeight+exampleCircles)],fill=player2Color,outline=boardOutlineColor,width=3)
d.text((w-border-textWidth,exampleHeight),player2,font=fnt,fill=(0,0,0))
textWidth = fnt.getsize(player2)[0]
d.ellipse([(w-border-exampleCircles-textWidth-textPadding,exampleHeight),(w-border-textWidth-textPadding),(exampleHeight+exampleCircles)],fill=player2Color,outline=boardOutlineColor,width=3)
d.text((w-border-textWidth,exampleHeight),player2,font=fnt,fill=(0,0,0))
background.save("resources/games/4InARowBoards/board"+channel+".png")
background.save("resources/games/4InARowBoards/board"+channel+".png")

View File

@ -1,223 +1,213 @@
import asyncio
import discord
import json
from funcs import logThis, deleteGame
from .money import addMoney
from .fourInARow import parseFourInARow, fourInARowAI
from .hex import parseHex, hexAI
from .monopoly import parseMonopoly, monopolyContinue
from .hangman import parseHangman
from funcs import logThis
# Deletes a message
async def deleteMessage(imageLocation,channel):
try:
with open("resources/games/oldImages/"+imageLocation, "r") as f:
messages = f.read().splitlines()
for message in messages:
oldMessage = await channel.fetch_message(int(message))
logThis("Deleting old message")
await oldMessage.delete()
except:
oldMessage = ""
return oldMessage
# Runs Hex
async def runHex(channel,command,user):
try:
response, showImage, deleteImage, gameDone, gwendoTurn = parseHex(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1510)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
try:
oldImage = await deleteMessage("hex"+str(channel.id),channel)
except:
logThis("Error deleting old image (error code 1501)")
oldImage = await channel.send(file = discord.File("resources/games/hexBoards/board"+str(channel.id)+".png"))
if not gameDone:
if gwendoTurn:
try:
response, showImage, deleteImage, gameDone, gwendoTurn = hexAI(str(channel.id))
except:
response, showImage, deleteImage, gameDone, gwendoTurn = "An AI error occured",False,False,False,False
logThis("AI error (error code 1520)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await channel.send(file = discord.File("resources/games/hexBoards/board"+str(channel.id)+".png"))
else:
with open("resources/games/oldImages/hex"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
if gameDone:
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
winner = data[str(channel.id)]["winner"]
if winner != 0 and data[channel]["players"][0] != data[channel]["players"][1]: # player1 != player2
winnings = data[str(channel.id)]["difficulty"]*10
addMoney(data[str(channel.id)]["players"][winner-1].lower(),winnings)
#deleteGame("hex games",str(channel.id))
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
del data[str(channel.id)]
with open("resources/games/hexGames.json", "w") as f:
json.dump(data,f,indent=4)
class GameLoops():
def __init__(self,bot):
self.bot = bot
# Runs Four in a Row
async def fiar(channel,command,user):
try:
response, showImage, deleteImage, gameDone, gwendoTurn = parseFourInARow(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1410)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
try:
oldImage = await deleteMessage("fourInARow"+str(channel.id),channel)
except:
logThis("Error deleting message (error code 1401)")
oldImage = await channel.send(file = discord.File("resources/games/4InARowBoards/board"+str(channel.id)+".png"))
if gameDone == False:
if gwendoTurn:
try:
response, showImage, deleteImage, gameDone, gwendoTurn = await fourInARowAI(str(channel.id))
except:
logThis("AI error (error code 1420)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await channel.send(file = discord.File("resources/games/4InARowBoards/board"+str(channel.id)+".png"))
if gameDone == False:
with open("resources/games/oldImages/fourInARow"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
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.id), "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
except:
logThis("Image deleted before I could react to all of them")
if gameDone:
with open("resources/games/games.json", "r") as f:
data = json.load(f)
# Deletes a message
async def deleteMessage(self, imageLocation,channel):
try:
with open("resources/games/oldImages/fourInARow"+str(channel.id), "r") as f:
oldImage = await channel.fetch_message(int(f.read()))
with open("resources/games/oldImages/"+imageLocation, "r") as f:
messages = f.read().splitlines()
await oldImage.delete()
for message in messages:
oldMessage = await channel.fetch_message(int(message))
logThis("Deleting old message")
await oldMessage.delete()
except:
logThis("The old image was already deleted")
oldMessage = ""
winner = data["4 in a row games"][str(channel.id)]["winner"]
difficulty = int(data["4 in a row games"][str(channel.id)]["difficulty"])
reward = difficulty**2 + 5
if winner != 0:
if data["4 in a row games"][str(channel.id)]["players"][winner-1].lower() != "gwendolyn":
addMoney(data["4 in a row games"][str(channel.id)]["players"][winner-1].lower(),reward)
with open("resources/games/games.json", "r") as f:
data = json.load(f) #why is this here?
return oldMessage
deleteGame("4 in a row games",str(channel.id))
# Runs Four in a Row
async def fiar(self, channel,command,user):
try:
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.fourInARow.parseFourInARow(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1410)")
async def runMonopoly(channel, command, user):
try:
response, showImage, deleteImage, gameStarted, gameContinue = parseMonopoly(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1610)")
if response != "":
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
try:
oldImage = await deleteMessage("monopoly"+str(channel.id),channel)
except:
logThis("Error deleting message (error code 1601)")
oldImage = await channel.send(file = discord.File("resources/games/monopolyBoards/monopolyBoard"+str(channel.id)+".png"))
with open("resources/games/oldImages/monopoly"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
if gameContinue:
if gameStarted:
await asyncio.sleep(60)
else:
await asyncio.sleep(3)
response, showImage, deleteImage, gameDone = monopolyContinue(str(channel.id))
em = discord.Embed(description=response,colour = 0x59f442)
await channel.send(embed=em)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
try:
oldImage = await deleteMessage("monopoly"+str(channel.id),channel)
oldImage = await self.deleteMessage("fourInARow"+str(channel.id),channel)
except:
logThis("Error deleting message (error code 1401)")
oldImage = await channel.send(file = discord.File("resources/games/4InARowBoards/board"+str(channel.id)+".png"))
if gameDone == False:
if gwendoTurn:
try:
response, showImage, deleteImage, gameDone, gwendoTurn = await self.bot.fourInARow.fourInARowAI(str(channel.id))
except:
logThis("AI error (error code 1420)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await channel.send(file = discord.File("resources/games/4InARowBoards/board"+str(channel.id)+".png"))
if gameDone == False:
with open("resources/games/oldImages/fourInARow"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
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.id), "w") as f:
f.write(str(oldImage.id))
try:
reactions = ["1","2","3","4","5","6","7"]
for reaction in reactions:
await oldImage.add_reaction(reaction)
except:
logThis("Image deleted before I could react to all of them")
if gameDone:
game = self.bot.database["4 in a row games"].find_one({"_id":str(channel.id)})
try:
with open("resources/games/oldImages/fourInARow"+str(channel.id), "r") as f:
oldImage = await channel.fetch_message(int(f.read()))
await oldImage.delete()
except:
logThis("The old image was already deleted")
winner = game["winner"]
difficulty = int(game["difficulty"])
reward = difficulty**2 + 5
if winner != 0:
if game["players"][winner-1].lower() != "gwendolyn":
self.bot.money.addMoney(game["players"][winner-1].lower(),reward)
self.bot.funcs.deleteGame("4 in a row games",str(channel.id))
async def runMonopoly(self,channel, command, user):
try:
response, showImage, deleteImage, gameStarted, gameContinue = self.bot.monopoly.parseMonopoly(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1610)")
if response != "":
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
try:
oldImage = await self.deleteMessage("monopoly"+str(channel.id),channel)
except:
logThis("Error deleting message (error code 1601)")
oldImage = await channel.send(file = discord.File("resources/games/monopolyBoards/monopolyBoard"+str(channel.id)+".png"))
with open("resources/games/oldImages/monopoly"+str(channel.id), "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")
async def runHangman(channel,user,apiKey = "",command = "start"):
try:
response, showImage, deleteImage, remainingLetters = parseHangman(str(channel.id),user,command,apiKey)
except:
logThis("Error parsing command (error code 1701)")
if response != "":
if gameContinue:
if gameStarted:
await asyncio.sleep(60)
else:
await asyncio.sleep(3)
response, showImage, deleteImage, gameDone = self.bot.monopoly.monopolyContinue(str(channel.id))
em = discord.Embed(description=response,colour = 0x59f442)
await channel.send(embed=em)
if deleteImage:
try:
oldImage = await self.deleteMessage("monopoly"+str(channel.id),channel)
except:
logThis("Error deleting message (error code 1601)")
if showImage:
oldImage = await channel.send(file = discord.File("resources/games/monopolyBoards/monopolyBoard"+str(channel.id)+".png"))
with open("resources/games/oldImages/monopoly"+str(channel.id), "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")
async def runHangman(self,channel,user,command = "start"):
try:
response, showImage, deleteImage, remainingLetters = self.bot.hangman.parseHangman(str(channel.id),user,command)
except:
logThis("Error parsing command (error code 1701)")
if response != "":
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await self.deleteMessage("hangman"+str(channel.id),channel)
oldImage = await channel.send(file = discord.File("resources/games/hangmanBoards/hangmanBoard"+str(channel.id)+".png"))
if len(remainingLetters) > 15:
otherMessage = await channel.send("_ _")
reactionMessages = {oldImage : remainingLetters[:15],otherMessage : remainingLetters[15:]}
else:
otherMessage = ""
reactionMessages = {oldImage : remainingLetters}
oldMessages = str(oldImage.id)
if otherMessage != "":
oldMessages += "\n"+str(otherMessage.id)
with open("resources/games/oldImages/hangman"+str(channel.id), "w") as f:
f.write(oldMessages)
try:
for message, letters in reactionMessages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
except:
logThis("Image deleted before adding all reactions")
# Runs Hex
async def runHex(self,channel,command,user):
try:
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.hex.parseHex(command,str(channel.id),user)
except:
logThis("Error parsing command (error code 1510)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await deleteMessage("hangman"+str(channel.id),channel)
oldImage = await channel.send(file = discord.File("resources/games/hangmanBoards/hangmanBoard"+str(channel.id)+".png"))
if showImage:
if deleteImage:
try:
oldImage = await self.deleteMessage("hex"+str(channel.id),channel)
except:
logThis("Error deleting old image (error code 1501)")
oldImage = await channel.send(file = discord.File("resources/games/hexBoards/board"+str(channel.id)+".png"))
if not gameDone:
if gwendoTurn:
try:
response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.hex.hexAI(str(channel.id))
except:
response, showImage, deleteImage, gameDone, gwendoTurn = "An AI error occured",False,False,False,False
logThis("AI error (error code 1520)")
await channel.send(response)
logThis(response,str(channel.id))
if showImage:
if deleteImage:
await oldImage.delete()
oldImage = await channel.send(file = discord.File("resources/games/hexBoards/board"+str(channel.id)+".png"))
if len(remainingLetters) > 15:
otherMessage = await channel.send("_ _")
reactionMessages = {oldImage : remainingLetters[:15],otherMessage : remainingLetters[15:]}
else:
otherMessage = ""
reactionMessages = {oldImage : remainingLetters}
else:
with open("resources/games/oldImages/hex"+str(channel.id), "w") as f:
f.write(str(oldImage.id))
oldMessages = str(oldImage.id)
if otherMessage != "":
oldMessages += "\n"+str(otherMessage.id)
with open("resources/games/oldImages/hangman"+str(channel.id), "w") as f:
f.write(oldMessages)
if gameDone:
game = self.bot.database["hexGames"].find_one({"_id":str(channel.id)})
print(game)
winner = game["winner"]
if winner != 0 and game["players"][0] != game["players"][1]: # player1 != player2
winnings = game["difficulty"]*10
self.bot.money.addMoney(game["players"][winner-1].lower(),winnings)
try:
for message, letters in reactionMessages.items():
for letter in letters:
emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji)
except:
logThis("Image deleted before adding all reactions")
self.bot.funcs.deleteGame("hex games",str(channel.id))

21
funcs/games/games.py Normal file
View File

@ -0,0 +1,21 @@
from .invest import Invest
from .trivia import Trivia
from .blackjack import Blackjack
from .fourInARow import FourInARow
from .gameLoops import GameLoops
from .monopoly import Monopoly
from .hangman import Hangman
from .hex import HexGame
class Games():
def __init__(self, bot):
self.bot = bot
bot.invest = Invest(bot)
bot.trivia = Trivia(bot)
bot.blackjack = Blackjack(bot)
bot.fourInARow = FourInARow(bot)
bot.gameLoops = GameLoops(bot)
bot.monopoly = Monopoly(bot)
bot.hangman = Hangman(bot)
bot.hex = HexGame(bot)

View File

@ -1,114 +1,110 @@
import json, urllib, datetime, string
from . import hangmanDraw, money
from funcs import getName, logThis
from .hangmanDraw import DrawHangman
from funcs import logThis
apiUrl = "https://api.wordnik.com/v4/words.json/randomWords?hasDictionaryDef=true&minCorpusCount=5000&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=3&maxLength=11&limit=1&api_key="
def hangmanStart(channel,user,apiKey):
with open("resources/games/hangmanGames.json", "r") as f:
data = json.load(f)
class Hangman():
def __init__(self,bot):
self.bot = bot
self.draw = DrawHangman(bot)
if channel not in data:
with urllib.request.urlopen(apiUrl+apiKey) as p:
word = list(json.load(p)[0]["word"].upper())
logThis("Found the word \""+"".join(word)+"\"")
guessed = [False] * len(word)
gameID = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
data[channel] = {"player" : user,"guessed letters" : [],"word" : word,"game ID" : gameID,"misses" : 0,"guessed" : guessed}
def hangmanStart(self,channel,user):
game = self.bot.database["hangman games"].find_one({"_id":channel})
remainingLetters = list(string.ascii_uppercase)
if game == None:
apiKey = self.bot.credentials.wordnikKey
with urllib.request.urlopen(apiUrl+apiKey) as p:
word = list(json.load(p)[0]["word"].upper())
logThis("Found the word \""+"".join(word)+"\"")
guessed = [False] * len(word)
gameID = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
newGame = {"_id":channel,"player" : user,"guessed letters" : [],"word" : word,"game ID" : gameID,"misses" : 0,"guessed" : guessed}
self.bot.database["hangman games"].insert_one(newGame)
with open("resources/games/hangmanGames.json", "w") as f:
json.dump(data,f)
remainingLetters = list(string.ascii_uppercase)
try:
hangmanDraw.drawImage(channel)
except:
logThis("Error drawing image (error code 1710)")
return f"{getName(user)} started game of hangman.", True, False, remainingLetters
else:
return "There's already a Hangman game going on in the channel", False, False, []
try:
self.draw.drawImage(channel)
except:
logThis("Error drawing image (error code 1710)")
return f"{self.bot.funcs.getName(user)} started game of hangman.", True, False, remainingLetters
else:
return "There's already a Hangman game going on in the channel", False, False, []
def hangmanStop(channel):
with open("resources/games/hangmanGames.json", "r") as f:
data = json.load(f)
def hangmanStop(self,channel):
self.bot.database["hangman games"].delete_one({"_id":channel})
del data[channel]
with open("resources/games/hangmanGames.json", "w") as f:
json.dump(data,f,indent=4)
return "Game stopped.", False, False, []
return "Game stopped.", False, False, []
def hangmanGuess(self,channel,user,guess):
game = self.bot.database["hangman games"].find_one({"_id":channel})
def hangmanGuess(channel,user,guess):
with open("resources/games/hangmanGames.json", "r") as f:
data = json.load(f)
if game != None:
if user == game["player"]:
if len(guess) == 1:
if guess not in game["guessed letters"]:
correctGuess = 0
if channel in data:
if user == data[channel]["player"]:
if len(guess) == 1:
if guess not in data[channel]["guessed letters"]:
correctGuess = 0
for x, letter in enumerate(game["word"]):
if guess == letter:
correctGuess += 1
self.bot.database["hangman games"].update_one({"_id":channel},{"$set":{"guessed."+str(x):True}})
for x, letter in enumerate(data[channel]["word"]):
if guess == letter:
correctGuess += 1
data[channel]["guessed"][x] = True
if correctGuess == 0:
self.bot.database["hangman games"].update_one({"_id":channel},{"$inc":{"misses":1}})
if correctGuess == 0:
data[channel]["misses"] += 1
self.bot.database["hangman games"].update_one({"_id":channel},{"$push":{"guessed letters":guess}})
data[channel]["guessed letters"].append(guess)
remainingLetters = list(string.ascii_uppercase)
remainingLetters = list(string.ascii_uppercase)
game = self.bot.database["hangman games"].find_one({"_id":channel})
for letter in data[channel]["guessed letters"]:
remainingLetters.remove(letter)
for letter in game["guessed letters"]:
remainingLetters.remove(letter)
if correctGuess == 1:
message = f"Guessed {guess}. There was 1 {guess} in the word."
if correctGuess == 1:
message = f"Guessed {guess}. There was 1 {guess} in the word."
else:
message = f"Guessed {guess}. There were {correctGuess} {guess}s in the word."
try:
self.draw.drawImage(channel)
except:
logThis("Error drawing image (error code 1710)")
if game["misses"] == 6:
self.hangmanStop(channel)
return message+" You've guessed wrong six times and have lost the game.", True, True, []
elif all(i == True for i in game["guessed"]):
self.hangmanStop(channel)
self.bot.money.addMoney(user,15)
return message+" You've guessed the word! Congratulations! Adding 15 GwendoBucks to your account", True, True, []
else:
return message, True, True, remainingLetters
else:
message = f"Guessed {guess}. There were {correctGuess} {guess}s in the word."
with open("resources/games/hangmanGames.json", "w") as f:
json.dump(data,f)
try:
hangmanDraw.drawImage(channel)
except:
logThis("Error drawing image (error code 1710)")
if data[channel]["misses"] == 6:
hangmanStop(channel)
return message+" You've guessed wrong six times and have lost the game.", True, True, []
elif all(i == True for i in data[channel]["guessed"]):
hangmanStop(channel)
money.addMoney(user,15)
return message+" You've guessed the word! Congratulations! Adding 15 GwendoBucks to your account", True, True, []
else:
return message, True, True, remainingLetters
return f"You've already guessed {guess}", False, False, []
else:
return f"You've already guessed {guess}", False, False, []
return "", False, False, []
else:
return "", False, False, []
else:
return "", False, False, []
else:
return "There's no Hangman game going on in this channel", False, False, []
return "There's no Hangman game going on in this channel", False, False, []
def parseHangman(channel,user,command,apiKey):
if command == "start":
try:
return hangmanStart(channel,user,apiKey)
except:
logThis("Error starting game (error code 1730)")
elif command == "stop":
return hangmanStop(channel)
elif command.startswith("guess "):
guess = command[6:].upper()
try:
return hangmanGuess(channel,user,guess)
except:
logThis("Error in guessing (Error Code 1720)")
else:
return "I didn't understand that", False, False, []
def parseHangman(self,channel,user,command):
if command == "start":
try:
return self.hangmanStart(channel,user)
except:
logThis("Error starting game (error code 1730)")
elif command == "stop":
return self.hangmanStop(channel)
elif command.startswith("guess "):
guess = command[6:].upper()
try:
return self.hangmanGuess(channel,user,guess)
except:
logThis("Error in guessing (Error Code 1720)")
else:
return "I didn't understand that", False, False, []

View File

@ -1,4 +1,4 @@
import math, random, json
import math, random
from PIL import ImageDraw, Image, ImageFont
from funcs import logThis
@ -28,222 +28,226 @@ smolfnt = ImageFont.truetype('resources/comic-sans-bold.ttf', textSize)
backgroundColor = (255,255,255,255)
def calcDeviance(preDev,preDevAcc,posChange,maxmin,maxAcceleration):
devAcc = preDevAcc + random.uniform(-posChange,posChange)
if devAcc > maxmin * maxAcceleration: devAcc = maxmin * maxAcceleration
elif devAcc < -maxmin * maxAcceleration: devAcc = -maxmin * maxAcceleration
class DrawHangman():
def __init__(self,bot):
self.bot = bot
dev = preDev + devAcc
if dev > maxmin: dev = maxmin
elif dev < -maxmin: dev = -maxmin
return dev, devAcc
def calcDeviance(self,preDev,preDevAcc,posChange,maxmin,maxAcceleration):
devAcc = preDevAcc + random.uniform(-posChange,posChange)
if devAcc > maxmin * maxAcceleration: devAcc = maxmin * maxAcceleration
elif devAcc < -maxmin * maxAcceleration: devAcc = -maxmin * maxAcceleration
def badCircle():
background = Image.new("RGBA",(circleSize+(lineWidth*3),circleSize+(lineWidth*3)),color=(0,0,0,0))
dev = preDev + devAcc
if dev > maxmin: dev = maxmin
elif dev < -maxmin: dev = -maxmin
return dev, devAcc
d = ImageDraw.Draw(background,"RGBA")
middle = (circleSize+(lineWidth*3))/2
devx = 0
devy = 0
devAccx = 0
devAccy = 0
start = random.randint(-100,-80)
degreesAmount = circleDegrees + random.randint(-10,30)
def badCircle(self):
background = Image.new("RGBA",(circleSize+(lineWidth*3),circleSize+(lineWidth*3)),color=(0,0,0,0))
for degree in range(degreesAmount):
devx, devAccx = calcDeviance(devx,devAccx,lineWidth/100,lineWidth,0.03)
devy, devAccy = calcDeviance(devy,devAccy,lineWidth/100,lineWidth,0.03)
d = ImageDraw.Draw(background,"RGBA")
middle = (circleSize+(lineWidth*3))/2
devx = 0
devy = 0
devAccx = 0
devAccy = 0
start = random.randint(-100,-80)
degreesAmount = circleDegrees + random.randint(-10,30)
x = middle + (math.cos(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devx
y = middle + (math.sin(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devy
for degree in range(degreesAmount):
devx, devAccx = self.calcDeviance(devx,devAccx,lineWidth/100,lineWidth,0.03)
devy, devAccy = self.calcDeviance(devy,devAccy,lineWidth/100,lineWidth,0.03)
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
x = middle + (math.cos(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devx
y = middle + (math.sin(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devy
return background
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
def badLine(length, rotated = False):
if rotated:
w, h = length+lineWidth*3, lineWidth*3
else:
w, h = lineWidth*3,length+lineWidth*3
background = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(background,"RGBA")
devx = random.randint(-int(lineWidth/3),int(lineWidth/3))
devy = 0
devAccx = 0
devAccy = 0
for pixel in range(length):
devx, devAccx = calcDeviance(devx,devAccx,lineWidth/1000,lineWidth,0.004)
devy, devAccy = calcDeviance(devy,devAccy,lineWidth/1000,lineWidth,0.004)
return background
def badLine(self, length, rotated = False):
if rotated:
x = lineWidth + pixel + devx
y = lineWidth + devy
w, h = length+lineWidth*3, lineWidth*3
else:
x = lineWidth + devx
y = lineWidth + pixel + devy
w, h = lineWidth*3,length+lineWidth*3
background = Image.new("RGBA",(w,h),color=(0,0,0,0))
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
d = ImageDraw.Draw(background,"RGBA")
devx = random.randint(-int(lineWidth/3),int(lineWidth/3))
devy = 0
devAccx = 0
devAccy = 0
return background
for pixel in range(length):
devx, devAccx = self.calcDeviance(devx,devAccx,lineWidth/1000,lineWidth,0.004)
devy, devAccy = self.calcDeviance(devy,devAccy,lineWidth/1000,lineWidth,0.004)
def drawMan(misses):
background = Image.new("RGBA",(manx,many),color=(0,0,0,0))
if rotated:
x = lineWidth + pixel + devx
y = lineWidth + devy
else:
x = lineWidth + devx
y = lineWidth + pixel + devy
if misses >= 1:
head = badCircle()
background.paste(head,(int((manx-(circleSize+(lineWidth*3)))/2),0),head)
if misses >= 2:
body = badLine(bodySize)
background.paste(body,(int((manx-(lineWidth*3))/2),circleSize),body)
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
if misses >= 3:
limbs = random.sample(["rl","ll","ra","la"],min(misses-2,4))
else: limbs = []
return background
for limb in limbs:
if limb == "ra":
limbDrawing = badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)
rotationCompensation = min(-int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "la":
limbDrawing = badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)-limbSize
rotationCompensation = min(int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "rl":
limbDrawing = badLine(limbSize,True)
rotation = random.randint(-15,15)
xpos = int((manx-(lineWidth*3))/2)-lineWidth
ypos = circleSize+bodySize-lineWidth
limbDrawing = limbDrawing.rotate(rotation-45,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "ll":
limbDrawing = badLine(limbSize,True)
rotation = random.randint(-15,15)
limbDrawing = limbDrawing.rotate(rotation+45,expand=1)
xpos = int((manx-(lineWidth*3))/2)-limbDrawing.size[0]+lineWidth*3
ypos = circleSize+bodySize
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
def drawMan(self, misses):
background = Image.new("RGBA",(manx,many),color=(0,0,0,0))
return background
if misses >= 1:
head = self.badCircle()
background.paste(head,(int((manx-(circleSize+(lineWidth*3)))/2),0),head)
if misses >= 2:
body = self.badLine(bodySize)
background.paste(body,(int((manx-(lineWidth*3))/2),circleSize),body)
def badText(text, big, color=(0,0,0,255)):
if big: font = fnt
else: font = smolfnt
w, h = font.getsize(text)
img = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(img,"RGBA")
if misses >= 3:
limbs = random.sample(["rl","ll","ra","la"],min(misses-2,4))
else: limbs = []
d.text((0,0),text,font=font,fill=color)
return img
for limb in limbs:
if limb == "ra":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)
rotationCompensation = min(-int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "la":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)-limbSize
rotationCompensation = min(int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "rl":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-15,15)
xpos = int((manx-(lineWidth*3))/2)-lineWidth
ypos = circleSize+bodySize-lineWidth
limbDrawing = limbDrawing.rotate(rotation-45,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "ll":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-15,15)
limbDrawing = limbDrawing.rotate(rotation+45,expand=1)
xpos = int((manx-(lineWidth*3))/2)-limbDrawing.size[0]+lineWidth*3
ypos = circleSize+bodySize
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
def drawGallows():
background = Image.new("RGBA",(gallowx,gallowy),color=(0,0,0,0))
return background
bottomLine = badLine(int(gallowx*0.75),True)
background.paste(bottomLine,(int(gallowx*0.125),gallowy-(lineWidth*4)),bottomLine)
def badText(self, text, big, color=(0,0,0,255)):
if big: font = fnt
else: font = smolfnt
w, h = font.getsize(text)
img = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(img,"RGBA")
lineTwo = badLine(gallowy-lineWidth*6)
background.paste(lineTwo,(int(gallowx*(0.75*goldenRatio)),lineWidth*2),lineTwo)
d.text((0,0),text,font=font,fill=color)
return img
topLine = badLine(int(gallowy*0.30),True)
background.paste(topLine,(int(gallowx*(0.75*goldenRatio))-lineWidth,lineWidth*3),topLine)
def drawGallows(self):
background = Image.new("RGBA",(gallowx,gallowy),color=(0,0,0,0))
lastLine = badLine(int(gallowy*0.125))
background.paste(lastLine,((int(gallowx*(0.75*goldenRatio))+int(gallowy*0.30)-lineWidth),lineWidth*3),lastLine)
return background
bottomLine = self.badLine(int(gallowx*0.75),True)
background.paste(bottomLine,(int(gallowx*0.125),gallowy-(lineWidth*4)),bottomLine)
def drawLetterLines(word,guessed,misses):
letterLines = Image.new("RGBA",((letterLineLength+letterLineDistance)*len(word),letterLineLength+lineWidth*3),color=(0,0,0,0))
for x, letter in enumerate(word):
line = badLine(letterLineLength,True)
letterLines.paste(line,(x*(letterLineLength+letterLineDistance),letterLineLength),line)
if guessed[x]:
letterDrawing = badText(letter,True)
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
elif misses == 6:
letterDrawing = badText(letter,True,(242,66,54))
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
lineTwo = self.badLine(gallowy-lineWidth*6)
background.paste(lineTwo,(int(gallowx*(0.75*goldenRatio)),lineWidth*2),lineTwo)
return letterLines
topLine = self.badLine(int(gallowy*0.30),True)
background.paste(topLine,(int(gallowx*(0.75*goldenRatio))-lineWidth,lineWidth*3),topLine)
def shortestDist(positions,newPosition):
shortestDist = math.inf
x, y = newPosition
for i, j in positions:
xdist = abs(i-x)
ydist = abs(j-y)
dist = math.sqrt(xdist**2+ydist**2)
if shortestDist > dist: shortestDist = dist
return shortestDist
lastLine = self.badLine(int(gallowy*0.125))
background.paste(lastLine,((int(gallowx*(0.75*goldenRatio))+int(gallowy*0.30)-lineWidth),lineWidth*3),lastLine)
return background
def drawMisses(guesses,word):
background = Image.new("RGBA",(600,400),color=(0,0,0,0))
pos = []
for guess in guesses:
if guess not in word:
placed = False
while placed == False:
letter = badText(guess,True)
w, h = fnt.getsize(guess)
x = random.randint(0,600-w)
y = random.randint(0,400-h)
if shortestDist(pos,(x,y)) > 70:
pos.append((x,y))
background.paste(letter,(x,y),letter)
placed = True
return background
def drawLetterLines(self, word,guessed,misses):
letterLines = Image.new("RGBA",((letterLineLength+letterLineDistance)*len(word),letterLineLength+lineWidth*3),color=(0,0,0,0))
for x, letter in enumerate(word):
line = self.badLine(letterLineLength,True)
letterLines.paste(line,(x*(letterLineLength+letterLineDistance),letterLineLength),line)
if guessed[x]:
letterDrawing = self.badText(letter,True)
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
elif misses == 6:
letterDrawing = self.badText(letter,True,(242,66,54))
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
def drawImage(channel):
with open("resources/games/hangmanGames.json", "r") as f:
data = json.load(f)
return letterLines
random.seed(data[channel]["game ID"])
def shortestDist(self,positions,newPosition):
shortestDist = math.inf
x, y = newPosition
for i, j in positions:
xdist = abs(i-x)
ydist = abs(j-y)
dist = math.sqrt(xdist**2+ydist**2)
if shortestDist > dist: shortestDist = dist
return shortestDist
background = Image.open("resources/paper.jpg")
try:
gallow = drawGallows()
except:
logThis("Error drawing gallows (error code 1711)")
def drawMisses(self,guesses,word):
background = Image.new("RGBA",(600,400),color=(0,0,0,0))
pos = []
for guess in guesses:
if guess not in word:
placed = False
while placed == False:
letter = self.badText(guess,True)
w, h = fnt.getsize(guess)
x = random.randint(0,600-w)
y = random.randint(0,400-h)
if self.shortestDist(pos,(x,y)) > 70:
pos.append((x,y))
background.paste(letter,(x,y),letter)
placed = True
return background
try:
man = drawMan(data[channel]["misses"])
except:
logThis("Error drawing stick figure (error code 1712)")
def drawImage(self,channel):
logThis("Drawing hangman image",channel)
game = self.bot.database["hangman games"].find_one({"_id":channel})
random.seed(data[channel]["game ID"])
try:
letterLines = drawLetterLines(data[channel]["word"],data[channel]["guessed"],data[channel]["misses"])
except:
logThis("error drawing letter lines (error code 1713)")
random.seed(game["game ID"])
random.seed(data[channel]["game ID"])
try:
misses = drawMisses(data[channel]["guessed letters"],data[channel]["word"])
except:
logThis("Error drawing misses (error code 1714)")
background = Image.open("resources/paper.jpg")
try:
gallow = self.drawGallows()
except:
logThis("Error drawing gallows (error code 1711)")
background.paste(gallow,(100,100),gallow)
background.paste(man,(300,210),man)
background.paste(letterLines,(120,840),letterLines)
background.paste(misses,(600,150),misses)
try:
man = self.drawMan(game["misses"])
except:
logThis("Error drawing stick figure (error code 1712)")
missesText = badText("MISSES",False)
missesTextWidth = missesText.size[0]
background.paste(missesText,(850-int(missesTextWidth/2),50),missesText)
random.seed(game["game ID"])
try:
letterLines = self.drawLetterLines(game["word"],game["guessed"],game["misses"])
except:
logThis("error drawing letter lines (error code 1713)")
background.save("resources/games/hangmanBoards/hangmanBoard"+channel+".png")
random.seed(game["game ID"])
try:
misses = self.drawMisses(game["guessed letters"],game["word"])
except:
logThis("Error drawing misses (error code 1714)")
background.paste(gallow,(100,100),gallow)
background.paste(man,(300,210),man)
background.paste(letterLines,(120,840),letterLines)
background.paste(misses,(600,150),misses)
missesText = self.badText("MISSES",False)
missesTextWidth = missesText.size[0]
background.paste(missesText,(850-int(missesTextWidth/2),50),missesText)
background.save("resources/games/hangmanBoards/hangmanBoard"+channel+".png")

View File

@ -1,10 +1,9 @@
import json
import random
import copy
import math
from . import hexDraw
from funcs import logThis, getName, getID
from .hexDraw import DrawHex
from funcs import logThis
BOARDWIDTH = 11
ALL_POSITIONS = [(i,j) for i in range(11) for j in range(11)]
@ -14,368 +13,364 @@ for position in ALL_POSITIONS:
EMPTY_DIJKSTRA[position] = math.inf # an impossibly high number
HEX_DIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)]
# Parses command
def parseHex(command, channel, user):
commands = command.lower().split()
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
if command == "" or command == " ":
return "I didn't get that. Use \"!hex start [opponent]\" to start a game.", False, False, False, False
elif commands[0] == "start":
# Starting a game
if len(commands) == 1: # if the commands is "!hex start", the opponent is Gwendolyn at difficulty 2
commands.append("2")
logThis("Starting a hex game with hexStart(). "+str(user)+" challenged "+commands[1])
return hexStart(channel,user,commands[1]) # commands[1] is the opponent
# If using a command with no game, return error
elif channel not in data:
return "There's no game in this channel", False, False, False, False
class HexGame():
def __init__(self,bot):
self.bot = bot
self.draw = DrawHex(bot)
# Stopping the game
elif commands[0] == "stop":
if user in data[channel]["players"]:
return "Ending game.", False, False, True, False
else:
return "You can't end a game where you're not a player.", False, False, False, False
# Placing a piece
elif commands[0] == "place":
try:
return placeHex(channel,commands[1], user)
except:
return "I didn't get that. To place a piece use \"!hex place [position]\". A valid position is e.g. \"E2\".", False, False, False, False
# Undo
elif commands[0] == "undo":
return undoHex(channel, user)
# Surrender
elif commands[0] == "surrender":
players = data[channel]["players"]
if user in players:
opponent = (players.index(user) + 1) % 2
data[channel]["winner"] = opponent + 1
return "{} surrendered. That means {} won! Adding 30 Gwendobucks to their account.".format(getName(user),getName(players[opponent])), False, False, True, False
else:
return "You can't surrender when you're not a player.", False, False, False, False
# Parses command
def parseHex(self, command, channel, user):
commands = command.lower().split()
game = self.bot.database["hex games"].find_one({"_id":channel})
# Swap
elif commands[0] == "swap":
if len(data[channel]["gameHistory"]) == 1: # Only after the first move
data[channel]["players"] = data[channel]["players"][::-1] # Swaps their player-number
with open("resources/games/hexGames.json", "w") as f:
json.dump(data,f,indent=4)
# Swaps the color of the hexes on the board drawing:
hexDraw.drawSwap(channel)
player2 = data[channel]["players"][1]
gwendoTurn = (player2 == "Gwendolyn")
return "The color of both players were swapped. It is now {}'s turn".format(player2), True, True, False, gwendoTurn
else:
return "You can only swap as the second player after the very first move.", False, False, False, False
if command == "" or command == " ":
return "I didn't get that. Use \"!hex start [opponent]\" to start a game.", False, False, False, False
else:
return "I didn't get that. Use \"!hex start [opponent]\" to start a game, \"!hex place [position]\" to place a piece, \"!hex undo\" to undo your last move or \"!hex stop\" to stop a current game.", False, False, False, False
elif commands[0] == "start":
# Starting a game
if len(commands) == 1: # if the commands is "!hex start", the opponent is Gwendolyn at difficulty 2
commands.append("2")
logThis("Starting a hex game with hexStart(). "+str(user)+" challenged "+commands[1])
return self.hexStart(channel,user,commands[1]) # commands[1] is the opponent
# If using a command with no game, return error
elif game == None:
return "There's no game in this channel", False, False, False, False
# Starts the game
def hexStart(channel, user, opponent):
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
if channel not in data:
if opponent in ["1","2","3","4","5"]:
difficulty = int(opponent)
diffText = " with difficulty "+opponent
opponent = "Gwendolyn"
elif opponent.lower() == "gwendolyn":
difficulty = 2
diffText = " with difficulty 2"
opponent = "Gwendolyn"
else:
try:
int(opponent)
return "That difficulty doesn't exist", False, False, False, False
except:
opponent = getID(opponent)
if opponent == None:
return "I can't find that user", False, False, False, False
else:
# Opponent is another player
difficulty = 3
diffText = ""
# board is 11x11
board = [ [ 0 for i in range(BOARDWIDTH) ] for j in range(BOARDWIDTH) ]
players = [user,opponent]
random.shuffle(players) # random starting player
gameHistory = []
data[channel] = {"board":board, "winner":0,
"players":players, "turn":1, "difficulty":difficulty, "gameHistory":gameHistory}
with open("resources/games/hexGames.json", "w") as f:
json.dump(data,f,indent=4)
# draw the board
hexDraw.drawBoard(channel)
gwendoTurn = True if players[0] == "Gwendolyn" else False
showImage = True
return "Started Hex game against "+getName(opponent)+ diffText+". It's "+getName(players[0])+"'s turn", showImage, False, False, gwendoTurn
else:
return "There's already a hex game going on in this channel", False, False, False, False
# Places a piece at the given location and checks things afterwards
def placeHex(channel : str,position : str, user):
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
if channel in data:
players = data[channel]["players"]
if user in players:
turn = data[channel]["turn"]
if players[0] == players[1]:
player = turn
# Stopping the game
elif commands[0] == "stop":
if user in game["players"]:
return "Ending game.", False, False, True, False
else:
player = players.index(user)+1
return "You can't end a game where you're not a player.", False, False, False, False
# Placing a piece
elif commands[0] == "place":
try:
return self.placeHex(channel,commands[1], user)
except:
return "I didn't get that. To place a piece use \"!hex place [position]\". A valid position is e.g. \"E2\".", False, False, False, False
# Undo
elif commands[0] == "undo":
return self.undoHex(channel, user)
# Surrender
elif commands[0] == "surrender":
players = game["players"]
if user in players:
opponent = (players.index(user) + 1) % 2
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}})
return "{} surrendered. That means {} won! Adding 30 Gwendobucks to their account.".format(self.bot.funcs.getName(user),self.bot.funcs.getName(players[opponent])), False, False, True, False
else:
return "You can't surrender when you're not a player.", False, False, False, False
# Swap
elif commands[0] == "swap":
if len(game["gameHistory"]) == 1: # Only after the first move
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"players":game["players"][::-1]}}) # Swaps their player-number
# Swaps the color of the hexes on the board drawing:
self.draw.drawSwap(channel)
player2 = game["players"][1]
gwendoTurn = (player2 == "Gwendolyn")
return "The color of both players were swapped. It is now {}'s turn".format(player2), True, True, False, gwendoTurn
else:
return "You can only swap as the second player after the very first move.", False, False, False, False
else:
return "I didn't get that. Use \"!hex start [opponent]\" to start a game, \"!hex place [position]\" to place a piece, \"!hex undo\" to undo your last move or \"!hex stop\" to stop a current game.", False, False, False, False
# Starts the game
def hexStart(self, channel, user, opponent):
game = self.bot.database["hex games"].find_one({"_id":channel})
if game == None:
if opponent in ["1","2","3","4","5"]:
difficulty = int(opponent)
diffText = " with difficulty "+opponent
opponent = "Gwendolyn"
elif opponent.lower() == "gwendolyn":
difficulty = 2
diffText = " with difficulty 2"
opponent = "Gwendolyn"
else:
try:
int(opponent)
return "That difficulty doesn't exist", False, False, False, False
except:
opponent = self.bot.funcs.getID(opponent)
if opponent == None:
return "I can't find that user", False, False, False, False
else:
# Opponent is another player
difficulty = 3
diffText = ""
if player == turn:
board = data[channel]["board"]
# board is 11x11
board = [ [ 0 for i in range(BOARDWIDTH) ] for j in range(BOARDWIDTH) ]
players = [user,opponent]
random.shuffle(players) # random starting player
gameHistory = []
logThis("Placing a piece on the board with placeHex()")
# Places on board
board = placeOnHexBoard(board,player,position)
if isinstance(board, list):
# If the move is valid:
data[channel]["board"] = board
turn = 1 if turn == 2 else 2
data[channel]["turn"] = turn
newGame = {"_id":channel,"board":board, "winner":0,
"players":players, "turn":1, "difficulty":difficulty, "gameHistory":gameHistory}
# Checking for a win
logThis("Checking for win")
score, winner = evaluateBoard(data[channel]["board"])
self.bot.database["hex games"].insert_one(newGame)
if winner == 0: # Continue with the game.
gameWon = False
message = getName(data[channel]["players"][player-1])+" placed at "+position.upper()+". It's now "+getName(data[channel]["players"][turn-1])+"'s turn."# The score is "+str(score)
else: # Congratulations!
gameWon = True
data[channel]["winner"] = winner
message = getName(data[channel]["players"][player-1])+" placed at "+position.upper()+" and won!"
if data[channel]["players"][winner-1] != "Gwendolyn":
winAmount = data[channel]["difficulty"]*10
message += " Adding "+str(winAmount)+" GwendoBucks to their account."
data[channel]["gameHistory"].append((int(position[1])-1, ord(position[0])-97))
# Is it now Gwendolyn's turn?
gwendoTurn = False
if data[channel]["players"][turn-1] == "Gwendolyn":
logThis("It's Gwendolyn's turn")
gwendoTurn = True
# Save the data
with open("resources/games/hexGames.json", "w") as f:
json.dump(data,f,indent=4)
# Update the board
hexDraw.drawHexPlacement(channel,player,position)
# draw the board
self.draw.drawBoard(channel)
return message, True, True, gameWon, gwendoTurn
gwendoTurn = True if players[0] == "Gwendolyn" else False
showImage = True
return "Started Hex game against "+self.bot.funcs.getName(opponent)+ diffText+". It's "+self.bot.funcs.getName(players[0])+"'s turn", showImage, False, False, gwendoTurn
else:
return "There's already a hex game going on in this channel", False, False, False, False
# Places a piece at the given location and checks things afterwards
def placeHex(self, channel : str,position : str, user):
game = self.bot.database["hex games"].find_one({"_id":channel})
if game != None:
players = game["players"]
if user in players:
turn = game["turn"]
if players[0] == players[1]:
player = turn
else:
# Invalid move. "board" is the error message
message = board
player = players.index(user)+1
if player == turn:
board = game["board"]
logThis("Placing a piece on the board with placeHex()")
# Places on board
board = self.placeOnHexBoard(board,player,position)
if isinstance(board, list):
# If the move is valid:
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"board":board}})
turn = 1 if turn == 2 else 2
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"turn":turn}})
# Checking for a win
logThis("Checking for win")
winner = self.evaluateBoard(game["board"])[1]
if winner == 0: # Continue with the game.
gameWon = False
message = self.bot.funcs.getName(game["players"][player-1])+" placed at "+position.upper()+". It's now "+self.bot.funcs.getName(game["players"][turn-1])+"'s turn."# The score is "+str(score)
else: # Congratulations!
gameWon = True
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":winner}})
message = self.bot.funcs.getName(game["players"][player-1])+" placed at "+position.upper()+" and won!"
if game["players"][winner-1] != "Gwendolyn":
winAmount = game["difficulty"]*10
message += " Adding "+str(winAmount)+" GwendoBucks to their account."
self.bot.database["hex games"].update_one({"_id":channel},
{"$push":{"gameHistory":(int(position[1])-1, ord(position[0])-97)}})
# Is it now Gwendolyn's turn?
gwendoTurn = False
if game["players"][turn-1] == "Gwendolyn":
logThis("It's Gwendolyn's turn")
gwendoTurn = True
# Update the board
self.draw.drawHexPlacement(channel,player,position)
return message, True, True, gameWon, gwendoTurn
else:
# Invalid move. "board" is the error message
message = board
return message, False, False, False, False
else:
# Move out of turn
message = "It isn't your turn, it is "+self.bot.funcs.getName(game["players"][turn-1])+"'s turn."
return message, False, False, False, False
else:
# Move out of turn
message = "It isn't your turn, it is "+getName(data[channel]["players"][turn-1])+"'s turn."
message = "You can't place when you're not in the game. The game's players are: "+self.bot.funcs.getName(game["players"][0])+" and "+self.bot.funcs.getName(game["players"][1])+"."
return message, False, False, False, False
else:
message = "You can't place when you're not in the game. The game's players are: "+getName(data[channel]["players"][0])+" and "+getName(data[channel]["players"][1])+"."
return message, False, False, False, False
else:
return "There's no game in this channel", False, False, False, False
return "There's no game in this channel", False, False, False, False
# Returns a board where the placement has occured
def placeOnHexBoard(board,player,position):
# Translates the position
position = position.lower()
# Error handling
try:
column = ord(position[0]) - 97 # ord() translates from letter to number
row = int(position[1:]) - 1
if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH):
logThis("Position out of bounds (error code 1533)")
return "Error. That position is out of bounds."
except:
logThis("Invalid position (error code 1531)")
return "Error. The position should be a letter followed by a number, e.g. \"e2\"."
# Place at the position
if board[row][column] == 0:
board[row][column] = player
return board
else:
logThis("Cannot place on existing piece (error code 1532)")
return "Error. You must place on an empty space."
# Returns a board where the placement has occured
def placeOnHexBoard(self, board,player,position):
# Translates the position
position = position.lower()
# Error handling
try:
column = ord(position[0]) - 97 # ord() translates from letter to number
row = int(position[1:]) - 1
if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH):
logThis("Position out of bounds (error code 1533)")
return "Error. That position is out of bounds."
except:
logThis("Invalid position (error code 1531)")
return "Error. The position should be a letter followed by a number, e.g. \"e2\"."
# Place at the position
if board[row][column] == 0:
board[row][column] = player
return board
else:
logThis("Cannot place on existing piece (error code 1532)")
return "Error. You must place on an empty space."
# After your move, you have the option to undo get your turn back #TimeTravel
def undoHex(channel, user):
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
if user in data[channel]["players"]:
if len(data[channel]["gameHistory"]):
turn = data[channel]["turn"]
# You can only undo after your turn, which is the opponent's turn.
if user == data[channel]["players"][(turn % 2)]: # If it's not your turn
logThis("Undoing {}'s last move".format(getName(user)))
# After your move, you have the option to undo get your turn back #TimeTravel
def undoHex(self, channel, user):
game = self.bot.database["hex games"].find_one({"_id":channel})
lastMove = data[channel]["gameHistory"].pop()
data[channel]["board"][lastMove[0]][lastMove[1]] = 0
data[channel]["turn"] = turn%2 + 1
# Save the data
with open("resources/games/hexGames.json", "w") as f:
json.dump(data,f,indent=4)
# Update the board
hexDraw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear
return "You undid your last move at {}".format(lastMove), True, True, False, False
if user in game["players"]:
if len(game["gameHistory"]):
turn = game["turn"]
# You can only undo after your turn, which is the opponent's turn.
if user == game["players"][(turn % 2)]: # If it's not your turn
logThis("Undoing {}'s last move".format(self.bot.funcs.getName(user)))
lastMove = game["gameHistory"].pop()
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"board."+lastMove[0]+"."+lastMove[1]:0}})
self.bot.database["hex games"].update_one({"_id":channel},
{"$set":{"turn":turn%2 + 1}})
# Update the board
self.draw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear
return "You undid your last move at {}".format(lastMove), True, True, False, False
else:
# Sassy
return "Nice try. You can't undo your opponent's move. ", False, False, False, False
else:
# Sassy
return "Nice try. You can't undo your opponent's move. ", False, False, False, False
return "Really? You undo right at the start of the game?", False, False, False, False
else:
# Sassy
return "Really? You undo right at the start of the game?", False, False, False, False
else:
return "You're not a player in the game", False, False, False, False
return "You're not a player in the game", False, False, False, False
# Plays as the AI
def hexAI(channel):
logThis("Figuring out best move")
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
board = data[channel]["board"]
if len(data[channel]["gameHistory"]):
lastMove = data[channel]["gameHistory"][-1]
else:
lastMove = (5,5)
# These moves are the last move +- 2.
moves = [[(lastMove[0]+j-2,lastMove[1]+i-2) for i in range(5) if lastMove[1]+i-2 in range(11)] for j in range(5) if lastMove[0]+j-2 in range(11)]
moves = sum(moves,[])
movesCopy = moves.copy()
for move in movesCopy:
if board[move[0]][move[1]] != 0:
moves.remove(move)
chosenMove = random.choice(moves)
"""
GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue
if len(data[channel]["gameHistory"]) == 0:
return placeHex(channel,"F6", "Gwendolyn") # If starting, start in the middle
board = data[channel]["board"]
difficulty = data[channel]["difficulty"]
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
judgements = [float('nan')]*len(possiblePlaces) # All possible moves are yet to be judged
current_score = evaluateBoard(board)[0]
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = GwenColor
if evaluateBoard(testBoard)[0] != current_score: # only think about a move if it improves the score (it's impossible to get worse)
# Testing a move and evaluating it
judgements[i] = minimaxHex(testBoard,difficulty,-math.inf,math.inf,GwenColor==2)
logThis("Best score for place {} is {}".format((i // BOARDWIDTH,i % BOARDWIDTH),judgements[i]))
# Plays as the AI
def hexAI(self, channel):
logThis("Figuring out best move")
game = self.bot.database["hex games"].find_one({"_id":channel})
board = game["board"]
bestScore = max(judgements) if (GwenColor == 1) else min(judgements) # this line has an error
indices = [i for i, x in enumerate(judgements) if x == bestScore] # which moves got that score?
i = random.choice(indices)
chosenMove = (i // BOARDWIDTH , i % BOARDWIDTH)
"""
placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1)
logThis("ChosenMove is {} at {}".format(chosenMove,placement))
return placeHex(channel,placement, "Gwendolyn")
def evaluateBoard(board):
scores = {1:0, 2:0}
winner = 0
# Here, I use Dijkstra's algorithm to evaluate the board, as proposed by this article: https://towardsdatascience.com/hex-creating-intelligent-adversaries-part-2-heuristics-dijkstras-algorithm-597e4dcacf93
for player in [1,2]:
Distance = copy.deepcopy(EMPTY_DIJKSTRA)
# Initialize the starting hexes. For the blue player, this is the leftmost column. For the red player, this is the tom row.
for start in (ALL_POSITIONS[::11] if player == 2 else ALL_POSITIONS[:11]):
# An empty hex adds a of distance of 1. A hex of own color add distance 0. Opposite color adds infinite distance.
Distance[start] = 1 if (board[start[0]][start[1]] == 0) else 0 if (board[start[0]][start[1]] == player) else math.inf
visited = set() # Also called sptSet, short for "shortest path tree Set"
for _ in range(BOARDWIDTH**2): # We can at most check every 121 hexes
# Find the next un-visited hex, that has the lowest distance
remainingHexes = ALL_SET.difference(visited)
A = [Distance[k] for k in remainingHexes] # Find the distance to each un-visited hex
u = list(remainingHexes)[A.index(min(A))] # Chooses the one with the lowest distance
# Find neighbors of the hex u
for di in HEX_DIRECTIONS:
v = (u[0] + di[0] , u[1] + di[1]) # v is a neighbor of u
if v[0] in range(11) and v[1] in range(11) and v not in visited:
new_dist = Distance[u] + (1 if (board[v[0]][v[1]] == 0) else 0 if (board[v[0]][v[1]] == player) else math.inf)
Distance[v] = min(Distance[v], new_dist)
# After a hex has been visited, this is noted
visited.add(u)
#logThis("Distance from player {}'s start to {} is {}".format(player,u,Distance[u]))
if u[player-1] == 10: # if the right coordinate of v is 10, it means we're at the goal
scores[player] = Distance[u] # A player's score is the shortest distance to goal. Which equals the number of remaining moves they need to win if unblocked by the opponent.
break
if len(game["gameHistory"]):
lastMove = game["gameHistory"][-1]
else:
logThis("For some reason, no path to the goal was found. ")
if scores[player] == 0:
winner = player
break # We don't need to check the other player's score, if player1 won.
return scores[2]-scores[1], winner
lastMove = (5,5)
# These moves are the last move +- 2.
moves = [[(lastMove[0]+j-2,lastMove[1]+i-2) for i in range(5) if lastMove[1]+i-2 in range(11)] for j in range(5) if lastMove[0]+j-2 in range(11)]
moves = sum(moves,[])
movesCopy = moves.copy()
for move in movesCopy:
if board[move[0]][move[1]] != 0:
moves.remove(move)
chosenMove = random.choice(moves)
def minimaxHex(board, depth, alpha, beta, maximizingPlayer):
# The depth is how many moves ahead the computer checks. This value is the difficulty.
if depth == 0 or 0 not in sum(board,[]):
score = evaluateBoard(board)[0]
return score
# if final depth is not reached, look another move ahead:
if maximizingPlayer: # red player predicts next move
maxEval = -math.inf
"""
GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue
if len(data[channel]["gameHistory"]) == 0:
return placeHex(channel,"F6", "Gwendolyn") # If starting, start in the middle
board = data[channel]["board"]
difficulty = data[channel]["difficulty"]
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
#logThis("Judging a red move at depth {}".format(depth))
judgements = [float('nan')]*len(possiblePlaces) # All possible moves are yet to be judged
current_score = evaluateBoard(board)[0]
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 1 # because maximizingPlayer is Red which is number 1
evaluation = minimaxHex(testBoard,depth-1,alpha,beta,False)
maxEval = max(maxEval, evaluation)
alpha = max(alpha, evaluation)
if beta <= alpha:
#logThis("Just pruned something!")
break
return maxEval
else: # blue player predicts next move
minEval = math.inf
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
#logThis("Judging a blue move at depth {}".format(depth))
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 2 # because minimizingPlayer is Blue which is number 2
evaluation = minimaxHex(testBoard,depth-1,alpha,beta,True)
minEval = min(minEval, evaluation)
beta = min(beta, evaluation)
if beta <= alpha:
#logThis("Just pruned something!")
break
return minEval
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = GwenColor
if evaluateBoard(testBoard)[0] != current_score: # only think about a move if it improves the score (it's impossible to get worse)
# Testing a move and evaluating it
judgements[i] = minimaxHex(testBoard,difficulty,-math.inf,math.inf,GwenColor==2)
logThis("Best score for place {} is {}".format((i // BOARDWIDTH,i % BOARDWIDTH),judgements[i]))
bestScore = max(judgements) if (GwenColor == 1) else min(judgements) # this line has an error
indices = [i for i, x in enumerate(judgements) if x == bestScore] # which moves got that score?
i = random.choice(indices)
chosenMove = (i // BOARDWIDTH , i % BOARDWIDTH)
"""
placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1)
logThis("ChosenMove is {} at {}".format(chosenMove,placement))
return self.placeHex(channel,placement, "Gwendolyn")
def evaluateBoard(self, board):
scores = {1:0, 2:0}
winner = 0
# Here, I use Dijkstra's algorithm to evaluate the board, as proposed by this article: https://towardsdatascience.com/hex-creating-intelligent-adversaries-part-2-heuristics-dijkstras-algorithm-597e4dcacf93
for player in [1,2]:
Distance = copy.deepcopy(EMPTY_DIJKSTRA)
# Initialize the starting hexes. For the blue player, this is the leftmost column. For the red player, this is the tom row.
for start in (ALL_POSITIONS[::11] if player == 2 else ALL_POSITIONS[:11]):
# An empty hex adds a of distance of 1. A hex of own color add distance 0. Opposite color adds infinite distance.
Distance[start] = 1 if (board[start[0]][start[1]] == 0) else 0 if (board[start[0]][start[1]] == player) else math.inf
visited = set() # Also called sptSet, short for "shortest path tree Set"
for _ in range(BOARDWIDTH**2): # We can at most check every 121 hexes
# Find the next un-visited hex, that has the lowest distance
remainingHexes = ALL_SET.difference(visited)
A = [Distance[k] for k in remainingHexes] # Find the distance to each un-visited hex
u = list(remainingHexes)[A.index(min(A))] # Chooses the one with the lowest distance
# Find neighbors of the hex u
for di in HEX_DIRECTIONS:
v = (u[0] + di[0] , u[1] + di[1]) # v is a neighbor of u
if v[0] in range(11) and v[1] in range(11) and v not in visited:
new_dist = Distance[u] + (1 if (board[v[0]][v[1]] == 0) else 0 if (board[v[0]][v[1]] == player) else math.inf)
Distance[v] = min(Distance[v], new_dist)
# After a hex has been visited, this is noted
visited.add(u)
#logThis("Distance from player {}'s start to {} is {}".format(player,u,Distance[u]))
if u[player-1] == 10: # if the right coordinate of v is 10, it means we're at the goal
scores[player] = Distance[u] # A player's score is the shortest distance to goal. Which equals the number of remaining moves they need to win if unblocked by the opponent.
break
else:
logThis("For some reason, no path to the goal was found. ")
if scores[player] == 0:
winner = player
break # We don't need to check the other player's score, if player1 won.
return scores[2]-scores[1], winner
def minimaxHex(self, board, depth, alpha, beta, maximizingPlayer):
# The depth is how many moves ahead the computer checks. This value is the difficulty.
if depth == 0 or 0 not in sum(board,[]):
score = self.evaluateBoard(board)[0]
return score
# if final depth is not reached, look another move ahead:
if maximizingPlayer: # red player predicts next move
maxEval = -math.inf
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
#logThis("Judging a red move at depth {}".format(depth))
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 1 # because maximizingPlayer is Red which is number 1
evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,False)
maxEval = max(maxEval, evaluation)
alpha = max(alpha, evaluation)
if beta <= alpha:
#logThis("Just pruned something!")
break
return maxEval
else: # blue player predicts next move
minEval = math.inf
possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0]
#logThis("Judging a blue move at depth {}".format(depth))
for i in possiblePlaces:
testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 2 # because minimizingPlayer is Blue which is number 2
evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,True)
minEval = min(minEval, evaluation)
beta = min(beta, evaluation)
if beta <= alpha:
#logThis("Just pruned something!")
break
return minEval

View File

@ -1,9 +1,8 @@
import json
import math
import os
from PIL import Image, ImageDraw, ImageFont
from funcs import logThis, getName
from funcs import logThis
# Defining all the variables
CANVAS_WIDTH = 2400
@ -38,152 +37,151 @@ NAMEHEXPADDING = 90
SMOL_WIDTH = HEXAGONWIDTH * 0.6
SMOL_SIDELENGTH = SIDELENGTH * 0.6
def drawBoard(channel):
logThis("Drawing empty Hex board")
class DrawHex():
def __init__(self,bot):
self.bot = bot
# Creates the empty image
im = Image.new('RGB', size=(CANVAS_WIDTH, CANVAS_HEIGHT),color = BACKGROUND_COLOR)
# 'd' is a shortcut to drawing on the image
d = ImageDraw.Draw(im,"RGBA")
def drawBoard(self, channel):
logThis("Drawing empty Hex board")
# Drawing all the hexagons
for column in BOARDCOORDINATES:
for startingPoint in column:
x = startingPoint[0]
y = startingPoint[1]
d.polygon([
(x, y),
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH),
(x+HEXAGONWIDTH, y),
(x+HEXAGONWIDTH, y+SIDELENGTH),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH),
(x, y+SIDELENGTH),
],fill = BETWEEN_COLOR)
d.polygon([
(x+X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH + HEXTHICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH - HEXTHICKNESS),
(x+X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
],fill = BLANK_COLOR)
# Creates the empty image
im = Image.new('RGB', size=(CANVAS_WIDTH, CANVAS_HEIGHT),color = BACKGROUND_COLOR)
# 'd' is a shortcut to drawing on the image
d = ImageDraw.Draw(im,"RGBA")
# Draw color on the outside of the board
# Top line, red
d.line(sum((sum([(point[0],point[1],point[0]+HEXAGONWIDTH/2,point[1]-HEXAGONHEIGHT+SIDELENGTH) for point in BOARDCOORDINATES[0]],()),(BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4)),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Bottom line, red
d.line(sum(((BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4),sum([(point[0]+HEXAGONWIDTH/2,point[1]+HEXAGONHEIGHT,point[0]+HEXAGONWIDTH,point[1]+SIDELENGTH) for point in BOARDCOORDINATES[10]],())),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Left line, blue
d.line(sum((sum([(row[0][0],row[0][1],row[0][0],row[0][1]+SIDELENGTH) for row in BOARDCOORDINATES],()),(BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4)),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Right line, blue
d.line(sum(((BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4),sum([(row[10][0]+HEXAGONWIDTH,row[10][1],row[10][0]+HEXAGONWIDTH,row[10][1]+SIDELENGTH) for row in BOARDCOORDINATES],())),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Writes "abc..", "123.." on the columns and rows
for i in range(11):
# Top letters
d.text( (X_OFFSET + HEXAGONWIDTH*i, Y_OFFSET-66) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Bottom letters
d.text( (X_OFFSET + HEXAGONWIDTH*(i+11.5/2), Y_OFFSET - 15 + 11*HEXAGONHEIGHT) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Left numbers
d.multiline_text( (X_OFFSET + HEXAGONWIDTH*i/2 - 72 -4*(i>8), Y_OFFSET + 18 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR, align="right")
# Right numbers
d.text( (X_OFFSET + HEXAGONWIDTH*(i/2+11) + 30 , Y_OFFSET + 6 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR)
# Write player names and color
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
for p in [1,2]:
playername = getName(data[channel]["players"][p-1])
# Draw name
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
d.text((x,y),playername, font=NAME_fnt, fill = TEXTCOLOR)
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p])
im.save("resources/games/hexBoards/board"+channel+".png")
def drawHexPlacement(channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
logThis("Drawing a newly placed hex. Filepath: "+FILEPATH)
# Translates position
# We don't need to error-check, because the position is already checked in placeOnHexBoard()
position = position.lower()
column = ord(position[0])-97 # ord() translates from letter to number
row = int(position[1:])-1
# Find the coordinates for the filled hex drawing
hexCoords = [
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]-0.5*SIDELENGTH + COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]+1.5*SIDELENGTH - COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
]
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Draws the hex piece
d.polygon(hexCoords,fill = PIECECOLOR[player], outline = BETWEEN_COLOR)
# Save
im.save(FILEPATH)
except:
logThis("Error drawing new hex on board (error code 1541")
def drawSwap(channel):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
with open("resources/games/hexGames.json", "r") as f:
data = json.load(f)
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Write player names and color
for p in [1,2]:
playername = getName(data[channel]["players"][p%2])
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
# Drawing all the hexagons
for column in BOARDCOORDINATES:
for startingPoint in column:
x = startingPoint[0]
y = startingPoint[1]
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p % 2 + 1])
# Save
im.save(FILEPATH)
except:
logThis("Error drawing swap (error code 1542)")
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH),
(x+HEXAGONWIDTH, y),
(x+HEXAGONWIDTH, y+SIDELENGTH),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH),
(x, y+SIDELENGTH),
],fill = BETWEEN_COLOR)
d.polygon([
(x+X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH + HEXTHICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH - HEXTHICKNESS),
(x+X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
],fill = BLANK_COLOR)
# Draw color on the outside of the board
# Top line, red
d.line(sum((sum([(point[0],point[1],point[0]+HEXAGONWIDTH/2,point[1]-HEXAGONHEIGHT+SIDELENGTH) for point in BOARDCOORDINATES[0]],()),(BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4)),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Bottom line, red
d.line(sum(((BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4),sum([(point[0]+HEXAGONWIDTH/2,point[1]+HEXAGONHEIGHT,point[0]+HEXAGONWIDTH,point[1]+SIDELENGTH) for point in BOARDCOORDINATES[10]],())),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Left line, blue
d.line(sum((sum([(row[0][0],row[0][1],row[0][0],row[0][1]+SIDELENGTH) for row in BOARDCOORDINATES],()),(BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4)),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Right line, blue
d.line(sum(((BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4),sum([(row[10][0]+HEXAGONWIDTH,row[10][1],row[10][0]+HEXAGONWIDTH,row[10][1]+SIDELENGTH) for row in BOARDCOORDINATES],())),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Writes "abc..", "123.." on the columns and rows
for i in range(11):
# Top letters
d.text( (X_OFFSET + HEXAGONWIDTH*i, Y_OFFSET-66) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Bottom letters
d.text( (X_OFFSET + HEXAGONWIDTH*(i+11.5/2), Y_OFFSET - 15 + 11*HEXAGONHEIGHT) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Left numbers
d.multiline_text( (X_OFFSET + HEXAGONWIDTH*i/2 - 72 -4*(i>8), Y_OFFSET + 18 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR, align="right")
# Right numbers
d.text( (X_OFFSET + HEXAGONWIDTH*(i/2+11) + 30 , Y_OFFSET + 6 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR)
# Write player names and color
game = self.bot.database["hex games"].find_one({"_id":channel})
for p in [1,2]:
playername = self.bot.funcs.getName(game["players"][p-1])
# Draw name
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
d.text((x,y),playername, font=NAME_fnt, fill = TEXTCOLOR)
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p])
im.save("resources/games/hexBoards/board"+channel+".png")
def drawHexPlacement(self, channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
logThis("Drawing a newly placed hex. Filepath: "+FILEPATH)
# Translates position
# We don't need to error-check, because the position is already checked in placeOnHexBoard()
position = position.lower()
column = ord(position[0])-97 # ord() translates from letter to number
row = int(position[1:])-1
# Find the coordinates for the filled hex drawing
hexCoords = [
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]-0.5*SIDELENGTH + COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]+1.5*SIDELENGTH - COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
]
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Draws the hex piece
d.polygon(hexCoords,fill = PIECECOLOR[player], outline = BETWEEN_COLOR)
# Save
im.save(FILEPATH)
except:
logThis("Error drawing new hex on board (error code 1541")
def drawSwap(self, channel):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
game = self.bot.database["hex games"].find_one({"_id":channel})
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Write player names and color
for p in [1,2]:
playername = getName(game["players"][p%2])
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p % 2 + 1])
# Save
im.save(FILEPATH)
except:
logThis("Error drawing swap (error code 1542)")

View File

@ -1,131 +1,137 @@
import json
class Invest():
def __init__(self,bot):
self.bot = bot
from funcs import getName
from .money import checkBalance, addMoney
def getPrice(self, symbol : str):
res = self.bot.finnhubClient.quote(symbol.upper())
if res == {}:
return 0
else:
return int(res["c"] * 100)
def getPrice(symbol : str,finnhubClient):
res = finnhubClient.quote(symbol.upper())
if res == {}:
return 0
else:
return int(res["c"] * 100)
def getPortfolio(self, user : str):
userInvestments = self.bot.database["investments"].find_one({"_id":user})
def getPortfolio(user : str,finnhubClient):
with open("resources/games/investments.json") as f:
data = json.load(f)
if userInvestments in [None,{}]:
return f"{self.bot.funcs.getName(user)} does not have a stock portfolio."
else:
portfolio = f"**Stock portfolio for {self.bot.funcs.getName(user)}**"
if user not in data or data[user] == {}:
return f"{getName(user)} does not have a stock portfolio."
else:
portfolio = f"**Stock portfolio for {getName(user)}**"
for key, value in list(userInvestments["investments"].items()):
purchaseValue = value["purchased for"]
currentValue = int((self.getPrice(key) / value["value at purchase"]) * value["purchased"])
if purchaseValue == "?":
portfolio += f"\n**{key}**: ___{str(currentValue)} GwendoBucks___"
else:
portfolio += f"\n**{key}**: ___{str(currentValue)} GwendoBucks___ (purchased for {str(purchaseValue)})"
for key, value in list(data[user].items()):
purchaseValue = value["purchased for"]
currentValue = int((getPrice(key,finnhubClient) / value["value at purchase"]) * value["purchased"])
if purchaseValue == "?":
portfolio += f"\n**{key}**: ___{str(currentValue)} GwendoBucks___"
else:
portfolio += f"\n**{key}**: ___{str(currentValue)} GwendoBucks___ (purchased for {str(purchaseValue)})"
return portfolio
return portfolio
def buyStock(self, user : str, stock : str, buyAmount : int):
if buyAmount >= 100:
if self.bot.money.checkBalance(user) >= buyAmount:
stockPrice = self.getPrice(stock)
if stockPrice > 0:
userInvestments = self.bot.database["investments"].find_one({"_id":user})
def buyStock(user : str, stock : str, buyAmount : int,finnhubClient):
if buyAmount >= 100:
if checkBalance(user) >= buyAmount:
stockPrice = getPrice(stock,finnhubClient)
if stockPrice > 0:
with open("resources/games/investments.json", "r") as f:
data = json.load(f)
self.bot.money.addMoney(user,-1*buyAmount)
stock = stock.upper()
addMoney(user,-1*buyAmount)
stock = stock.upper()
if userInvestments != None:
userInvestments = userInvestments["investments"]
if stock in userInvestments:
value = userInvestments[stock]
newAmount = int((stockPrice / value["value at purchase"]) * value["purchased"]) + buyAmount
if user in data:
if stock in data[user]:
value = data[user][stock]
newAmount = int((stockPrice / value["value at purchase"]) * value["purchased"]) + buyAmount
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".value at purchase" : stockPrice}})
data[user][stock]["value at purchase"] = stockPrice
data[user][stock]["purchased"] = newAmount
if value["purchased for"] != "?":
data[user][stock]["purchased for"] += buyAmount
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".purchased" : newAmount}})
if value["purchased for"] != "?":
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".purchased for" : buyAmount}})
else:
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock : {"purchased" : buyAmount, "value at purchase" : stockPrice,
"purchased for" : buyAmount}}})
else:
data[user][stock] = {"purchased" : buyAmount, "value at purchase" : stockPrice, "purchased for" : buyAmount}
newUser = {"_id":user,"investments":{stock : {"purchased" : buyAmount, "value at purchase" : stockPrice, "purchased for" : buyAmount}}}
self.bot.database["investments"].insert_one(newUser)
return f"{self.bot.funcs.getName(user)} bought {buyAmount} GwendoBucks worth of {stock} stock"
else:
data[user] = {stock : {"purchased" : buyAmount, "value at purchase" : stockPrice, "purchased for" : buyAmount}}
with open("resources/games/investments.json", "w") as f:
json.dump(data,f,indent=4)
return f"{getName(user)} bought {buyAmount} GwendoBucks worth of {stock} stock"
return f"{stock} is not traded on the american market."
else:
return f"{stock} is not traded on the american market."
return "You don't have enough money for that"
else:
return "You don't have enough money for that"
else:
return "You cannot buy stocks for less than 100 GwendoBucks"
return "You cannot buy stocks for less than 100 GwendoBucks"
def sellStock(user : str, stock : str, sellAmount : int,finnhubClient):
if sellAmount > 0:
with open("resources/games/investments.json", "r") as f:
data = json.load(f)
def sellStock(self, user : str, stock : str, sellAmount : int):
if sellAmount > 0:
stock = stock.upper()
userInvestments = self.bot.database["investments"].find_one({"_id":user})["investments"]
if user in data and stock in data[user]:
value = data[user][stock]
stockPrice = getPrice(stock,finnhubClient)
data[user][stock]["purchased"] = int((stockPrice / value["value at purchase"]) * value["purchased"])
data[user][stock]["value at purchase"] = stockPrice
if value["purchased"] >= sellAmount:
stock = stock.upper()
addMoney(user,sellAmount)
if sellAmount < value["purchased"]:
data[user][stock]["purchased"] -= sellAmount
data[user][stock]["purchased for"] = "?"
if userInvestments != None and stock in userInvestments:
value = userInvestments[stock]
stockPrice = self.getPrice(stock)
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".purchased" :
int((stockPrice / value["value at purchase"]) * value["purchased"])}})
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".value at purchase" : stockPrice}})
if value["purchased"] >= sellAmount:
self.bot.money.addMoney(user,sellAmount)
if sellAmount < value["purchased"]:
self.bot.database["investments"].update_one({"_id":user},
{"$inc":{"investments."+stock+".purchased" : -sellAmount}})
self.bot.database["investments"].update_one({"_id":user},
{"$set":{"investments."+stock+".purchased for" : "?"}})
else:
self.bot.database["investments"].update_one({"_id":user},
{"$unset":{"investments."+stock:""}})
return f"{self.bot.funcs.getName(user)} sold {sellAmount} GwendoBucks worth of {stock} stock"
else:
del data[user][stock]
with open("resources/games/investments.json", "w") as f:
json.dump(data,f,indent=4)
return f"{getName(user)} sold {sellAmount} GwendoBucks worth of {stock} stock"
return f"You don't have enough {stock} stocks to do that"
else:
return f"You don't have enough {stock} stocks to do that"
return f"You don't have any {stock} stock"
else:
return f"You don't have any {stock} stock"
else:
return "no"
return "no"
def parseInvest(content: str, user : str,finnhubClient):
if content.startswith("check"):
commands = content.split(" ")
if len(commands) == 1:
return getPortfolio(user,finnhubClient)
else:
price = getPrice(commands[1],finnhubClient)
if price == 0:
return f"{commands[1].upper()} is not traded on the american market."
def parseInvest(self, content: str, user : str):
if content.startswith("check"):
commands = content.split(" ")
if len(commands) == 1:
return self.getPortfolio(user)
else:
price = f"{price:,}".replace(",",".")
return f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks"
price = self.getPrice(commands[1])
if price == 0:
return f"{commands[1].upper()} is not traded on the american market."
else:
price = f"{price:,}".replace(",",".")
return f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks"
elif content.startswith("buy"):
commands = content.split(" ")
if len(commands) == 3:
try:
return buyStock(user,commands[1],int(commands[2]),finnhubClient)
except:
return "The command must be given as \"!invest buy [stock] [amount of GwendoBucks to purchase with]\""
else:
return "You must give both a stock name and an amount of gwendobucks you wish to spend."
elif content.startswith("buy"):
commands = content.split(" ")
if len(commands) == 3:
#try:
return self.buyStock(user,commands[1],int(commands[2]))
#except:
# return "The command must be given as \"!invest buy [stock] [amount of GwendoBucks to purchase with]\""
else:
return "You must give both a stock name and an amount of gwendobucks you wish to spend."
elif content.startswith("sell"):
commands = content.split(" ")
if len(commands) == 3:
try:
return sellStock(user,commands[1],int(commands[2]),finnhubClient)
except:
return "The command must be given as \"!invest sell [stock] [amount of GwendoBucks to sell stocks for]\""
else:
return "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for."
elif content.startswith("sell"):
commands = content.split(" ")
if len(commands) == 3:
try:
return self.sellStock(user,commands[1],int(commands[2]))
except:
return "The command must be given as \"!invest sell [stock] [amount of GwendoBucks to sell stocks for]\""
else:
return "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for."

View File

@ -1,56 +1,56 @@
import json
import pymongo
from funcs import logThis, getID, getName
from funcs import logThis
# Returns the account balance for a user
def checkBalance(user):
user = user.lower()
logThis("checking "+user+"'s account balance")
with open("resources/users.json", "r") as f:
data = json.load(f)
class Money():
if user in data:
return data[user]["money"]
else: return 0
def __init__(self, bot):
self.bot = bot
self.database = bot.database
# Adds money to the account of a user
def addMoney(user,amount):
logThis("adding "+str(amount)+" to "+user+"'s account")
with open("resources/users.json", "r") as f:
data = json.load(f)
# Returns the account balance for a user
def checkBalance(self, user):
logThis("checking "+user+"'s account balance")
if user in data:
points = data[user]["money"]
data[user]["money"] = points + amount
else:
data[user]["money"] = amount
userData = self.database["users"].find_one({"_id":user})
with open("resources/users.json", "w") as f:
json.dump(data,f,indent=4)
if userData != None:
return userData["money"]
else: return 0
# Transfers money from one user to another
def giveMoney(user,targetUser,amount):
with open("resources/users.json", "r") as f:
data = json.load(f)
# Adds money to the account of a user
def addMoney(self,user,amount):
logThis("adding "+str(amount)+" to "+user+"'s account")
targetUser = getID(targetUser)
userData = self.database["users"].find_one({"_id":user})
if amount > 0:
if targetUser != None:
if user in data:
if data[user]["money"] >= amount:
addMoney(user,-1 * amount)
addMoney(targetUser,amount)
return "Transferred "+str(amount)+" GwendoBucks to "+getName(targetUser)
else:
logThis("They didn't have enough GwendoBucks (error code 1223b)")
return "You don't have that many GwendoBucks (error code 1223b)"
else:
logThis("They didn't have enough GwendoBucks (error code 1223a)")
return "You don't have that many GwendoBucks (error code 1223a)"
if userData != None:
self.database["users"].update_one({"_id":user},{"$inc":{"money":amount}})
else:
logThis("They weren't in the system")
return "The target doesn't exist"
else:
logThis("They tried to steal")
return "Yeah, no. You can't do that"
self.database["users"].insert_one({"_id":user,"user name":self.bot.funcs.getName(user),"money":amount})
# Transfers money from one user to another
def giveMoney(self,user,targetUser,amount):
userData = self.database["users"].find_one({"_id":user})
targetUser = self.bot.funcs.getID(targetUser)
if amount > 0:
if targetUser != None:
if userData != None:
if userData["money"] >= amount:
self.addMoney(user,-1 * amount)
self.addMoney(targetUser,amount)
return "Transferred "+str(amount)+" GwendoBucks to "+self.bot.funcs.getName(targetUser)
else:
logThis("They didn't have enough GwendoBucks (error code 1223b)")
return "You don't have that many GwendoBucks (error code 1223b)"
else:
logThis("They didn't have enough GwendoBucks (error code 1223a)")
return "You don't have that many GwendoBucks (error code 1223a)"
else:
logThis("They weren't in the system")
return "The target doesn't exist"
else:
logThis("They tried to steal")
return "Yeah, no. You can't do that"

View File

@ -1,141 +1,138 @@
import json, random
import random
from funcs import getName, logThis
from . import monopolyDraw
from funcs import logThis
from .monopolyDraw import DrawMonopoly
rulesAndTerms = {
"pass go money" : 200,
"money term" : "GP"
}
def monopolyStart(channel):
logThis("Starting a monopoly game")
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
class Monopoly():
def __init__(self, bot):
self.bot = bot
self.draw = DrawMonopoly(bot)
if channel not in data:
buildings = [0] * 40
def monopolyStart(self, channel):
logThis("Starting a monopoly game")
game = self.bot.database["monopoly games"].find_one({"_id":channel})
data[channel] = {"players" : {}, "player list" : [],"turn" : 0, "buildings" : buildings, "last roll" : [0,0], "started" : False}
if game == None:
buildings = [0] * 40
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
newGame = {"_id":channel,"players" : {}, "player list" : [],"turn" : 0, "buildings" : buildings, "last roll" : [0,0], "started" : False}
def monopolyJoin(channel,user):
with open("resources/games/monopolyGames.json", "r") as f:
data = json.load(f)
self.bot.database["monopoly games"].insert_one(newGame)
if channel in data:
if not data[channel]["started"]:
if user not in data[channel]["players"]:
if len(data[channel]["players"]) < 6:
try:
self.draw.drawImage(channel)
except:
logThis("Error drawing board (error code 1640)")
data[channel]["players"][user] = {"position" : 0, "properties" : [], "money" : 1500, "doubles" : 0}
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
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(data,f,indent=4)
def monopolyJoin(self,channel,user):
game = self.bot.database["monopoly games"].find_one({"_id":channel})
return getName(user)+" has joined the game.", False, False, False, False
if game != None:
if not game["started"]:
if user not in game["players"]:
if len(game["players"]) < 6:
newPlayer = {"position" : 0, "properties" : [], "money" : 1500, "doubles" : 0}
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"players."+user:newPlayer}})
return self.bot.funcs.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 "There are already 6 players in the game.", False, False, False, False
return "You're already in the game!", False, False, False, False
else:
return "You're already in the game!", False, False, False, False
return "It's too late to join.", 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
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
def parseMonopoly(self, command, channel, user):
logThis("Parsing "+command)
commands = command.split()
if command in [" ", ""] or commands[0] == "start":
try:
return self.monopolyStart(channel)
except:
logThis("Error starting game (error code 1620)")
elif commands[0] == "join":
try:
return self.monopolyJoin(channel,user)
except:
logThis("Error joining game (error code 1630)")
elif commands[0] == "roll":
try:
return self.monopolyRoll(channel,user)
except:
logThis("Error rolling (error code 1650)")
else:
if data[channel]["last roll"][0] == data[channel]["last roll"][1]:
turn = data[channel]["turn"]
return "I didn't understand that (error code 1602)", False, False, False, False
def monopolyContinue(self, channel):
game = self.bot.database["monopoly games"].find_one({"_id":channel})
if game != None:
if game["started"] == False:
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"started":True}})
playerList = list(game["players"].keys())
random.shuffle(playerList)
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"player list":playerList}})
turn = 0
else:
turn = (data[channel]["turn"] + 1)%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)")
if game["last roll"][0] == game["last roll"][1]:
turn = game["turn"]
else:
turn = (game["turn"] + 1)%len(game["player list"])
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"turn":turn}})
playerList = list(game["players"].keys())
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
try:
self.draw.drawImage(channel)
except:
logThis("Error drawing board (error code 1640)")
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 playerList == []:
return "No one joined. Ending game.", False, True, True
else:
message = "It's "+self.bot.funcs.getName(playerList[turn])+"'s turn. Use the 🎲 reaction to roll. You can also use \"!monopoly trade\" at any time."
return message, True, True, False
if user == currentPlayer:
rolls = [random.randint(1,6),random.randint(1,6)]
message = getName(user)+" rolled a "+str(rolls[0])+" and a "+str(rolls[1])+"."
if rolls[0] == rolls[1]:
message += " Doubbles!"
def monopolyRoll(self, channel,user):
game = self.bot.database["monopoly games"].find_one({"_id":channel})
roll = rolls[0] + rolls[1]
oldPosition = data[channel]["players"][user]["position"]
newPosition = (oldPosition + roll)%40
if newPosition < oldPosition:
data[channel]["players"][user]["money"] += rulesAndTerms["pass go money"]
message += "\nYou passed go and got "+str(rulesAndTerms["pass go money"])+" "+rulesAndTerms["money term"]+"."
turn = game["turn"]
currentPlayer = game["player list"][turn]
data[channel]["players"][user]["position"] = newPosition
data[channel]["last roll"] = rolls
if user == currentPlayer:
rolls = [random.randint(1,6),random.randint(1,6)]
message = self.bot.funcs.getName(user)+" rolled a "+str(rolls[0])+" and a "+str(rolls[1])+"."
if rolls[0] == rolls[1]:
message += " Doubbles!"
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 message, True, True, False, True
else: return "", False, False, False, False
roll = rolls[0] + rolls[1]
oldPosition = game["players"][user]["position"]
newPosition = (oldPosition + roll)%40
if newPosition < oldPosition:
self.bot.database["monopoly games"].update_one({"_id":channel},
{"$inc":{"players."+user+".money":rulesAndTerms["pass go money"]}})
message += "\nYou passed go and got "+str(rulesAndTerms["pass go money"])+" "+rulesAndTerms["money term"]+"."
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"players."+user+".position":newPosition}})
self.bot.database["monopoly games"].update_one({"_id":channel},{"$set":{"last roll":rolls}})
try:
self.draw.drawImage(channel)
except:
logThis("Error drawing board (error code 1640)")
return message, True, True, False, True
else: return "", False, False, False, False

View File

@ -1,4 +1,4 @@
import math, json
import math
from funcs import logThis
@ -10,48 +10,48 @@ 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)
class DrawMonopoly():
def __init__(self,bot):
self.bot = bot
board = Image.open("resources/games/monopolyBoard.png")
d = ImageDraw.Draw(board,"RGBA")
def drawImage(self, channel):
logThis("Drawing monopoly board for "+channel)
game = self.bot.database["monopoly games"].find_one({"_id":channel})
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 = Image.open("resources/games/monopolyBoard.png")
d = ImageDraw.Draw(board,"RGBA")
board.save("resources/games/monopolyBoards/monopolyBoard"+channel+".png")
for key, value in list(game["players"].items()):
logThis("Drawing "+key)
try:
x, y = self.getPosition(value["position"])
except:
logThis("Error getting position (error code 1641)")
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)
def getPosition(self, 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))
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 <= 10:
y = math.floor(largeSpace/2)
elif positionNumber > 10 and positionNumber < 20:
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))
if positionNumber >= 0 and positionNumber <= 20:
y = math.floor(largeSpace/2)
elif positionNumber > 10 and positionNumber < 20:
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
return x, y

View File

@ -5,88 +5,84 @@ import random
from . import money
from funcs import logThis
# Starts a game of trivia. Downloads a question with answers, shuffles the wrong answers with the
# correct answer and returns the questions and answers. Also saves the question in the games.json file.
def triviaStart(channel : str):
with open("resources/games/games.json", "r") as f:
triviaFile = json.load(f)
logThis("Trying to find a trivia question for "+channel)
class Trivia():
def __init__(self, bot):
self.bot = bot
if channel not in triviaFile["trivia questions"]:
with urllib.request.urlopen("https://opentdb.com/api.php?amount=10&type=multiple") as response:
data = json.loads(response.read())
logThis("Found the question \""+data["results"][0]["question"]+"\"")
answers = data["results"][0]["incorrect_answers"]
answers.append(data["results"][0]["correct_answer"])
random.shuffle(answers)
correctAnswer = answers.index(data["results"][0]["correct_answer"]) + 97
triviaFile["trivia questions"][channel] = {"answer" : str(chr(correctAnswer)),"players" : {}}
with open("resources/games/games.json", "w") as f:
json.dump(triviaFile,f,indent=4)
# Starts a game of trivia. Downloads a question with answers, shuffles the wrong answers with the
# correct answer and returns the questions and answers. Also saves the question in the games.json file.
def triviaStart(self, channel : str):
question = self.bot.database["trivia questions"].find_one({"_id":channel})
replacements = {"&#039;": "\'",
"&quot;": "\"",
"&ldquo;": "\"",
"&rdquo;": "\"",
"&eacute;": "é"}
question = data["results"][0]["question"]
logThis("Trying to find a trivia question for "+channel)
if question == None:
with urllib.request.urlopen("https://opentdb.com/api.php?amount=10&type=multiple") as response:
data = json.loads(response.read())
logThis("Found the question \""+data["results"][0]["question"]+"\"")
answers = data["results"][0]["incorrect_answers"]
answers.append(data["results"][0]["correct_answer"])
random.shuffle(answers)
correctAnswer = answers.index(data["results"][0]["correct_answer"]) + 97
self.bot.database["trivia questions"].insert_one({"_id":channel,"answer" : str(chr(correctAnswer)),"players" : {}})
replacements = {"&#039;": "\'",
"&quot;": "\"",
"&ldquo;": "\"",
"&rdquo;": "\"",
"&eacute;": "é"}
question = data["results"][0]["question"]
for key, value in replacements.items():
question = question.replace(key,value)
for answer in answers:
for key, value in replacements.items():
answer = answer.replace(key,value)
question = question.replace(key,value)
return question, answers, correctAnswer
else:
logThis("There was already a trivia question for that channel (error code 1106)")
return "There's already a trivia question going on. Try again in like, a minute (error code 1106)", "", ""
for answer in answers:
for key, value in replacements.items():
answer = answer.replace(key,value)
# Lets players answer a trivia question
def triviaAnswer(user : str, channel : str, command : str):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
if command in ["a","b","c","d"]:
if channel in data["trivia questions"]:
if user not in data["trivia questions"][channel]["players"]:
logThis(user+" answered the question in "+channel)
data["trivia questions"][channel]["players"][user] = command
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
return "Locked in "+user+"'s answer"
else:
logThis(user+" has already answered this question (error code 1105)")
return user+" has already answered this question (error code 1105)"
return question, answers, correctAnswer
else:
logThis("There's no question right now (error code 1104)")
return "There's no question right now (error code 1104)"
else:
logThis("I didn't quite understand that (error code 1103)")
return "I didn't quite understand that (error code 1103)"
logThis("There was already a trivia question for that channel (error code 1106)")
return "There's already a trivia question going on. Try again in like, a minute (error code 1106)", "", ""
# Lets players answer a trivia question
def triviaAnswer(self, user : str, channel : str, command : str):
question = self.bot.database["trivia questions"].find_one({"_id":channel})
if command in ["a","b","c","d"]:
if question != None:
if user not in question["players"]:
logThis(user+" answered the question in "+channel)
self.bot.database["trivia questions"].update_one({"_id":channel},{"$set":{"players."+user : command}})
return "Locked in "+user+"'s answer"
else:
logThis(user+" has already answered this question (error code 1105)")
return user+" has already answered this question (error code 1105)"
else:
logThis("There's no question right now (error code 1104)")
return "There's no question right now (error code 1104)"
else:
logThis("I didn't quite understand that (error code 1103)")
return "I didn't quite understand that (error code 1103)"
# Adds 1 GwendoBuck to each player that got the question right and deletes question from games.json.
def triviaCountPoints(channel : str):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
# Adds 1 GwendoBuck to each player that got the question right and deletes question from games.json.
def triviaCountPoints(self, channel : str):
question = self.bot.database["trivia questions"].find_one({"_id":channel})
logThis("Counting points for question in "+channel)
logThis("Counting points for question in "+channel)
if channel in data["trivia questions"]:
for player, answer in data["trivia questions"][channel]["players"].items():
if answer == data["trivia questions"][channel]["answer"]:
money.addMoney(player,1)
if question != None:
for player, answer in question["players"].items():
if answer == question["answer"]:
self.bot.money.addMoney(player,1)
else:
logThis("Couldn't find the question (error code 1102)")
return None
else:
logThis("Couldn't find the question (error code 1102)")
return None

View File

@ -7,7 +7,6 @@ import time # Used for logging
import logging # Used for... you know... logging
import wikia # Used by findWikiPage
import os # Used by makeFiles
import git # Used by stopServer()
import pymongo # Used by transferUsers
logging.basicConfig(filename="gwendolyn.log", level=logging.INFO)
@ -207,86 +206,6 @@ def emojiToCommand(emoji):
return "roll"
else: return ""
def fiarReactionTest(channel,message,user):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
with open("resources/games/oldImages/fourInARow"+str(channel.id), "r") as f:
oldImage = int(f.read())
if message.id == oldImage:
logThis("They reacted to the fourinarow game")
turn = data["4 in a row games"][str(channel.id)]["turn"]
if user == data["4 in a row games"][str(channel.id)]["players"][turn]:
return True, turn+1
else:
logThis("It wasn't their turn")
return False, 0
else:
return False, 0
def monopolyReactionTest(channel,message):
try:
with open("resources/games/oldImages/monopoly"+str(channel.id), "r") as f:
oldImage = int(f.read())
except:
return False
if message.id == oldImage:
logThis("They reacted to the monopoly game")
return True
else:
return False
def hangmanReactionTest(channel,message):
try:
with open("resources/games/oldImages/hangman"+str(channel.id), "r") as f:
oldMessages = f.read().splitlines()
except:
return False
gameMessage = False
for oldMessage in oldMessages:
oldMessageID = int(oldMessage)
if message.id == oldMessageID:
logThis("They reacted to the hangman game")
gameMessage = True
return gameMessage
def stopServer():
with open("resources/games/games.json","r") as f:
games = json.load(f)
games["trivia questions"] = {}
games["blackjack games"] = {}
games["4 in a row games"] = {}
with open("resources/games/games.json","w") as f:
json.dump(games,f,indent=4)
emptyDict = {}
with open("resources/games/monopolyGames.json", "w") as f:
json.dump(emptyDict,f,indent=4)
with open("resources/games/hexGames.json", "w") as f:
json.dump(emptyDict,f,indent=4)
with open("resources/games/hangmanGames.json", "w") as f:
json.dump(emptyDict,f,indent=4)
g = git.cmd.Git("")
g.pull()
def deleteGame(gameType,channel):
with open("resources/games/games.json", "r") as f:
data = json.load(f)
del data[gameType][channel]
with open("resources/games/games.json", "w") as f:
json.dump(data,f,indent=4)
def addToDict(userID,userName):
with open("resources/users.json", "r") as f:
data = json.load(f)
@ -315,35 +234,6 @@ def addToDict(userID,userName):
with open("resources/users.json", "w") as f:
json.dump(data,f,indent=4)
def getName(userID):
try:
with open("resources/users.json", "r") as f:
data = json.load(f)
if userID in data:
return data[userID]["user name"]
else:
logThis("Couldn't find user "+userID)
return userID
except:
logThis("Error getting name")
def getID(userName):
try:
with open("resources/users.json", "r") as f:
data = json.load(f)
userID = None
for key, value in data.items():
if userName.lower() == value["user name"].lower():
userID = key
break
return userID
except:
logThis("Error getting ID")
def transferUsers(database):
collist = database.list_collection_names()
if "users" not in collist and os.path.exists("resources/users.json"):
@ -354,7 +244,20 @@ def transferUsers(database):
userList = []
for key, value in list(data.items()):
user = {"_id":int(key[1:]),"user name":value["user name"],"money":value["money"]}
user = {"_id":key,"user name":value["user name"],"money":value["money"]}
userList.append(user)
database["users"].insert_many(userList)
if "investments" not in collist and os.path.exists("resources/games/investments.json"):
logThis("Transfering investments")
with open("resources/games/investments.json", "r") as f:
data = json.load(f)
userList = []
for key, value in list(data.items()):
user = {"_id":key,"investments":value}
userList.append(user)
database["investments"].insert_many(userList)

View File

@ -1,7 +1,7 @@
"""Functions related to the Star Wars TTRPG."""
__all__ = ["parseChar", "parseRoll", "critRoll", "parseDestiny"]
__all__ = ["SwChar", "SwRoll", "SwDestiny"]
from .swchar import parseChar
from .swroll import parseRoll, critRoll
from .swdestiny import parseDestiny
from .swchar import SwChar
from .swroll import SwRoll
from .swdestiny import SwDestiny

View File

@ -1,142 +1,201 @@
import json
import string
from funcs import logThis, getName
from funcs import logThis
def getCharName(user : str):
logThis("Getting name for "+getName(user)+"'s character")
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
if user in data:
logThis("Name is "+data[user]["Name"])
return data[user]["Name"]
else:
logThis("Just using "+getName(user))
return getName(user)
class SwChar():
def __init__(self, bot):
self.bot = bot
def setUpDict(cmd : dict):
logThis("Setting up a dictionary in a nice way")
if bool(cmd):
keys = list(cmd)
values = list(cmd.values())
result = ""
if type(values[0]) is dict:
return ", ".join(values)
def getCharName(self, user : str):
logThis("Getting name for "+self.bot.funcs.getName(user)+"'s character")
userCharacter = self.bot.database["swcharacters"].find_one({"_id":user})
if user != None:
logThis("Name is "+userCharacter["Name"])
return userCharacter["Name"]
else:
for x in range(len(keys)):
if type(keys[x]) is list:
if x%3 != 2:
result += "**" + keys[x] + "**" + ": " + ", ".join(values[x]) + " "
else:
result += "**" + keys[x] + "**" + ": " + ", ".join(values[x]) + "\n"
else:
if x%3 != 2:
result += "**" + keys[x] + "**" + ": " + str(values[x]) + " "
else:
result += "**" + keys[x] + "**" + ": " + str(values[x]) + "\n"
logThis("Returning a dictionary, but well formatted")
return result
else:
logThis("Couldn't find anything")
return "There doesn't seem to be anything here..."
logThis("Just using "+self.bot.funcs.getName(user))
return self.bot.funcs.getName(user)
def lookUp(data : dict, key : str, cmd : str = ""):
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
logThis("Looking up "+key)
if key in data:
logThis(key+" exists")
if cmd == "":
if type(data[key]) is dict and key != "Weapons":
return setUpDict(data[key])
elif key == "Weapons":
logThis("Does this even get used? I'm too scared to delete it")
if bool(data[key]):
logThis("Found "+(", ".join(list(data[key]))))
return ", ".join(list(data[key]))
else:
logThis("There is nothing here")
return "There doesn't seem to be anything here..."
def setUpDict(self, cmd : dict):
logThis("Setting up a dictionary in a nice way")
if bool(cmd):
keys = list(cmd)
values = list(cmd.values())
result = ""
if type(values[0]) is dict:
return ", ".join(values)
else:
if str(data[key]) != "":
logThis("Returning "+str(data[key]))
return data[key]
else:
logThis("There was nothing there")
return "There doesn't seem to be anything here"
elif cmd[0] == '+':
logThis("Trying to add to "+key)
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Yeah, that fucked up")
return "Can't do that"
for x in range(len(keys)):
if type(keys[x]) is list:
if x%3 != 2:
result += "**" + keys[x] + "**" + ": " + ", ".join(values[x]) + " "
else:
result += "**" + keys[x] + "**" + ": " + ", ".join(values[x]) + "\n"
else:
if x%3 != 2:
result += "**" + keys[x] + "**" + ": " + str(values[x]) + " "
else:
result += "**" + keys[x] + "**" + ": " + str(values[x]) + "\n"
logThis("Returning a dictionary, but well formatted")
return result
else:
logThis("Couldn't find anything")
return "There doesn't seem to be anything here..."
if type(data[key]) is int:
def lookUp(self, data : dict, key : str, cmd : str = ""):
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
logThis("Looking up "+key)
if key in data:
logThis(key+" exists")
if cmd == "":
if type(data[key]) is dict and key != "Weapons":
return self.setUpDict(data[key])
elif key == "Weapons":
logThis("Does this even get used? I'm too scared to delete it")
if bool(data[key]):
logThis("Found "+(", ".join(list(data[key]))))
return ", ".join(list(data[key]))
else:
logThis("There is nothing here")
return "There doesn't seem to be anything here..."
else:
if str(data[key]) != "":
logThis("Returning "+str(data[key]))
return data[key]
else:
logThis("There was nothing there")
return "There doesn't seem to be anything here"
elif cmd[0] == '+':
logThis("Trying to add to "+key)
try:
newValue = data[key] + int(cmd)
data[key] = newValue
logThis("Added "+cmd+" to "+key)
return data
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Couldn't add "+cmd+" to "+key)
return "Can't add that"
elif type(data[key]) is list:
logThis("Yeah, that fucked up")
return "Can't do that"
if type(data[key]) is int:
try:
data[key].append(cmd)
newValue = data[key] + int(cmd)
data[key] = newValue
logThis("Added "+cmd+" to "+key)
return data
except:
logThis("Couldn't add "+cmd+" to "+key)
return "Can't add that"
else:
logThis("Yeah, I can't add that to "+key)
return "Can't add that"
elif type(data[key]) is list:
try:
data[key].append(cmd)
logThis("Added "+cmd+" to "+key)
return data
except:
logThis("Couldn't add "+cmd+" to "+key)
return "Can't add that"
else:
logThis("Yeah, I can't add that to "+key)
return "Can't add that"
elif cmd[0] == '-':
logThis("Trying to remove/subtract from "+key)
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Yeah, that fucked up")
return "Can't do that"
if type(data[key]) is int:
elif cmd[0] == '-':
logThis("Trying to remove/subtract from "+key)
try:
newValue = data[key] - int(cmd)
data[key] = newValue
logThis("Subtracted "+cmd+" from "+key)
return data
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Couldn't subtract "+cmd+" from "+key)
return "Can't remove that"
elif type(data[key]) is list:
logThis("Yeah, that fucked up")
return "Can't do that"
if type(data[key]) is int:
try:
data[key].remove(cmd)
logThis("Removed "+cmd+" from "+key)
newValue = data[key] - int(cmd)
data[key] = newValue
logThis("Subtracted "+cmd+" from "+key)
return data
except:
logThis("Couldn't remove "+cmd+" from "+key)
logThis("Couldn't subtract "+cmd+" from "+key)
return "Can't remove that"
elif type(data[key]) is list:
try:
data[key].remove(cmd)
logThis("Removed "+cmd+" from "+key)
return data
except:
logThis("Couldn't remove "+cmd+" from "+key)
return "Can't remove that"
else:
logThis("Yeah, I can't remove/subtract that from "+key)
return "Can't remove that"
else:
logThis("Yeah, I can't remove/subtract that from "+key)
return "Can't remove that"
else:
while cmd[0] == ' ':
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
if type(data[key]) is dict:
if type(data[key]) is dict:
newKey = cmd.split(" ")[0]
cmd = cmd[len(newKey):]
if cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
logThis("Looking up "+newKey+" in "+key)
lookUpResult = self.lookUp(data[key],newKey,cmd)
if type(lookUpResult) is dict:
data[key] = lookUpResult
return data
else:
return lookUpResult
elif type(data[key]) != list:
logThis("Trying to change "+key+" to "+cmd)
try:
cmd = type(data[key])(cmd)
data[key] = cmd
logThis("Did that")
return data
except:
logThis("No. That did not work")
return "Wrong data type"
else:
logThis("Yeah, that didn't work")
return "Wrong data type"
else:
logThis("Couldn't find "+key)
logThis("Testing to see if it's a multi-word key")
cmd = key + " " + cmd
words = cmd.split(" ")
search = ""
i = 0
while search not in data:
try:
search += " " + words[i]
i += 1
except:
logThis("It wasn't. "+search+" doesn't exist")
return search + " doesn't exist"
if search[0] == " ":
search = search[1:]
logThis("Yeah! Did that! The key was "+search)
cmd = cmd[len(search):]
if cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
if cmd == "":
logThis("Returning "+search)
return self.setUpDict(data[search])
else:
newKey = cmd.split(" ")[0]
cmd = cmd[len(newKey):]
if cmd != "":
@ -144,394 +203,321 @@ def lookUp(data : dict, key : str, cmd : str = ""):
cmd = cmd[1:]
if cmd == "":
break
logThis("Looking up "+newKey+" in "+key)
lookUpResult = lookUp(data[key],newKey,cmd)
lookUpResult = self.lookUp(data[search],newKey,cmd)
if type(lookUpResult) is dict:
data[key] = lookUpResult
data[search] = lookUpResult
return data
else:
return lookUpResult
elif type(data[key]) != list:
logThis("Trying to change "+key+" to "+cmd)
try:
cmd = type(data[key])(cmd)
data[key] = cmd
logThis("Did that")
return data
except:
logThis("No. That did not work")
return "Wrong data type"
else:
logThis("Yeah, that didn't work")
return "Wrong data type"
else:
logThis("Couldn't find "+key)
logThis("Testing to see if it's a multi-word key")
cmd = key + " " + cmd
words = cmd.split(" ")
search = ""
i = 0
while search not in data:
try:
search += " " + words[i]
i += 1
except:
logThis("It wasn't. "+search+" doesn't exist")
return search + " doesn't exist"
if search[0] == " ":
search = search[1:]
logThis("Yeah! Did that! The key was "+search)
cmd = cmd[len(search):]
if cmd != "":
def characterSheet(self,character : dict):
logThis("Setting up a character sheet for "+character["Name"])
divider = "--------------------\n"
name = character["Name"]
textf = ""
if character["Force-rating"] != 0:
textf = "\n**Force Rating**: "+str(character["Force-rating"])
text1 = "**Species**: "+character["Species"]+"\n**Career**: "+character["Career"]+"\n**Specialization Trees**: "+", ".join(character["Specialization-trees"])+textf+"\n**Soak**: "+str(character["Soak"])
text2 = "\n\n**Wounds**: "+str(character["Wounds"])+"/"+str(character["Wound-threshold"])+"\n**Strain**: "+str(character["Strain"])+"/"+str(character["Strain-threshold"])
text3 = self.setUpDict(character["Characteristics"])
text4 = self.setUpDict(character["Skills"])
text5 = ""
text6 = ""
text7 = ""
text8 = ""
if bool(character["Talents"]):
text5 = "**Talents**: "+", ".join(list(character["Talents"]))+"\n\n"
if bool(character["Force-powers"]):
text6 = "**Force Powers**: "+", ".join(list(character["Force-powers"]))+"\n\n"
text7 = "**Equipment**: "+", ".join(character["Equipment"])+"\n**Credits**: "+str(character["Credits"])+"\n**Weapons**: "+", ".join(list(character["Weapons"]))+"\n"+divider
if bool(character["Obligations"]):
text8 = "**Obligations**: "+",".join(list(character["Obligations"]))
return name, text1+text2+"\n\n"+text3+divider+text4+"\n"+divider+text5+text6+text7+text8
def charData(self,user : str,cmd : str):
userCharacter = self.bot.database["swcharacters"].find_one({"_id":user})
key = string.capwords(cmd.split(" ")[0])
cmd = cmd[len(key):]
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
if cmd == "":
logThis("Returning "+search)
return setUpDict(data[search])
else:
newKey = cmd.split(" ")[0]
cmd = cmd[len(newKey):]
if cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
logThis("Looking for "+self.bot.funcs.getName(user)+"'s character")
if userCharacter != None:
logThis("Foundt it! Looking for "+key+" in the data")
if key in userCharacter:
logThis("Found it!")
if type(userCharacter[key]) is dict:
logThis("It's a dictionary!")
if cmd == "":
break
lookUpResult = lookUp(data[search],newKey,cmd)
if type(lookUpResult) is dict:
data[search] = lookUpResult
return data
else:
return lookUpResult
def characterSheet(character : dict):
logThis("Setting up a character sheet for "+character["Name"])
divider = "--------------------\n"
name = character["Name"]
textf = ""
if character["Force-rating"] != 0:
textf = "\n**Force Rating**: "+str(character["Force-rating"])
text1 = "**Species**: "+character["Species"]+"\n**Career**: "+character["Career"]+"\n**Specialization Trees**: "+", ".join(character["Specialization-trees"])+textf+"\n**Soak**: "+str(character["Soak"])
text2 = "\n\n**Wounds**: "+str(character["Wounds"])+"/"+str(character["Wound-threshold"])+"\n**Strain**: "+str(character["Strain"])+"/"+str(character["Strain-threshold"])
text3 = setUpDict(character["Characteristics"])
text4 = setUpDict(character["Skills"])
text5 = ""
text6 = ""
text7 = ""
text8 = ""
if bool(character["Talents"]):
text5 = "**Talents**: "+", ".join(list(character["Talents"]))+"\n\n"
if bool(character["Force-powers"]):
text6 = "**Force Powers**: "+", ".join(list(character["Force-powers"]))+"\n\n"
text7 = "**Equipment**: "+", ".join(character["Equipment"])+"\n**Credits**: "+str(character["Credits"])+"\n**Weapons**: "+", ".join(list(character["Weapons"]))+"\n"+divider
if bool(character["Obligations"]):
text8 = "**Obligations**: "+",".join(list(character["Obligations"]))
return name, text1+text2+"\n\n"+text3+divider+text4+"\n"+divider+text5+text6+text7+text8
def charData(user : str,cmd : str):
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
key = string.capwords(cmd.split(" ")[0])
cmd = cmd[len(key):]
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
logThis("Looking for "+getName(user)+"'s character")
if user in data:
logThis("Foundt it! Looking for "+key+" in the data")
if key in data[user]:
logThis("Found it!")
if type(data[user][key]) is dict:
logThis("It's a dictionary!")
if cmd == "":
logThis("Retrieving data")
if key == "Weapons":
if bool(data[user][key]):
logThis("Returning a list of weapons")
return ", ".join(list(data[user][key]))
logThis("Retrieving data")
if key == "Weapons":
if bool(userCharacter[key]):
logThis("Returning a list of weapons")
return ", ".join(list(userCharacter[key]))
else:
logThis("The character doesn't have any weapons. Which is probably for the best. Like, who just walks around with weapons? (error code 941)")
return "There doesn't seem to be anything there... (error code 941)"
else:
logThis("The character doesn't have any weapons. Which is probably for the best. Like, who just walks around with weapons? (error code 941)")
return "There doesn't seem to be anything there... (error code 941)"
else:
return setUpDict(data[user][key])
elif cmd[0] == "+":
logThis("Gonna add something!!!")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Nope. That didn't happen (error code 942)")
return "Can't do that (error code 942)"
if (key == "Talents" or key == "Force-powers") and "," in cmd:
cmd = cmd.split(",")
while cmd[1][0] == " ":
cmd[1] = cmd[1][1:]
logThis("Adding "+cmd[0]+" to "+key)
data[user][key][cmd[0]] = cmd[1]
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return cmd[0]+" added to "+key+" for " + data[user]["Name"]
elif key == "Obligations" and "," in cmd:
cmd = cmd.split(",")
while cmd[1][0] == " ":
cmd[1] = cmd[1][1:]
logThis("Adding "+cmd[0]+" to "+key)
return self.setUpDict(userCharacter[key])
elif cmd[0] == "+":
logThis("Gonna add something!!!")
try:
data[user][key][cmd[0]] = int(cmd[1])
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Fucked that up (error code 949)")
return "Wrong data type (error code 949)"
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return cmd[0]+" added to "+key+" for " + data[user]["Name"]
elif key == "Weapons":
with open("resources/starWars/swtemplates.json", "r") as f:
templates = json.load(f)
newWeapon = templates["Weapon"]
logThis("Adding "+cmd+" to "+key)
data[user][key][cmd] = newWeapon
logThis("Nope. That didn't happen (error code 942)")
return "Can't do that (error code 942)"
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return cmd+" added to weapons for " + data[user]["Name"]
else:
logThis("That's not happening (error code 947d)")
return "Can't add that (error code 947d)"
if (key == "Talents" or key == "Force-powers") and "," in cmd:
cmd = cmd.split(",")
while cmd[1][0] == " ":
cmd[1] = cmd[1][1:]
logThis("Adding "+cmd[0]+" to "+key)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key+"."+cmd[0] : cmd[1]}})
return cmd[0]+" added to "+key+" for " + userCharacter["Name"]
elif cmd[0] == "-":
logThis("Gonna subtract/remove something")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("AAAAAAAAAAAA (error code 948)")
return "Can't do that (error code 948)"
if key == "Talents" or key == "Force-powers" or key == "Weapons" or key == "Obligations":
logThis("Trying to remove "+cmd+" from "+key)
if cmd in data[user][key]:
del data[user][key][cmd]
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
logThis("I did that")
return cmd+" removed from "+key+" from "+data[user]["Name"]
else:
logThis("Welp. I fucked that up (error code 946e)")
return "Can't remove that (error code 946e)"
else:
logThis("Urgh! (error code 946d)")
return "Can't remove that (error code 946d)"
else:
logThis("Looking up "+cmd+" in "+key)
if key == "Talents" or key == "Force-powers":
newKey = cmd
newcmd = ""
else:
newKey = string.capwords(cmd.split(" ")[0])
newcmd = cmd[len(newKey):]
lookUpResult = lookUp(data[user][key],newKey,newcmd)
if type(lookUpResult) is dict:
data[user][key] = lookUpResult
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Changed " + data[user]["Name"] + "'s " + key
else:
return lookUpResult
else:
if cmd == "":
logThis("Retrieving data")
if type(data[user][key]) is list:
return key+":\n"+", ".join(data[user][key])
else:
return data[user][key]
elif cmd[0] == '+':
logThis("Adding")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Error message (error code 948)")
return "Can't do that (error code 948)"
if type(data[user][key]) is int:
try:
logThis("Adding "+cmd+" to "+key)
beforeData = data[user][key]
data[user][key] = beforeData+ int(cmd)
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Added " + cmd + " to " + data[user]["Name"] + "'s " + key
except:
logThis("BITCH SANDWICH (error code 947c)")
return "Can't add that (error code 947c)"
elif type(data[user][key]) is list:
try:
logThis("Adding "+cmd+" to "+key)
data[user][key].append(cmd)
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Added " + cmd + " to " + data[user]["Name"] + "'s " + key
except:
logThis("tstststststs (error code 947b)")
return "Can't add that (error code 947b)"
else:
logThis("Help (error code 947a)")
return "Can't add that (error code 947a)"
elif cmd[0] == '-':
logThis("Removing/subtracting")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("lalalala (error code 948)")
return "Can't do that (error code 948)"
if type(data[user][key]) is int:
try:
logThis("Subtracting "+cmd+" from "+key)
beforeData = data[user][key]
data[user][key] = beforeData - int(cmd)
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Subtracted " + cmd + " from " + data[user]["Name"] + "'s " + key
except:
logThis("Tried it. Didn't want to (error code 946c)")
return "Can't remove that (error code 946c)"
elif type(data[user][key]) is list:
try:
logThis("removing "+cmd+" from "+key)
beforeData = data[user][key]
elif key == "Obligations" and "," in cmd:
cmd = cmd.split(",")
while cmd[1][0] == " ":
cmd[1] = cmd[1][1:]
logThis("Adding "+cmd[0]+" to "+key)
try:
data[user][key].remove(cmd)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key+"."+cmd[0] : int(cmd[1])}})
except:
logThis("They can only remove stuff that's actually in the list")
return "Not in list (error code 944b)"
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Removed " + cmd + " from " + data[user]["Name"] + "'s " + key
except:
logThis("nah (error code 946b)")
return "Can't remove that (error code 946b)"
else:
logThis("nyope (error code 946a)")
return "Can't remove that (error code 946a)"
else:
logThis("Changing "+key+" to "+cmd)
if type(data[user][key]) is int:
logThis("Fucked that up (error code 949)")
return "Wrong data type (error code 949)"
return cmd[0]+" added to "+key+" for " + userCharacter["Name"]
elif key == "Weapons":
with open("resources/starWars/swtemplates.json", "r") as f:
templates = json.load(f)
newWeapon = templates["Weapon"]
logThis("Adding "+cmd+" to "+key)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key+"."+cmd : newWeapon}})
return cmd+" added to weapons for " + userCharacter["Name"]
else:
logThis("That's not happening (error code 947d)")
return "Can't add that (error code 947d)"
elif cmd[0] == "-":
logThis("Gonna subtract/remove something")
try:
data[user][key] = int(cmd)
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("I don't wanna tho (error code 945b)")
return "Can't do that (error code 945b)"
elif type(data[user][key]) is str:
data[user][key] = cmd
logThis("AAAAAAAAAAAA (error code 948)")
return "Can't do that (error code 948)"
if key == "Talents" or key == "Force-powers" or key == "Weapons" or key == "Obligations":
logThis("Trying to remove "+cmd+" from "+key)
if cmd in userCharacter[key]:
self.bot.database["swcharacters"].update_one({"_id":user},
{"$unset": {cmd}})
logThis("I did that")
return cmd+" removed from "+key+" from "+userCharacter["Name"]
else:
logThis("Welp. I fucked that up (error code 946e)")
return "Can't remove that (error code 946e)"
else:
logThis("Urgh! (error code 946d)")
return "Can't remove that (error code 946d)"
else:
logThis("I don't wanna tho (error code 945a)")
return "Can't do that (error code 945a)"
logThis("Looking up "+cmd+" in "+key)
if key == "Talents" or key == "Force-powers":
newKey = cmd
newcmd = ""
else:
newKey = string.capwords(cmd.split(" ")[0])
newcmd = cmd[len(newKey):]
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "Changed " + data[user]["Name"] + "'s " + key +" to " + cmd
lookUpResult = self.lookUp(userCharacter[key],newKey,newcmd)
if type(lookUpResult) is dict:
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key : lookUpResult}})
return "Changed " + userCharacter["Name"] + "'s " + key
else:
return lookUpResult
else:
if cmd == "":
logThis("Retrieving data")
if type(userCharacter[key]) is list:
return key+":\n"+", ".join(userCharacter[key])
else:
return userCharacter[key]
elif cmd[0] == '+':
logThis("Adding")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("Error message (error code 948)")
return "Can't do that (error code 948)"
if type(userCharacter[key]) is int:
try:
logThis("Adding "+cmd+" to "+key)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$inc": {key : int(cmd)}})
return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
except:
logThis("BITCH SANDWICH (error code 947c)")
return "Can't add that (error code 947c)"
elif type(userCharacter[key]) is list:
try:
logThis("Adding "+cmd+" to "+key)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$push": {key : cmd}})
return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
except:
logThis("tstststststs (error code 947b)")
return "Can't add that (error code 947b)"
else:
logThis("Help (error code 947a)")
return "Can't add that (error code 947a)"
elif cmd[0] == '-':
logThis("Removing/subtracting")
try:
cmd = cmd[1:]
while cmd[0] == ' ':
cmd = cmd[1:]
except:
logThis("lalalala (error code 948)")
return "Can't do that (error code 948)"
if type(userCharacter[key]) is int:
try:
logThis("Subtracting "+cmd+" from "+key)
self.bot.database["swcharacters"].update_one({"_id":user},
{"$inc": {key : -int(cmd)}})
return "Subtracted " + cmd + " from " + userCharacter["Name"] + "'s " + key
except:
logThis("Tried it. Didn't want to (error code 946c)")
return "Can't remove that (error code 946c)"
elif type(userCharacter[key]) is list:
try:
logThis("removing "+cmd+" from "+key)
try:
self.bot.database["swcharacters"].update_one({"_id":user},
{"$pull": {key : cmd}})
except:
logThis("They can only remove stuff that's actually in the list")
return "Not in list (error code 944b)"
return "Removed " + cmd + " from " + userCharacter["Name"] + "'s " + key
except:
logThis("nah (error code 946b)")
return "Can't remove that (error code 946b)"
else:
logThis("nyope (error code 946a)")
return "Can't remove that (error code 946a)"
else:
logThis("Changing "+key+" to "+cmd)
if type(userCharacter[key]) is int:
try:
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key : int(cmd)}})
except:
logThis("I don't wanna tho (error code 945b)")
return "Can't do that (error code 945b)"
elif type(userCharacter[key]) is str:
self.bot.database["swcharacters"].update_one({"_id":user},
{"$set": {key : cmd}})
else:
logThis("I don't wanna tho (error code 945a)")
return "Can't do that (error code 945a)"
return "Changed " + userCharacter["Name"] + "'s " + key +" to " + cmd
else:
logThis(key+" isn't in there (error code 944)")
return "Couldn't find that data. Are you sure you spelled it correctly? (error code 944)"
else:
logThis(key+" isn't in there (error code 944)")
return "Couldn't find that data. Are you sure you spelled it correctly? (error code 944)"
else:
logThis(user+" doesn't have a character (error code 943)")
return "You don't have a character. You can make one with !swchar (error code 943)"
logThis(user+" doesn't have a character (error code 943)")
return "You don't have a character. You can make one with !swchar (error code 943)"
def replaceSpaces(cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - Light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
def replaceSpaces(self,cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - Light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
for x in range(len(withoutSpaces)):
cmd = cmd.replace(withSpaces[x],withoutSpaces[x])
return cmd
for x in range(len(withoutSpaces)):
cmd = cmd.replace(withSpaces[x],withoutSpaces[x])
def replaceWithSpaces(cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
return cmd
for x in range(len(withoutSpaces)):
cmd = cmd.replace(withoutSpaces[x],withSpaces[x])
return cmd
def replaceWithSpaces(self,cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
def parseChar(user : str, cmd : str):
for x in range(len(withoutSpaces)):
cmd = cmd.replace(withoutSpaces[x],withSpaces[x])
cmd = replaceSpaces(cmd)
return cmd
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
def parseChar(self,user : str, cmd : str):
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
cmd = self.replaceSpaces(cmd)
if cmd == "":
if user in data:
text1, text2 = characterSheet(data[user])
return text1, replaceWithSpaces(text2)
userCharacter = self.bot.database["swcharacters"].find_one({"_id":user})
if cmd == " ":
cmd = ""
elif cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
if cmd == "":
if userCharacter != None:
text1, text2 = self.characterSheet(userCharacter)
return text1, self.replaceWithSpaces(text2)
else:
logThis("Makin' a character for "+self.bot.funcs.getName(user))
with open("resources/starWars/swtemplates.json", "r") as f:
templates = json.load(f)
newChar = templates["Character"]
print("yeet")
newChar["_id"] = user
print("yeet")
self.bot.database["swcharacters"].insert_one(newChar)
print("yeet")
return "", "Character for " + self.bot.funcs.getName(user) + " created"
else:
logThis("Makin' a character for "+getName(user))
with open("resources/starWars/swtemplates.json", "r") as f:
templates = json.load(f)
newChar = templates["Character"]
data[user] = newChar
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "", "Character for " + getName(user) + " created"
else:
if cmd == "Purge":
logThis("Deleting "+getName(user)+"'s character")
del data[user]
with open("resources/starWars/swcharacters.json", "w") as f:
json.dump(data,f,indent = 4)
return "", "Character for " + getName(user) + " deleted"
else:
return "", replaceWithSpaces(str(charData(user,cmd)))
if cmd == "Purge":
logThis("Deleting "+self.bot.funcs.getName(user)+"'s character")
self.bot.database["swcharacters"].remove_one({newChar})
return "", "Character for " + self.bot.funcs.getName(user) + " deleted"
else:
return "", self.replaceWithSpaces(str(self.charData(user,cmd)))
def lightsaberChar(user : str):
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
def lightsaberChar(self,user : str):
userCharacter = self.bot.database["swcharacters"].find_one({"_id":user})
if user in data:
return data[user]["Lightsaber-characteristic"]
if userCharacter != None:
return userCharacter["Lightsaber-characteristic"]
def userHasChar(user : str):
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
def userHasChar(self,user : str):
userCharacter = self.bot.database["swcharacters"].find_one({"_id":user})
return user in data
return userCharacter != None

View File

@ -1,66 +1,68 @@
from . import swroll
from funcs import logThis
def destinyNew(num : int):
logThis("Creating a new destiny pool with "+str(num)+" players")
roll, diceResults = swroll.roll(0,0,0,0,0,0,num)
roll = "".join(sorted(roll))
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(roll)
return "Rolled for Destiny Points and got:\n"+swroll.diceResultToEmoji(diceResults)+"\n"+swroll.resultToEmoji(roll)
class SwDestiny():
def __init__(self, bot):
self.bot = bot
def destinyUse(user : str):
with open("resources/starWars/destinyPoints.txt","rt") as f:
points = f.read()
if user == "Nikolaj":
logThis("Trying to use a dark side destiny point")
if 'B' in points:
points = points.replace("B","L",1)
points = "".join(sorted(points))
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points)
logThis("Did it")
return "Used a dark side destiny point. Destiny pool is now:\n"+swroll.resultToEmoji(points)
else:
logThis("There were no dark side destiny points")
return "No dark side destiny points"
else:
logThis("Trying to use a light side destiny point")
if 'L' in points:
points = points.replace("L","B",1)
points = "".join(sorted(points))
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points)
logThis("Did it")
return "Used a light side destiny point. Destiny pool is now:\n"+swroll.resultToEmoji(points)
else:
logThis("There were no dark side destiny points")
return "No light side destiny points"
def destinyNew(self, num : int):
logThis("Creating a new destiny pool with "+str(num)+" players")
roll, diceResults = self.bot.swroll.roll(0,0,0,0,0,0,num)
roll = "".join(sorted(roll))
def parseDestiny(user : str, cmd : str):
if cmd != "":
while cmd[0] == ' ':
cmd = cmd[1:]
if cmd == "":
break
if cmd == "":
logThis("Retrieving destiny pool info")
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(roll)
return "Rolled for Destiny Points and got:\n"+self.bot.swroll.diceResultToEmoji(diceResults)+"\n"+self.bot.swroll.resultToEmoji(roll)
def destinyUse(self, user : str):
with open("resources/starWars/destinyPoints.txt","rt") as f:
return swroll.resultToEmoji(f.read())
else:
commands = cmd.upper().split(" ")
if commands[0] == "N":
if len(commands) > 1:
return destinyNew(int(commands[1]))
points = f.read()
if user == "Nikolaj":
logThis("Trying to use a dark side destiny point")
if 'B' in points:
points = points.replace("B","L",1)
points = "".join(sorted(points))
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points)
logThis("Did it")
return "Used a dark side destiny point. Destiny pool is now:\n"+self.bot.swroll.resultToEmoji(points)
else:
return "You need to give an amount of players (error code 921)"
elif commands[0] == "U":
return destinyUse(user)
logThis("There were no dark side destiny points")
return "No dark side destiny points"
else:
return "I didn't quite understand that (error code 922)"
logThis("Trying to use a light side destiny point")
if 'L' in points:
points = points.replace("L","B",1)
points = "".join(sorted(points))
with open("resources/starWars/destinyPoints.txt","wt") as f:
f.write(points)
logThis("Did it")
return "Used a light side destiny point. Destiny pool is now:\n"+self.bot.swroll.resultToEmoji(points)
else:
logThis("There were no dark side destiny points")
return "No light side destiny points"
def parseDestiny(self, user : str, cmd : str):
if cmd != "":
while cmd[0] == ' ':
cmd = cmd[1:]
if cmd == "":
break
if cmd == "":
logThis("Retrieving destiny pool info")
with open("resources/starWars/destinyPoints.txt","rt") as f:
return self.bot.swroll.resultToEmoji(f.read())
else:
commands = cmd.upper().split(" ")
if commands[0] == "N":
if len(commands) > 1:
return self.destinyNew(int(commands[1]))
else:
return "You need to give an amount of players (error code 921)"
elif commands[0] == "U":
return self.destinyUse(user)
else:
return "I didn't quite understand that (error code 922)"

View File

@ -3,376 +3,378 @@ import re
import string
import json
from . import swchar
from funcs import logThis
with open("resources/starWars/swskills.json", "r") as f:
skillData = json.load(f)
# Rolls the specified dice
def roll(abi : int = 1, prof : int = 0, dif : int = 3, cha : int = 0, boo : int = 0, setb : int = 0, force : int = 0):
result = ""
diceResult = []
for x in range(abi):
choice = random.choice(["","S","S","SS","A","A","SA","AA"])
result += choice
diceResult.append("abi"+choice)
class SwRoll():
def __init__(self, bot):
self.bot = bot
for x in range(prof):
choice = random.choice(["","S","S","SS","SS","A","SA","SA","SA","AA","AA","R"])
result += choice
diceResult.append("prof"+choice)
for x in range(dif):
choice = random.choice(["","F","FF","H","H","H","HH","FH"])
result += choice
diceResult.append("dif"+choice)
# Rolls the specified dice
def roll(self, abi : int = 1, prof : int = 0, dif : int = 3, cha : int = 0, boo : int = 0, setb : int = 0, force : int = 0):
result = ""
diceResult = []
for x in range(abi):
choice = random.choice(["","S","S","SS","A","A","SA","AA"])
result += choice
diceResult.append("abi"+choice)
for x in range(cha):
choice = random.choice(["","F","F","FF","FF","H","H","FH","FH","HH","HH","D"])
result += choice
diceResult.append("cha"+choice)
for x in range(boo):
choice = random.choice(["","","S","SA","AA","A"])
result += choice
diceResult.append("boo"+choice)
for x in range(prof):
choice = random.choice(["","S","S","SS","SS","A","SA","SA","SA","AA","AA","R"])
result += choice
diceResult.append("prof"+choice)
for x in range(setb):
choice = random.choice(["","","F","F","H","H"])
result += choice
diceResult.append("setb"+choice)
for x in range (force):
choice = random.choice(["B","B","B","B","B","B","BB","L","L","LL","LL","LL"])
result += choice
diceResult.append("force"+choice)
for x in range(dif):
choice = random.choice(["","F","FF","H","H","H","HH","FH"])
result += choice
diceResult.append("dif"+choice)
return result, diceResult
for x in range(cha):
choice = random.choice(["","F","F","FF","FF","H","H","FH","FH","HH","HH","D"])
result += choice
diceResult.append("cha"+choice)
# Lets dice cancel each other out
def simplify(result : str):
logThis("Simplifying "+result)
simp = ""
success = (result.count('S') + result.count('R')) - (result.count('F') + result.count('D'))
advantage = result.count('A') - result.count('H')
result = re.sub("S|A|F|H","",result)
for x in range(boo):
choice = random.choice(["","","S","SA","AA","A"])
result += choice
diceResult.append("boo"+choice)
if success > 0:
for x in range(success):
simp += "S"
elif success < 0:
for x in range(abs(success)):
simp += "F"
if advantage > 0:
for x in range(advantage):
simp += "A"
elif advantage < 0:
for x in range(abs(advantage)):
simp += "H"
simp += result
for x in range(setb):
choice = random.choice(["","","F","F","H","H"])
result += choice
diceResult.append("setb"+choice)
return simp
for x in range (force):
choice = random.choice(["B","B","B","B","B","B","BB","L","L","LL","LL","LL"])
result += choice
diceResult.append("force"+choice)
# Returns emoji that symbolize the dice results
def diceResultToEmoji(diceResults : list):
emoji = ""
for result in diceResults:
if result == "abiA":
emoji += "<:abil1a:695267684476125264> "
elif result == "abiSA":
emoji += "<:abil1a1s:695267684484513842> "
elif result == "abiS":
emoji += "<:abil1s:695267684514005013> "
elif result == "abiAA":
emoji += "<:abil2a:695267684547428352> "
elif result == "abiSS":
emoji += "<:abil2s:695267684761206914> "
elif result == "abi":
emoji += "<:abilbla:695267684660674602> "
return result, diceResult
elif result == "profA":
emoji += "<:prof1a:695267685361123338> "
elif result == "profSA":
emoji += "<:prof1a1s:695267685067653140> "
elif result == "profR":
emoji += "<:prof1r:695267685067522088> "
elif result == "profS":
emoji += "<:prof1s:695267684899881012> "
elif result == "profAA":
emoji += "<:prof2a:695267684996218982> "
elif result == "profSS":
emoji += "<:prof2s:695267684878647327> "
elif result == "prof":
emoji += "<:profbla:695267684698292235> "
# Lets dice cancel each other out
def simplify(self, result : str):
logThis("Simplifying "+result)
simp = ""
success = (result.count('S') + result.count('R')) - (result.count('F') + result.count('D'))
advantage = result.count('A') - result.count('H')
result = re.sub("S|A|F|H","",result)
elif result == "difF":
emoji += "<:dif1f:695267684924915804> "
elif result == "difH":
emoji += "<:dif1h:695267684908138506> "
elif result == "difFH":
emoji += "<:dif1h1f:695267684908269678> "
elif result == "difFF":
emoji += "<:dif2f:695267684924784680> "
elif result == "difHH":
emoji += "<:dif2h:695267685071585340> "
elif result == "dif":
emoji += "<:difbla:695267685000544276> "
if success > 0:
for x in range(success):
simp += "S"
elif success < 0:
for x in range(abs(success)):
simp += "F"
if advantage > 0:
for x in range(advantage):
simp += "A"
elif advantage < 0:
for x in range(abs(advantage)):
simp += "H"
simp += result
return simp
# Returns emoji that symbolize the dice results
def diceResultToEmoji(self, diceResults : list):
emoji = ""
for result in diceResults:
if result == "abiA":
emoji += "<:abil1a:695267684476125264> "
elif result == "abiSA":
emoji += "<:abil1a1s:695267684484513842> "
elif result == "abiS":
emoji += "<:abil1s:695267684514005013> "
elif result == "abiAA":
emoji += "<:abil2a:695267684547428352> "
elif result == "abiSS":
emoji += "<:abil2s:695267684761206914> "
elif result == "abi":
emoji += "<:abilbla:695267684660674602> "
elif result == "profA":
emoji += "<:prof1a:695267685361123338> "
elif result == "profSA":
emoji += "<:prof1a1s:695267685067653140> "
elif result == "profR":
emoji += "<:prof1r:695267685067522088> "
elif result == "profS":
emoji += "<:prof1s:695267684899881012> "
elif result == "profAA":
emoji += "<:prof2a:695267684996218982> "
elif result == "profSS":
emoji += "<:prof2s:695267684878647327> "
elif result == "prof":
emoji += "<:profbla:695267684698292235> "
elif result == "difF":
emoji += "<:dif1f:695267684924915804> "
elif result == "difH":
emoji += "<:dif1h:695267684908138506> "
elif result == "difFH":
emoji += "<:dif1h1f:695267684908269678> "
elif result == "difFF":
emoji += "<:dif2f:695267684924784680> "
elif result == "difHH":
emoji += "<:dif2h:695267685071585340> "
elif result == "dif":
emoji += "<:difbla:695267685000544276> "
elif result == "chaD":
emoji += "<:cha1d:695267684962533447> "
elif result == "chaF":
emoji += "<:cha1f:695267684601954346> "
elif result == "chaH":
emoji += "<:cha1h:695267685046681620> "
elif result == "chaFH":
emoji += "<:cha1h1f:695267685063327784> "
elif result == "chaFF":
emoji += "<:cha2f:695267684832641097> "
elif result == "chaHH":
emoji += "<:cha2h:695267684631183381> "
elif result == "cha":
emoji += "<:chabla:695267684895686787> "
elif result == "booA":
emoji += "<:boo1a:695267684975116329> "
elif result == "booSA":
emoji += "<:boo1a1s:695267684970922024> "
elif result == "booS":
emoji += "<:boo1s:695267684979441714> "
elif result == "booAA":
emoji += "<:boo2a:695267685100945488> "
elif result == "boo":
emoji += "<:boobla:695267684757012550> "
elif result == "setbF":
emoji += "<:set1f:695267685054939197> "
elif result == "setbH":
emoji += "<:set1h:695267685147082802> "
elif result == "setb":
emoji += "<:setbla:695267685151408169> "
elif result == "forceB":
emoji += "<:for1b:695267684593434677> "
elif result == "forceL":
emoji += "<:for1l:695267684606148640> "
elif result == "forceBB":
emoji += "<:for2b:695267684903944303> "
elif result == "forceLL":
emoji += "<:for2l:695267684992024626> "
return emoji
# Returns emoji that symbolize the results of the dice rolls
def resultToEmoji(self, result : str):
emoji = ""
for char in result:
if char == 'S':
emoji += "<:success:690971244971163718> "
elif char == 'A':
emoji += "<:advantage:690970761611051079> "
elif char == 'R':
emoji += "<:swtriumph:690971267486187643> "
elif char == 'F':
emoji += "<:failure:690970957786906664> "
elif char == 'H':
emoji += "<:threat:690971009469382656> "
elif char == 'D':
emoji += "<:despair:690971200163414238> "
elif char == 'L':
emoji += "<:light:691010089905029171>"
elif char == 'B':
emoji += "<:dark:691010101901000852>"
elif result == "chaD":
emoji += "<:cha1d:695267684962533447> "
elif result == "chaF":
emoji += "<:cha1f:695267684601954346> "
elif result == "chaH":
emoji += "<:cha1h:695267685046681620> "
elif result == "chaFH":
emoji += "<:cha1h1f:695267685063327784> "
elif result == "chaFF":
emoji += "<:cha2f:695267684832641097> "
elif result == "chaHH":
emoji += "<:cha2h:695267684631183381> "
elif result == "cha":
emoji += "<:chabla:695267684895686787> "
return emoji
elif result == "booA":
emoji += "<:boo1a:695267684975116329> "
elif result == "booSA":
emoji += "<:boo1a1s:695267684970922024> "
elif result == "booS":
emoji += "<:boo1s:695267684979441714> "
elif result == "booAA":
emoji += "<:boo2a:695267685100945488> "
elif result == "boo":
emoji += "<:boobla:695267684757012550> "
# Converts emoji into letters
def emojiToResult(self, emoji : str):
result = ""
for char in emoji:
if char == "<:light:691010089905029171>":
emoji += 'L'
if char == "<:dark:691010101901000852>":
emoji += 'B'
elif result == "setbF":
emoji += "<:set1f:695267685054939197> "
elif result == "setbH":
emoji += "<:set1h:695267685147082802> "
elif result == "setb":
emoji += "<:setbla:695267685151408169> "
return result
elif result == "forceB":
emoji += "<:for1b:695267684593434677> "
elif result == "forceL":
emoji += "<:for1l:695267684606148640> "
elif result == "forceBB":
emoji += "<:for2b:695267684903944303> "
elif result == "forceLL":
emoji += "<:for2l:695267684992024626> "
# Returns emoji that symbolize the dice
def diceToEmoji(self, dice : list):
emoji = ""
return emoji
for x in range(dice[0]):
emoji += "<:ability:690974213397282826> "
for x in range(dice[1]):
emoji += "<:proficiency:690973435354153071> "
for x in range(dice[2]):
emoji += "<:difficulty:690973992470708296> "
for x in range(dice[3]):
emoji += "<:challenge:690973419906400306> "
for x in range(dice[4]):
emoji += "<:boost:690972178216386561> "
for x in range(dice[5]):
emoji += "<:setback:690972157890658415> "
for x in range(dice[6]):
emoji += "<:force:690973451883774013> "
# Returns emoji that symbolize the results of the dice rolls
def resultToEmoji(result : str):
emoji = ""
for char in result:
if char == 'S':
emoji += "<:success:690971244971163718> "
elif char == 'A':
emoji += "<:advantage:690970761611051079> "
elif char == 'R':
emoji += "<:swtriumph:690971267486187643> "
elif char == 'F':
emoji += "<:failure:690970957786906664> "
elif char == 'H':
emoji += "<:threat:690971009469382656> "
elif char == 'D':
emoji += "<:despair:690971200163414238> "
elif char == 'L':
emoji += "<:light:691010089905029171>"
elif char == 'B':
emoji += "<:dark:691010101901000852>"
return emoji
return emoji
# Converts emoji into letters
def emojiToResult(emoji : str):
result = ""
for char in emoji:
if char == "<:light:691010089905029171>":
emoji += 'L'
if char == "<:dark:691010101901000852>":
emoji += 'B'
return result
# Rolls for obligation
def obligationRoll(self):
logThis("Rolling for obligation")
data = self.bot.database["swcharacters"]
# Returns emoji that symbolize the dice
def diceToEmoji(dice : list):
emoji = ""
table = []
for x in range(dice[0]):
emoji += "<:ability:690974213397282826> "
for x in range(dice[1]):
emoji += "<:proficiency:690973435354153071> "
for x in range(dice[2]):
emoji += "<:difficulty:690973992470708296> "
for x in range(dice[3]):
emoji += "<:challenge:690973419906400306> "
for x in range(dice[4]):
emoji += "<:boost:690972178216386561> "
for x in range(dice[5]):
emoji += "<:setback:690972157890658415> "
for x in range(dice[6]):
emoji += "<:force:690973451883774013> "
for character in data:
for obligation in data[character]["Obligations"]:
for x in range(data[character]["Obligations"][obligation]):
table.append(data[character]["Name"]+", "+obligation)
return emoji
while len(table) < 100:
table.append("Nothing")
# Rolls for obligation
def obligationRoll():
logThis("Rolling for obligation")
with open("resources/starWars/swcharacters.json", "r") as f:
data = json.load(f)
table = []
return random.choice(table)
for character in data:
for obligation in data[character]["Obligations"]:
for x in range(data[character]["Obligations"][obligation]):
table.append(data[character]["Name"]+", "+obligation)
while len(table) < 100:
table.append("Nothing")
return random.choice(table)
# Rolls for critical injury
def critRoll(self, addington : int):
dd = "<:difficulty:690973992470708296>"
sd = "<:setback:690972157890658415>"
bd = "<:boost:690972178216386561>"
roll = random.randint(1,100) + addington
injuries = [
"**Minor nick**: The target suffers 1 strain, "+dd] * 5 + [
"**Slowed down**: The target can only act during the last allied initiative slot this turn, "+dd] * 5 + [
"**Sudden Jolt**: The target drops whatever is in hand, "+dd] * 5 + [
"**Distracted**: The target cannot perform a Free maneuver during his next turn, "+dd] * 5 + [
"**Off-Balance**: The target adds "+sd+" to his next skill check, "+dd] * 5 + [
"**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+dd] * 5 + [
"**Stunned**: The target is staggered until the end of his next turn, "+dd] * 5 + [
"**Stinger**: Increase the difficulty of next check by one, "+dd] * 5 + [
"**Bowled Over**: The target is knocked prone and suffers 1 sttrain, "+dd+dd] * 5 + [
"**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Slightly Dazed**: The target is disoriented until the end of the encounter, "+dd+dd] * 5 + [
"**Scattered Senses**: The target removes all "+bd+" from skill checks until the end of the encounter, "+dd+dd] * 5 + [
"**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+dd+dd] * 5 + [
"**Overpowered**: The target leaves himselp open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+dd+dd] * 5 + [
"**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+dd+dd] * 5 + [
"**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**At the brink**: The target suffers 1 strain each time he performs an action, "+dd+dd+dd] * 5 + [
"**Crippled**: One of the target's limbs (selected by the GM) is crippled until healed or replaced. Increase difficulty of all checks that require use of that limb by one, "+dd+dd+dd] * 5 + [
"**Maimed**: One of the target's limbs (selected by the GM) is permanently lost. Unless the target has a cybernetic replacement, the target cannot perform actions that would require the use of that limb. All other actions gain "+sd+", "+dd+dd+dd] * 5 + [
"HI"] * 5 + [
"**Temporarily Lame**: Until this critical injury is healed, the target cannot perform more than one maneuver during his turn, "+dd+dd+dd] * 5 + [
"**Blinded**: The target can no longer see. Upgrade the difficulty of all checks twice. Upgrade the difficulty of perception checks three times, "+dd+dd+dd] * 5 + [
"**Knocked Senseless**: The target is staggered for the remainder of the encounter, "+dd+dd+dd] * 5 + [
"GI"] * 5 + [
"**Bleeding Out**: Every round, the target suffers 1 wound and 1 strain at the beginning of his turn. For every five wounds he suffers beyond his wound threshold, he suffers one additional critical injury. (If he suffers this one again, roll again), "+dd+dd+dd+dd] * 10 + [
"**The End is Nigh**: The target will die after the last initiative slot during the next round, "+dd+dd+dd+dd] * 10 + [
"**Dead**: U B Dead :("]
# Rolls for critical injury
def critRoll(addington : int):
dd = "<:difficulty:690973992470708296>"
sd = "<:setback:690972157890658415>"
bd = "<:boost:690972178216386561>"
roll = random.randint(1,100) + addington
injuries = [
"**Minor nick**: The target suffers 1 strain, "+dd] * 5 + [
"**Slowed down**: The target can only act during the last allied initiative slot this turn, "+dd] * 5 + [
"**Sudden Jolt**: The target drops whatever is in hand, "+dd] * 5 + [
"**Distracted**: The target cannot perform a Free maneuver during his next turn, "+dd] * 5 + [
"**Off-Balance**: The target adds "+sd+" to his next skill check, "+dd] * 5 + [
"**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+dd] * 5 + [
"**Stunned**: The target is staggered until the end of his next turn, "+dd] * 5 + [
"**Stinger**: Increase the difficulty of next check by one, "+dd] * 5 + [
"**Bowled Over**: The target is knocked prone and suffers 1 sttrain, "+dd+dd] * 5 + [
"**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Slightly Dazed**: The target is disoriented until the end of the encounter, "+dd+dd] * 5 + [
"**Scattered Senses**: The target removes all "+bd+" from skill checks until the end of the encounter, "+dd+dd] * 5 + [
"**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+dd+dd] * 5 + [
"**Overpowered**: The target leaves himselp open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+dd+dd] * 5 + [
"**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+dd+dd] * 5 + [
"**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**At the brink**: The target suffers 1 strain each time he performs an action, "+dd+dd+dd] * 5 + [
"**Crippled**: One of the target's limbs (selected by the GM) is crippled until healed or replaced. Increase difficulty of all checks that require use of that limb by one, "+dd+dd+dd] * 5 + [
"**Maimed**: One of the target's limbs (selected by the GM) is permanently lost. Unless the target has a cybernetic replacement, the target cannot perform actions that would require the use of that limb. All other actions gain "+sd+", "+dd+dd+dd] * 5 + [
"HI"] * 5 + [
"**Temporarily Lame**: Until this critical injury is healed, the target cannot perform more than one maneuver during his turn, "+dd+dd+dd] * 5 + [
"**Blinded**: The target can no longer see. Upgrade the difficulty of all checks twice. Upgrade the difficulty of perception checks three times, "+dd+dd+dd] * 5 + [
"**Knocked Senseless**: The target is staggered for the remainder of the encounter, "+dd+dd+dd] * 5 + [
"GI"] * 5 + [
"**Bleeding Out**: Every round, the target suffers 1 wound and 1 strain at the beginning of his turn. For every five wounds he suffers beyond his wound threshold, he suffers one additional critical injury. (If he suffers this one again, roll again), "+dd+dd+dd+dd] * 10 + [
"**The End is Nigh**: The target will die after the last initiative slot during the next round, "+dd+dd+dd+dd] * 10 + [
"**Dead**: U B Dead :("]
if roll >= len(injuries):
results = injuries[-1]
else:
results = injuries[roll]
if results == "HI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Horrific Injury**: Until this criticil injury is healed, treat the target's "+characteristic+" as if it's one lower, "+dd+dd+dd
if results == "GI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+dd+dd+dd+dd
return "Roll: "+str(roll)+"\nInjury:\n"+results
# Parses the command into something the other functions understand
def parseRoll(user : str,cmd : str = ""):
cmd = re.sub(' +',' ',cmd.upper()) + " "
if cmd[0] == " ":
cmd = cmd[1:]
cmd = swchar.replaceSpaces(string.capwords(cmd))
commands = cmd.split(" ")
if commands[0] == "":
rollParameters = [1,0,3,0,0,0,0]
else:
rollParameters = [0,0,0,0,0,0,0]
if string.capwords(commands[0]) == "Obligations":
try:
return obligationRoll()
except:
logThis("Obligation fucked up (error code 911)")
return "An error occured (error code 911)"
elif string.capwords(commands[0]) in skillData:
logThis("Oh look! This guy has skills!")
if swchar.userHasChar:
logThis("They have a character. That much we know")
skillLevel = swchar.charData(user,"Skills " + string.capwords(commands[0]))
if string.capwords(commands[0]) == "Lightsaber":
logThis("The skill is lightsaber")
charLevel = swchar.charData(user,"Characteristics " + swchar.lightsaberChar(user))
else:
charLevel = swchar.charData(user,"Characteristics " + skillData[string.capwords(commands[0])])
abilityDice = abs(charLevel-skillLevel)
proficiencyDice = min(skillLevel,charLevel)
commands = [str(abilityDice)] + [str(proficiencyDice)] + commands[1:]
logThis("Converted skill to dice")
if roll >= len(injuries):
results = injuries[-1]
else:
logThis("Okay, no they don't i guess (error code 912)")
return "You don't have a user. You can make one with !swchar (error code 912)"
results = injuries[roll]
elif string.capwords(commands[0]) in ["Ranged","Piloting"]:
logThis("They fucked up writing the name of a ranged or piloting skill")
if string.capwords(commands[0]) == "Ranged":
return "Did you mean \"Ranged - Heavy\" or \"Ranged - Light\" (error code 913)"
if results == "HI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Horrific Injury**: Until this criticil injury is healed, treat the target's "+characteristic+" as if it's one lower, "+dd+dd+dd
if results == "GI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+dd+dd+dd+dd
return "Roll: "+str(roll)+"\nInjury:\n"+results
# Parses the command into something the other functions understand
def parseRoll(self, user : str,cmd : str = ""):
cmd = re.sub(' +',' ',cmd.upper()) + " "
if cmd[0] == " ":
cmd = cmd[1:]
cmd = self.bot.swchar.replaceSpaces(string.capwords(cmd))
commands = cmd.split(" ")
if commands[0] == "":
rollParameters = [1,0,3,0,0,0,0]
else:
return "Did you mean \"Piloting - Planetary\" or \"Piloting - Space\" (error code 913)"
rollParameters = [0,0,0,0,0,0,0]
try:
logThis("Converting commands to dice")
for x in range(len(commands)):
if commands[x] != "":
commands[x] = commands[x].upper()
if commands[x][0] == "A":
rollParameters[0] = int(commands[x].replace("A",""))
elif commands[x][0] == "P":
rollParameters[1] = int(commands[x].replace("P",""))
elif commands[x][0] == "D":
rollParameters[2] = int(commands[x].replace("D",""))
elif commands[x][0] == "C":
rollParameters[3] = int(commands[x].replace("C",""))
elif commands[x][0] == "B":
rollParameters[4] = int(commands[x].replace("B",""))
elif commands[x][0] == "S":
rollParameters[5] = int(commands[x].replace("S",""))
elif commands[x][0] == "F":
rollParameters[6] = int(commands[x].replace("F",""))
if string.capwords(commands[0]) == "Obligations":
try:
return obligationRoll()
except:
logThis("Obligation fucked up (error code 911)")
return "An error occured (error code 911)"
elif string.capwords(commands[0]) in skillData:
logThis("Oh look! This guy has skills!")
if self.bot.swchar.userHasChar:
logThis("They have a character. That much we know")
skillLevel = self.bot.swchar.charData(user,"Skills " + string.capwords(commands[0]))
if string.capwords(commands[0]) == "Lightsaber":
logThis("The skill is lightsaber")
charLevel = self.bot.swchar.charData(user,"Characteristics " + self.bot.swchar.lightsaberChar(user))
else:
rollParameters[x] = int(commands[x])
except:
logThis("Someone fucked u-up! (it was them) (error code 914)")
return "Invalid input! (error code 914)"
logThis("Rolling "+str(rollParameters))
rollResults, diceResults = roll(rollParameters[0],rollParameters[1],rollParameters[2],rollParameters[3],rollParameters[4],rollParameters[5],rollParameters[6])
simplified = simplify(rollResults)
charLevel = self.bot.swchar.charData(user,"Characteristics " + skillData[string.capwords(commands[0])])
name = swchar.getCharName(user)
logThis("Returns results and simplified results")
abilityDice = abs(charLevel-skillLevel)
proficiencyDice = min(skillLevel,charLevel)
commands = [str(abilityDice)] + [str(proficiencyDice)] + commands[1:]
logThis("Converted skill to dice")
else:
logThis("Okay, no they don't i guess (error code 912)")
return "You don't have a user. You can make one with !swchar (error code 912)"
elif string.capwords(commands[0]) in ["Ranged","Piloting"]:
logThis("They fucked up writing the name of a ranged or piloting skill")
if string.capwords(commands[0]) == "Ranged":
return "Did you mean \"Ranged - Heavy\" or \"Ranged - Light\" (error code 913)"
else:
return "Did you mean \"Piloting - Planetary\" or \"Piloting - Space\" (error code 913)"
try:
logThis("Converting commands to dice")
for x in range(len(commands)):
if commands[x] != "":
commands[x] = commands[x].upper()
if commands[x][0] == "A":
rollParameters[0] = int(commands[x].replace("A",""))
elif commands[x][0] == "P":
rollParameters[1] = int(commands[x].replace("P",""))
elif commands[x][0] == "D":
rollParameters[2] = int(commands[x].replace("D",""))
elif commands[x][0] == "C":
rollParameters[3] = int(commands[x].replace("C",""))
elif commands[x][0] == "B":
rollParameters[4] = int(commands[x].replace("B",""))
elif commands[x][0] == "S":
rollParameters[5] = int(commands[x].replace("S",""))
elif commands[x][0] == "F":
rollParameters[6] = int(commands[x].replace("F",""))
else:
rollParameters[x] = int(commands[x])
except:
logThis("Someone fucked u-up! (it was them) (error code 914)")
return "Invalid input! (error code 914)"
logThis("Rolling "+str(rollParameters))
rollResults, diceResults = self.roll(rollParameters[0],rollParameters[1],rollParameters[2],rollParameters[3],rollParameters[4],rollParameters[5],rollParameters[6])
simplified = self.simplify(rollResults)
name = self.bot.swchar.getCharName(user)
logThis("Returns results and simplified results")
if simplified == "":
return name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\nEverything cancels out!"
else:
return name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\n" + self.resultToEmoji(simplified)
if simplified == "":
return name + " rolls: " + "\n" + diceResultToEmoji(diceResults) + "\nEverything cancels out!"
else:
return name + " rolls: " + "\n" + diceResultToEmoji(diceResults) + "\n" + resultToEmoji(simplified)

View File

@ -1,15 +1,5 @@
{
"json":{
"resources/starWars/swcharacters.json" : {},
"resources/games/hexGames.json": {},
"resources/games/monopolyGames.json": {},
"resources/games/hangmanGames.json": {},
"resources/games/investments.json" : {},
"resources/games/games.json" : {
"trivia questions":{},
"blackjack games":{},
"4 in a row games": {}
},
"resources/lookup/spells.json" : {
"Fireball" : {
"casting_time" : "1 action",
@ -76,9 +66,6 @@
"resources/games/blackjackTables",
"resources/games/4InARowBoards",
"resources/games/hexBoards",
"resources/games/oldImages",
"resources/games/blackjackCards",
"resources/games/hilo",
"resources/games/monopolyBoards",
"resources/games/hangmanBoards"
]